能夠建造分散式系統,不代表就值得建造——就像技術上可以在一台個人電腦上裝四台軟碟機,但這麼做毫無意義。本節討論一個分散式系統要「值得投入」應滿足的四個重要目標:

  • 讓資源容易被存取(accessibility)
  • 合理地隱藏資源分散在網路上的事實(distribution transparency)
  • 開放(openness)
  • 可擴展(scalability)

讓資源易於存取#

分散式系統的主要目標,是讓使用者(與應用程式)能輕鬆存取遠端資源,並以受控且有效率的方式共享。資源幾乎可以是任何東西:印表機、電腦、儲存設施、資料、檔案、網頁、網路等。

共享資源的理由:

  • 經濟因素:讓小辦公室的多位使用者共用一台印表機,比每人買一台便宜;超級電腦、高效能儲存系統、排版輸出機(imagesetter)等昂貴週邊也是同理。
  • 促進協作與資訊交換:網際網路以簡單協定交換檔案、郵件、文件、音訊與視訊的成功即是明證。連結性催生了各種虛擬組織(virtual organization)——地理上分散的人群透過群組軟體(groupware,協作編輯、視訊會議等)一起工作;也促成了電子商務,讓人不必出門就能買賣各種商品。

連結性與共享程度越高,安全性就越重要。現行實務中,系統對通訊的竊聽或入侵幾乎沒有保護:密碼等敏感資訊常以明文(cleartext)在網路上傳送,或存放在只能「希望它可信」的伺服器上。

延伸討論:安全與隱私的具體隱憂
  • 付款驗證薄弱:目前只憑信用卡號就能訂購商品,鮮少要求證明持卡人真的擁有這張卡。未來這類訂購可能得把卡片實際插入讀卡機、證明你持有它才行。
  • 追蹤通訊以建立偏好檔案(Wang et al., 1998):這種追蹤明確侵犯隱私,尤其是在未告知使用者的情況下進行。
  • 垃圾郵件(spam):連結性提高也帶來不請自來的通訊。此時可能需要依內容篩選訊息的特殊資訊過濾器來自保。

分散透明性#

分散式系統的重要目標之一,是隱藏行程與資源實際分散在多台電腦上的事實。若系統能對使用者與應用程式呈現得彷彿只是單一電腦系統,就稱它是透明的(transparent)

透明性的種類#

透明性可套用在分散式系統的多個面向(ISO, 1995):

  • 存取透明性(access transparency):隱藏資料表示方式與資源存取方式的差異。基本層次是隱藏機器架構差異,更重要的是就「不同機器與作業系統如何表示資料」達成一致——例如不同作業系統各有檔案命名慣例,這些差異與檔案操作方式的差異都應對使用者隱藏。
  • 位置透明性(location transparency):使用者無法得知資源實際位於系統何處。命名在此扮演要角:只給資源邏輯名稱(名稱中不暗藏位置資訊)即可達成,例如 URL http://www.prenhall.com/index.html 完全看不出 Prentice Hall 主網站伺服器在哪裡。
  • 遷移透明性(migration transparency):資源可以被搬移,而不影響它被存取的方式。
  • 重定位透明性(relocation transparency):更強的形式——資源在被存取的當下仍可搬移,使用者或應用程式毫無所覺。例如行動使用者帶著無線筆電四處移動,連線從未(暫時)中斷。
  • 複製透明性(replication transparency):隱藏「一份資源存在多個副本」的事實。資源可能為了提高可用性、或為了把副本放在靠近存取點以提升效能而複製。要隱藏複製,所有副本必須共用同一名稱——因此支援複製透明性的系統,通常也應支援位置透明性。
  • 並行透明性(concurrency transparency):資源共享除了合作式,也有競爭式——兩個獨立使用者可能把檔案存在同一台檔案伺服器、或存取同一資料庫的相同資料表。此時每個使用者不應察覺對方也在使用同一資源。關鍵是並行存取必須讓資源保持一致的狀態:可以用鎖定(locking)機制輪流給予互斥存取,更精緻的做法是交易(transaction),但交易在分散式系統中相當難實作。
  • 失效透明性(failure transparency):使用者不會注意到某個資源故障,也不會注意到系統隨後從故障中恢復。

圖 1-2:分散式系統中不同形式的透明性(ISO, 1995)。

藍波特(Leslie Lamport)給過一個流行的分散式系統另類定義:「當一台你從沒聽過的電腦當機,害你什麼事都做不了時,你就知道自己有一個分散式系統了。」這句話點出了設計上的一大課題:處理失效。

遮蔽失效是分散式系統中最困難的問題之一,在某些看似合理的假設下甚至不可能做到(第 8 章討論)。主要困難在於無法區分「死掉的資源」與「極慢的資源」:瀏覽器連線忙碌的網站伺服器最終逾時、回報網頁不可用,但使用者無法據此斷定伺服器真的掛了。

透明性的程度#

雖然一般認為分散透明性對任何分散式系統都是好事,但試圖對使用者完全隱藏所有分散面向,未必是好主意

  • 有些事實藏不住:要求電子報照常在當地時間早上 7 點前送達信箱,但你人在地球另一端的不同時區——你收到的「晨報」就不會是你習慣的晨報。同樣地,連接舊金山與阿姆斯特丹兩地行程的廣域系統,無法隱藏大自然不允許訊息在約 35 毫秒內送達的事實;實務上經由電腦網路要花數百毫秒——訊號不只受光速限制,也受中間交換器處理能力限制。
  • 透明性與效能存在取捨:許多網際網路應用會反覆嘗試聯繫伺服器才放棄;為了遮蔽暫時性的伺服器失效而不斷重試,可能拖慢整個系統——不如早點放棄,或至少讓使用者可以取消嘗試。又如要求分布在不同大洲的多個副本隨時保持一致(一份修改必須先傳播到所有副本才允許其他操作),單一更新操作可能耗時數秒,這無法對使用者隱藏。
  • 有時暴露分散反而更好:隨著分散式系統延伸到人們隨身攜帶的裝置,位置與情境感知(context awareness)日益重要,此時揭露分散可能比隱藏更好。簡單例子:上班族想從筆電列印檔案,把列印工作送到附近忙碌的印表機,比送到另一個國家總部那台閒置的印表機更好。
延伸論點:假裝能達成完全透明,明智嗎?

還有另一類反對分散透明性的論點:既然承認完全的分散透明性根本不可能,我們是否還該假裝能達成它?把分散明白揭露,讓使用者與應用程式開發者永遠不被「透明性存在」的假象欺騙,或許好得多。結果是使用者能更理解分散式系統(有時出乎意料)的行為,也更有準備去應對這些行為。

結論:把分散透明性當作設計與實作的目標是好的,但必須與效能、可理解性等其他議題一併權衡。為了追求無法達成的完全透明性,付出的代價可能高得驚人。

開放性#

開放的分散式系統(open distributed system)依照標準規則提供服務,這些規則描述服務的語法與語義。例如電腦網路中,標準規則規範訊息的格式、內容與意義,並被形式化為協定(protocol)

在分散式系統中,服務通常透過**介面(interface)規範,常以介面定義語言(Interface Definition Language, IDL)**描述:

  • IDL 幾乎只能捕捉服務的語法:可用的函式名稱、參數型別、回傳值、可能拋出的例外等。
  • 困難的部分是精確描述服務做什麼,也就是介面的語義。實務上,這類規格總是以自然語言非正式地給出。

介面定義若寫得好,可以讓需要某介面的任意行程,與提供該介面的另一行程對話;也允許兩個獨立團隊各自打造完全不同的實作,得到兩個運作方式一模一樣的分散式系統。好的規格應該完整(complete)且中立(neutral)

  • 完整:實作所需的一切都已規範。許多介面定義並不完整,開發者必須自行補上實作細節。
  • 中立:規格不規定實作該長什麼樣子。

完整性與中立性對互通性可移植性很重要(Blair and Stefani, 1998):

  • 互通性(interoperability):不同廠商的兩個系統或元件實作,只靠共同標準所規範的彼此服務,就能共存並協同運作的程度。
  • 可移植性(portability):為分散式系統 A 開發的應用程式,不經修改就能在實作相同介面的另一系統 B 上執行的程度。

開放的分散式系統還應該可延伸(extensible):容易用不同(可能來自不同開發者的)元件組裝系統、容易新增元件或替換既有元件而不影響留在原地的元件——例如相對容易加入跑在不同作業系統上的部件,甚至替換整個檔案系統。但如許多人的日常經驗所知,達到這種彈性說易行難。

政策與機制分離#

要在開放的分散式系統中達成彈性,關鍵是把系統組織成一組相對小而容易替換、調整的元件

  • 不只為最高層(使用者與應用程式看到的)介面提供定義,也要為系統內部各部件的介面及其互動方式提供定義。
  • 許多較舊、甚至當代的系統採**單體式(monolithic)**做法:元件只在邏輯上分離,實作上卻是一支巨大的程式。這使得替換或調整任一元件都會牽動整個系統——單體式系統因此傾向封閉而非開放。

系統需要更動,常是因為某元件的政策(policy)對特定使用者或應用不是最佳的。因此我們需要的是政策與機制(mechanism)的分離

延伸案例:Web 快取的政策與機制

以全球資訊網(World Wide Web)的快取為例。瀏覽器通常允許使用者調整快取政策:指定快取大小、快取文件要每次檢查一致性還是每個工作階段只檢查一次。但使用者無法影響其他快取參數:文件可以在快取中留多久、快取滿了該淘汰哪份文件;也不可能根據文件內容做快取決策——例如使用者想快取幾乎不變的火車時刻表,但絕不想快取高速公路即時路況。

理想上,瀏覽器應只提供儲存文件的機制,同時讓使用者決定存哪些文件、存多久。實務上可以提供一組可(動態)調整的豐富參數;更好的是讓使用者能把自己的政策實作成可插入瀏覽器的元件——當然,該元件必須具備瀏覽器看得懂的介面,才能被呼叫。

可擴展性#

全球性的網際網路連結已如寄明信片般平常,**可擴展性(scalability)**因此成為分散式系統開發者最重要的設計目標之一。

系統的可擴展性至少可沿三個維度衡量(Neuman, 1994):

  • 規模(size)可擴展:能輕鬆加入更多使用者與資源。
  • 地理(geographical)可擴展:使用者與資源可以相距很遠。
  • 管理(administrative)可擴展:即使橫跨許多獨立的行政組織,仍然容易管理。

可惜的是,在一個或多個維度上可擴展的系統,往往在規模擴大時出現一定程度的效能損失。

可擴展性問題#

規模擴展受限於三種「集中式」設計(圖 1-3 歸納):

  • 集中式服務:單一伺服器服務所有使用者。使用者與應用增加時,伺服器成為瓶頸;即使處理與儲存容量近乎無限,與該伺服器的通訊終將阻止進一步成長。不過單一伺服器有時無可避免——例如管理病歷、銀行帳戶等高度機密資訊的服務,放在一間高度安全的獨立機房、以特殊網路元件與系統其他部分隔離可能是最佳選擇,因為把伺服器複製到多處雖能提升效能,卻會讓服務更不安全。
  • 集中式資料:單一資料庫會讓進出它的通訊線路飽和。想像 5,000 萬人的電話號碼與地址:每筆 50 字元,一個 2.5 GB 的磁碟分割區就存得下,但單一資料庫必然癱瘓。同理,若 DNS(Domain Name System)仍是一張單一表格、每次 URL 解析都得送到唯一的 DNS 伺服器,沒有人用得了 Web。
  • 集中式演算法:大型分散式系統中有大量訊息要在許多線路上繞送。理論上的最佳解是收集所有機器與線路的完整負載資訊、算出所有最佳路由再散播結果——但收集與傳輸這些資訊本身就會壓垮部分網路。事實上,任何「從所有站點收集資訊、送到單一機器處理、再散播結果」的演算法都應避免。

圖 1-3:可擴展性限制的例子。

只有**去中心化演算法(decentralized algorithm)**才該使用,其特徵為:

  • 沒有任何機器擁有系統狀態的完整資訊。
  • 機器只根據本地資訊做決策。
  • 一台機器故障不會毀掉整個演算法。
  • 不隱含「存在全域時鐘」的假設。

第四點較不明顯但同樣重要:任何以「12:00:00 整,所有機器記下輸出佇列長度」開頭的演算法都會失敗,因為不可能讓所有時鐘精確同步。演算法必須把「缺乏精確時鐘同步」納入考量;系統越大,不確定性越大。在單一 LAN 上花大力氣或許能把時鐘同步到幾微秒內,但跨國、跨洲就非常棘手。

地理擴展有自己的難題:

  • 同步通訊(synchronous communication):許多為 LAN 設計的系統採用「客戶端(client)發出請求後阻塞等待回覆」的模式。LAN 上兩機通訊最差不過幾百微秒,這行得通;但廣域系統的行程間通訊可能要數百毫秒,慢了三個數量級。用同步通訊在廣域系統上蓋互動式應用,需要大量細心(和不小的耐心)。
  • 廣域通訊本質不可靠、且幾乎都是點對點:LAN 通常提供基於廣播的高可靠通訊,開發分散式系統容易得多——例如要找某服務,在 LAN 上行程可以直接廣播詢問每台機器,有該服務的機器回覆自己的網路位址即可。這種定位方式在廣域系統中不可想像(想像在整個網際網路上這樣找服務),必須設計專門的定位服務,且可能要擴展到全球、服務十億使用者(第 5 章)。
  • 集中式元件加劇地理擴展問題:廣域通訊的效能與可靠性問題會限制地理擴展,且集中式元件還會浪費網路資源——想像全國共用一台郵件伺服器,寄信給鄰居也得先繞到可能數百英里外的中央伺服器。

管理擴展則是困難且多半仍未解的問題:如何讓分散式系統跨越多個獨立的行政網域(administrative domain)。主要得解決資源使用(與付費)、管理、安全政策的衝突

  • 同一網域內的元件通常可被該網域使用者信任——管理者測試並認證過應用程式,也採取了防竄改措施;但這種信任不會自然延伸跨越網域邊界
  • 系統一旦跨進新網域,需要兩類安全措施:其一,分散式系統要防範新網域的惡意攻擊(例如新網域使用者對原網域檔案系統只有讀取權;昂貴設備不開放給外來使用者)。其二,新網域也要防範來自分散式系統的惡意攻擊——典型例子是下載 Web 瀏覽器中的 applet 之類程式:新網域不知道這些外來程式碼會做什麼,可能決定嚴格限制其存取權,難題(見第 9 章)在於如何強制執行這些限制。

擴展技術#

可擴展性問題多半以「伺服器與網路容量有限造成的效能問題」呈現。基本的擴展技術只有三種(參見 Neuman, 1994):隱藏通訊延遲、分散(distribution)、複製(replication)

隱藏通訊延遲——對地理擴展尤其重要,基本想法是盡量避免枯等遠端服務回應:

  • 使用非同步通訊(asynchronous communication):發出請求後繼續做其他有用的工作,回覆到達時中斷應用程式、呼叫處理常式完成先前的請求。這適合批次處理系統與平行應用,因為它們有較獨立的工作可以排程。或者,另起一條執行緒等待回覆,行程中其他執行緒照常執行。
  • 許多應用(例如互動式應用:使用者送出請求後多半只能等答案)用不上非同步通訊。此時更好的解法是減少整體通訊量,把原本在伺服器端的部分運算搬到客戶端。典型案例是用表單存取資料庫:與其每填一個欄位就送一則訊息、等伺服器確認(例如檢查語法錯誤),不如把填表與檢查欄位的程式碼送到客戶端,由客戶端回傳一份填好的完整表單。這種「搬運程式碼」的做法如今在 Web 上以 Java applet 與 JavaScript 的形式被廣泛支援。

圖 1-4:由 (a) 伺服器或 (b) 客戶端在表單填寫過程中做檢查,兩者的差異。

分散——把一個元件拆成較小的部分,再把這些部分散布到系統各處:

延伸案例:DNS 與 Web 的分散
  • DNS:DNS 名稱空間階層式地組織成網域樹,並切分成互不重疊的區(zone),每一區的名稱由單一名稱伺服器處理。解析一個名稱(可視為網際網路上某主機的名稱,對應其網路位址)如 nl.vu.cs.flits:先交給第一層區的伺服器,它回傳下一層區伺服器的位址,剩餘的 vu.cs.flits 交給它處理;如此逐層下推,最後一層伺服器回傳目標主機的位址。DNS 的命名服務因此分散在多台機器上,避免單一伺服器承擔所有名稱解析請求。

圖 1-5:把 DNS 名稱空間切分成區(zone)的一個例子。

  • Web:對多數使用者而言,Web 看起來像一個巨大的文件式資訊系統,每份文件有唯一的 URL,甚至彷彿只有一台伺服器。但實體上 Web 分散在大量伺服器上,各自負責一部分文件;負責某文件的伺服器名稱就編在該文件的 URL 裡。正因這種文件的分散,Web 才能擴展到今日的規模。

複製與快取——可擴展性問題常以效能劣化呈現,因此把元件複製到系統各處通常是好主意:

  • 複製不僅提高可用性,也有助於元件間的負載平衡而改善效能;在地理上高度分散的系統中,就近的副本還能遮掩前述大部分通訊延遲問題。
  • 快取(caching)是複製的特殊形式(兩者的界線常常很模糊、甚至是人為的):同樣是在客戶端附近做出資源副本,但快取是資源使用者(客戶端)的決策,而非資源擁有者的決策;而且快取是按需(on demand)發生,複製則通常是事先規劃

快取與複製有一個嚴重的副作用可能反噬可擴展性:一致性問題。多份副本中改了一份,它就與其他副本不同了。能容忍多少不一致取決於資源用途——許多 Web 使用者可以接受瀏覽器回傳幾分鐘沒驗證過的快取文件;但電子證券交易、拍賣等場合需要強一致性:更新必須立即傳播到所有副本,兩個並行更新還常要求各副本以相同順序套用。這通常需要全域同步機制,而這類機制幾乎不可能以可擴展的方式實作(光子與電訊號終究受光速——約 187 英里/毫秒——限制)。以複製求擴展,可能反過來引入本質上不可擴展的解法。(複製與一致性詳見第 7 章。)

綜合來看三個維度:

  • 規模擴展技術上最不成問題:很多時候直接加大機器容量就能(至少暫時、也許代價不小地)救場。
  • 地理擴展難得多,因為大自然擋在中間;但實務顯示,結合分散、複製與快取,再搭配不同形式的一致性,多數情況已經足夠。
  • 管理擴展看來最難,部分因為要解決的是非技術問題(組織政治與人的協作)。不過這方面也有進展——點對點(peer-to-peer)技術的興起與普及,展示了讓終端使用者直接接管控制權能達到什麼(Aberer and Hauswirth, 2005; Lua et al., 2005; Oram, 2001);但要說清楚:P2P 至多只是管理擴展的部分解法,這個問題終究得正面處理。

陷阱#

開發分散式系統是艱鉅的任務:要同時考慮的議題太多,彷彿只會得到複雜性。不過只要遵循一些設計原則,仍能開發出貼近本章目標的系統——其中許多原則就是體面軟體工程的基本守則,不再重複。

分散式系統與傳統軟體的差別在於:元件散布在網路上。設計時不考慮這種分散性,正是許多系統無謂複雜、事後不斷補洞的原因。當時任職於 Sun Microsystems 的彼得・多伊奇(Peter Deutsch)把這些錯誤歸納為——每個人第一次開發分散式應用時都會做的錯誤假設

  1. 網路是可靠的。
  2. 網路是安全的。
  3. 網路是同質的。
  4. 拓撲不會改變。
  5. 延遲為零。
  6. 頻寬無限大。
  7. 傳輸成本為零。
  8. 只有一位管理者。

這些假設恰好對應分散式系統特有的性質:網路的可靠性、安全性、異質性與拓撲;延遲與頻寬;傳輸成本;以及行政網域。開發非分散式應用時,這些問題多半不會浮現;而本書討論的多數原理,正是在處理「某一個或多個假設不成立」所導致的問題——例如可靠的網路根本不存在,所以失效透明性不可能完全達成;網路通訊本質不安全,本書用一整章處理;複製解可擴展性,實質上就是在對付延遲與頻寬問題;管理議題則對應「傳輸零成本」與「單一行政網域」這兩個錯誤假設。