日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Google Chubby 论文翻译

發布時間:2024/2/28 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Google Chubby 论文翻译 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

摘要

1 介紹

2 設計

3?擴展機理

4 實際應用,意外和設計錯誤

5 與相關工作的比較

6 總結

7 感謝


松耦合分布式系統的鎖服務 Chubby

摘要

我們描述了我們使用 Chubby 鎖服務的經驗,該服務旨在為松散耦合的分布式系統提供粗粒度的鎖以及可靠的(盡管體積很小)存儲。Chubby 提供了一個類似于帶有咨詢鎖的分布式文件系統的接口,但是其設計重點是可用性和可靠性,而不是高性能。該服務的許多實例已經使用了一年多,其中幾個實例同時處理數萬個客戶端。本文描述了最初的設計和預期的使用,并將其與實際使用進行了比較,解釋了如何修改設計以適應差異。

?

1 介紹

本文介紹了一種名為 Chubby 的鎖服務。它的目標是在一個松散耦合的分布式系統中使用,該系統由大量的小機器通過高速網絡連接而成。例如,一個 Chubby 的實例(也稱為 Chubby?cell?)可能服務于由 1Gbit/s 以太網連接的 10,000 臺 4 處理器機器。大多數 Chubby?cell?被限制在一個單獨的數據中心或機房里,盡管我們確實運行著至少一個 Chubby?cell,它們復制品之間相隔數千公里。

鎖服務的目的是允許它的客戶端同步它們的活動,并就它們的環境的基本信息達成一致。主要目標包括可靠性、對中等規模的客戶端的可用性和易于理解的語義;吞吐量和存儲容量被認為是次要的。Chubby 的客戶端接口類似于執行整個文件讀寫的簡單文件系統,并增加了通知鎖和文件修改等各種事件的通知。

我們希望 Chubby 能夠幫助開發人員處理系統內的粗粒度同步,特別是處理從一組其他方面相當的服務器中選出一個 Leader 的問題。例如,Google?文件系統使用一個 Chubby 鎖來指定一個 GFS Master,而 Bigtable 以幾種方式使用 Chubby?:選擇一個 Master?,允許 Master?發現它所控制的服務器,以及允許客戶端找到 Master。此外,GFS 和 Bigtable 都使用 Chubby 存儲少量元數據;實際上,他們使用 Chubby 作為分布式數據結構的根。一些服務使用鎖在多個服務器之間(以粗粒度)劃分工作。

在部署 Chubby 之前,Google?上的大多數分布式系統都使用了一些特別的方法來進行 Primary 選舉(當工作可以在不造成任何傷害的情況下進行復制時),或者需要操作員的干預(當正確性非常重要時)。在前一種情況下,Chubby 允許在計算工作中節省一點時間。在后一種情況下,它顯著提高了系統的可用性,不再需要人為干預。

熟悉分布式計算的讀者將會認識到,在 Peers 之間進行 Primary 選舉是分布式一致性問題的一個實例,并意識到我們需要一個使用異步通信的解決方案;這個術語描述了絕大多數真實網絡(如以太網或 Internet )的行為,這些網絡允許數據包丟失、延遲和重新排序。(實踐者通常應該注意基于模型的協議,這些模型對環境做出了更強的假設。)異步一致性通過 Paxos 協議解決。Oki 和 Liskov 使用了相同的協議(參見他們關于 viewstamped replication 的論文),其他人也注意到了這種等價性。實際上,我們目前遇到的所有異步協商一致的工作協議的核心都是 Paxos。Paxos 在沒有時間假設的情況下保持安全,但必須引入時鐘以確保活性;這克服了 Fischer 等人的不可能的結果。

建設 Chubby 是一項工程努力,需要滿足上述需求;這不是研究。我們沒有提出新的算法或技術,這篇論文的目的是描述我們做了什么,為什么做,而不是提倡它。在下一節中,我們將介紹 Chubby 的設計和實現,以及它是如何根據經驗進行更改的。我們描述了 Chubby 出人意料的用法,以及被證明是錯誤的功能。我們省略了文獻中其他地方所涉及的細節,例如一致性協議或?RPC?系統的細節。

?

2 設計

2.1?基本原理

有人可能會說,我們應該構建一個包含 Paxos 的庫,而不是一個訪問集中式鎖服務(甚至是一個高度可靠的鎖服務)的庫。客戶端?Paxos 庫將不依賴于任何其他服務器(除了 name service 之外),并為程序員提供標準框架,假設他們的服務可以作為狀態機實現。實際上,我們提供了這樣一個獨立于 Chubby 的客戶端庫。

盡管如此,與客戶端庫相比,鎖服務有一些優勢。首先,我們的開發人員有時并不按照期望的方式計劃高可用性。他們的系統通常以原型開始,只有很少的負載和松散的可用性保證;通常情況下,代碼并沒有特別的結構來與一致協議一起使用。隨著服務的成熟和客戶的增加,可用性變得更加重要然后將復制和 Primary 選舉添加到現有設計中。雖然這可以通過提供分布式一致性的庫來實現,但是鎖服務器使維護現有的程序結構和通信模式變得更加容易。例如,選出一個 Master 然后寫入現有的文件服務器需要將兩個語句和一個?RPC?參數添加到一個現有的系統一個將獲得一個鎖成為 Master 通過額外的整數(鎖獲取計數)寫?RPC ,如果請求計數低于當前值(防止數據包延遲)將一個 if 語句添加到文件服務器拒絕寫。我們發現這種技術比讓現有的服務器加入一致協議更容易,尤其是在遷移期間(?transition period )必須維持兼容性時。

其次,我們的許多服務選擇一個主服務,或者在它們的組件之間劃分數據,這些服務需要一種發布結果的機制。這意味著我們應該允許客戶端存儲和獲取少量數據——也就是說,讀取和寫入小文件。這可以通過 name service 來完成,但是我們的經驗是,鎖服務本身非常適合這項任務,因為它減少了客戶所依賴的服務器數量,而且協議的一致性特性是相同的。Chubby 作為 name server 的成功很大程度上歸功于它使用了一致的客戶緩存,而不是基于時間的緩存。特別的是,我們發現開發者不會選擇像 DNS 生存時間?TTL(time-to-live) 一樣的緩存超時值,這個值如果選擇不當會導致很高的 DNS 負載或者較長的客戶端故障修復時間。

第三,我們的程序員更熟悉基于鎖的接口。Paxos 的復制狀態機 (replicated state machine) 和與排他鎖相關聯的臨界區都能為程序員提供順序編程的幻覺。可是,許多程序員已經用過鎖了,并且認為他們知道怎么使用它們。頗為諷刺的是,這樣的程序員經常是錯的,尤其是當他們在分布式系統里使用鎖時。很少人考慮單個機器的失敗對一個異步通信的系統中的鎖的影響。不管怎樣,對鎖的 "熟悉性",戰勝了我們試圖說服程序員們為分布式決策使用可靠機制的努力。

最后,分布式一致性算法使用 Quorums 進行決策,因此它們使用多個副本來實現高可用性。例如,通常 Chubby 本身在每個?cell?中有5個副本,Chubby 單元要存活就必須保證其中三個副本在正常運行。相反,如果客戶端系統使用鎖服務,即使個客戶端也可以獲得鎖并安全地進行處理。因此,鎖服務減少了可靠客戶端系統運行時所需的服務器數量。在廣義上,人們可以將鎖服務視為一種提供通用選擇的方法,這種選擇允許客戶端系統在其自身成員未達到大多數時做出正確的決策。人們可以想象用另一種方式解決最后這個問題通過提供?"一致服務",在 Paxos 協議中使用許多服務器來提供?"接受者"。與鎖服務一樣,共識服務允許客戶端在只有一個活動客戶端進程的情況下安全地進行類似的技術也用于減少拜占庭式容錯所需的狀態機數量。然而,假設協服務不是專門用于提供鎖(這將其簡化為鎖服務),則此方法無法解決上述任何其他問題。

這些論證提出了兩個關鍵的設計決策

  • 我們選擇了一個鎖服務,而不是一個庫一致性服務來達成共識,以及
  • 我們選擇提供小文件,使得被選出來的 Primaries 可以公布自身以及它們的參,而不是創建和維護另一個服務。

一些決定來自我們的預期使用和我們的環境

  • 通過一個?Chubby?的文件公布其?Primary?服務可能會有成千上萬的客戶。因此,我們必須允許數千個客戶端監視這個文件,并且在這一過程中最好不需要多服務器。
  • 客戶端和有多個副本(replica)的服務的各個副本要知道什么時候服務的 Primary 發生了變化。這意味著一種事件通知機制將有助于避免輪詢。
  • 即使客戶不需要定期輪詢文件,許多客戶會這樣做這是支持許多開發人員的結果。因此,緩存這些文件是可取的。
  • 我們的開發人員被直觀的緩存語義搞糊涂了,所以我們更喜歡一致的緩存。
  • 為了避免經濟損失和牢獄之災我們提供了包括訪問控制在內的安全機制。

一個可能會讓一些讀者感到驚訝的選擇是,我們不期望鎖的使用是細粒度的,在這種情況下,鎖可能只被持有很短的時間(數秒鐘或更少)實際上,我們期望粗粒度的使用。例如,一個應用程序可能使用一個鎖來選擇一個 Master,然后 Master?將在相當長的時間內(幾小時或幾天)處理對該數據的所有訪問。這兩種使用方式意味著對鎖服務器的不同需求。

粗粒度鎖對鎖服務器的負載要小得多。特別是,鎖的獲取頻率通常與客戶端應用系統的事務頻率只有很微弱的關聯。粗粒度的鎖很少被獲取,所以臨時性的鎖服務器不可用給客戶端造成的延時會更少。另一方面,鎖客戶端間的轉移可能需要高昂的恢復處理所以人們不希望鎖服務器的故障恢復導致鎖丟失。因此,粗粒度的鎖可以很好地應對鎖服務器故障,幾乎不需要考慮這樣做的開銷,而且這樣的鎖允許少量的鎖服務器以較低的可用性為許多客戶端提供足夠的服務。

細粒度的鎖會有不同的結論。即使鎖服務器短暫地不可用,也可能導致許多客戶端被掛起。因為鎖服務的事務頻率隨著客戶事務頻率之和一起增長所以性能和隨意增加新服務器的能力非常重要。通過不維護跨鎖服務器故障的鎖來減少鎖的開銷是有優勢的,而且由于鎖只會被持有很短的時間,所以偶爾丟棄鎖的時間損失并不嚴重。(客戶端必須準備好在網絡分區期間丟失鎖,所以鎖服務器故障恢復造成的鎖的丟失不會引入新的恢復路徑。)

Chubby 只提供粗粒度的鎖定。幸運的是,客戶可以直接實現針對其應用程序定制的細粒度鎖。應用程序可以將其鎖劃分為組,并使用 Chubby 的粗粒度鎖將這些鎖組分配給應用程序特定的鎖服務器。維護這些細粒度的鎖只需要很少的狀態服務器只需要保持一個穩定的、單調遞增很少更新的請求計數器客戶端能夠在解鎖時發現丟失了的鎖,如果使用簡單的定長租(lease),協議會變得簡單而有效。此方案最重要的好處是,我們的客戶端開發人員負責提供支持其負載所需的服務器,而不必自己實現共識機制

?

2.2 系統結構

Chubby 有兩個通過?RPC?通信的主要組件服務器和客戶應用程序鏈接的庫參見圖1。Chubby 客戶和服務器之間的所有通信都由客戶庫進行中介。第3.1節討論了可選的第三個組件,即代理服務器。

一個?Chubby?單元由一組稱為副本(replicas)的服務器(通常是5個)組成,放置這些服務器是為了減少相關故障的可能性(例如,放在不同的機架上)。副本使用一個分布式一致性協議來選舉一個 Master?;Master?必須從大多數副本中獲得選票,并保證這些副本在 Master?租用的幾秒鐘內不會選擇其他的 Master。主租賃由副本定期更新,前提是主租賃繼續贏得多數選票。

副本維護一個簡單數據庫的副本,但是只有 Master?會發起對數據庫的讀寫。其他所有副本只是復制來自 Master?的更新,使用一致性協議發送。

客戶端通過向 DNS 中列出的副本發送 Master?位置請求來找到 Master。非主副本通過返回主副本的身份來響應此類請求。一旦客戶端找到了 Master,客戶端就會將所有請求定向到它,直到它停止響應,或者直到它指出它不再是 Master。寫請求通過協商一致協議傳播到所有副本當寫操作到達計算單元中的大多數副本時,將確認這些請求。讀請求僅由 Master?來滿足這是安全的,只要主租賃沒有到期,因為沒有其他的 Master?存在。如果 Master?失敗,其他副本在其 Master?租約到期時運行選舉協議新的 Master?通常會在幾秒鐘內選出。例如,最近的兩次選舉分別了 6s 和 4s,但我們也見過長達 30s?的情況

如果一個副本發生故障,并且幾個小時內無法恢復,則簡單的替換系統將從空閑池中選擇一臺新機器,并啟動其上的鎖服務器二進制文件。然后更新 DNS 表,將失敗副本的 IP 地址替換為新副本的 IP 地址。當前的 Master?定期輪詢 DNS,并最終注意到變化。然后更新單元數據庫中單元成員的列表這個列表通過正常的復制協議在所有成員之間保持一致。與此同時,新副本從存儲在文件服務器上的備份和活動副本的更新組合中獲取數據庫的最新副本。一旦新副本處理了當前 Master?等待提交的請求,就允許該副本在新 Master?的選舉中投票。

?

2.3 文件、目錄和句柄

Chubby?開放的文件系統接口與 UNIX 類似,但比后者更簡單。它通常按照的方式由嚴格的文件和目錄樹組成,名稱組成部分由斜杠分隔。一個典型的名字是:? ?/ ls / foo /wombat/pouch

ls 前綴對所有?Chubby?的名字都相同,代表鎖服務(lock service)。第二部分(foo)是一個?Chubby?單元的名稱它通過 DNS 查詢解析為一個或多個?Chubby?服務器。一個特殊的單元名稱?local表示應該使用客戶端的本地?Chubby?單元這個 Chubby 單元通常在同一棟樓里,因此這個單元最有可能能訪問到。名字的剩余部分,/wombat/pouch,是在?Chubby?單元解析的。同樣,在 UNIX 下,每個目錄包含子文件和目錄的列表,而每個文件包含未解析的字節序列。

因為 Chubby 的命名結構類似于一個文件系統,所以我們既可以通過專門的?API 將它開放給應用系統,也可以通過我們其他文件系統例如 GFS 使用的接口。顯著地減少了編寫基本的瀏覽和名空間操作工具所需的工作,也減少了培訓那些偶然使用 Chubby 的用戶的需求。

這種設計使得?Chubby 接口不同于 UNIX 文件系統,它使得分布更容易(The design differs from UNIX in a ways that easy distribution)。為允許不同目錄下的文件由不同的 Chubby master?來服務,我們沒有放出那些將文件從一個目錄移動到另一個目錄的操作,我們不維護目錄修改時間,也避開路徑相關的權限語義(也就是文件的訪問由其本身的權限控制,而不由它上層路徑上的目錄控制)。 為使緩存文件元數據更容易,系統不公開最后訪問時間。

名稱空間只包含文件和目錄,統稱為節點。每個這樣的節點在其Chubby單元內只有一個名稱沒有符號鏈接和硬鏈接。

節點可以是永久的(permanent),也可以是短暫的(ephemeral)任意節點都可以被顯示地(explicitly)刪除,但是瞬時節點也會在沒有客戶端打開它時被刪除 (另外,對目錄而言,在它們為空時被刪除)。短暫的文件用作臨時文件,并作為其他客戶端存活的指示器。任意節點都能作為一個意向性(advisory)的讀寫鎖;這些鎖將在 2.4 節更詳細地描述。

每個節點都有多種元數據,包括訪問控制列表 (access control lists,ACLs) 的三個名字,分別用于控制讀、寫和修改其 ACL。除非被覆蓋,否則節點在創建時將繼承其父目錄的 ACL 名稱。ACLs 本身是位于一個 ACL 目錄中的文件?這個 ACL 目錄是 Chubby 單元的一個為人熟知的本地名字空間。這些 ACL 文件的內容由簡單的訪問名字(principals)列表組成;讀者可能會想起?Plan 9 的?groups?。因此,如果文件 F 的寫 ACL 名稱是 foo,并且 ACL 目錄包含一個 foo 文件,foo 文件中包含 bar 這個條目,那么用戶 bar 就可以寫文件 F。用戶由內嵌在?RPC?系統里的機制鑒權。因為 Chubby 的 ACLs 是平常的文件,它們自動地就可以由其他想使用類似的訪問控制機制的服務訪問。

每個節點的元數據包括四個單調增加的 64 位編號有利于客戶端很容易地檢測變化

  • 實例編號:大于任意先前的同名節點的實例編號。
  • 內容生成編號(僅限文件)當寫入文件的內容時,這個值會增加。
  • 鎖生成編號當節點的鎖從空閑狀態轉換到被持有狀態時,這個值會增加。
  • ACL 生成編號當寫入節點的 ACL 名稱時,這種情況會增加。
  • Chubby 還開放了一個 64 位的文件內容校驗和,以便客戶端可以判斷文件是否有變化

客戶端通過打開節點以獲得類似于 UNIX 文件描述符的句柄。句柄包括

  • 校驗位:阻止客戶端自行創建或猜測句柄,所以完整的訪問控制檢查只需要在句柄創建時執行(對比UNIX,UNIX 在打開時檢查權限位但在每次讀寫時不檢查,因為文件描述符不能偽造)。
  • 一個序列號:這個序列號允許 Master?分辨一個句柄是由它或前面的 Master?生成。
  • 模式信息:在句柄打開時設定的是否允許新 Master?在遇見一個由前面的 Master?創建的舊句柄時重建該句柄的狀態。

?

2.4 鎖和計序器

每個 Chubby 文件和目錄都可以充當讀/寫鎖:一個客戶端句柄可以在獨占(寫)模式下持有鎖,或者任意數量的客戶端句柄可以在共享(讀)模式下持有鎖。就像大多數程序員所知道的互斥鎖(mutexes)一樣,鎖是協同鎖(advisory?lock)。也就是說,它們只與獲取相同鎖的其他請求沖突:持有鎖F既不是訪問文件F的必要條件,也不會阻止其他客戶端訪問文件F。我們舍棄強制鎖(mandatory lock)因為它使得其他沒有持有鎖的客戶端不能訪問被鎖定的對象

  • Chubby 鎖通常保護由其他服務實現的資源,而不僅僅是與鎖相關的文件。要以一種有意義的方式強制實施強制鎖定,我們需要對這些服務進行更廣泛的修改。
  • 我們不希望強制用戶在出于調試或管理目的需要訪問鎖定的文件時關閉應用程序。在復雜的系統中,使用大多數個人計算機上使用的方法比較困難,在這種情況下,管理軟件可以通過指示用戶關閉其應用程序或重新啟動來打破強制鎖。
  • 我們的開發人員以傳統的方式執行錯誤檢查,編寫諸如 "持有鎖X" 之類的斷言,因此他們從強制檢查中獲益甚微。當不持有鎖時,有 bug 的或惡意的進程有很多機會破壞數據,所以我們發現強制鎖提供的額外保護沒有多大價值。

在 Chubby 中,請求任意模式的鎖都需要寫權限,因而一個無權限的讀者不能阻止一個寫者的操作。

在分布式系統中,鎖是復雜的,因為通信經常是不確定的,并且進程可能會獨立地失敗。因此可能會出現這種情況,持有鎖 L 的進程可能會發出請求 R,但隨后就會失敗了。另一個進程可能在 R 獲取之前就獲得了 L,并執行了一些操作。如果 R 稍后到達,它可能在沒有 L 保護的情況下被執行,并且可能對不一致的數據進行操作。接收消息順序紊亂的問題已經被研究得很徹底:解決方案包括虛擬時間(virtual time)和虛擬同步(virtual synchrony)后者通過確保與每個參與者的觀察一致的順序處理消息,從而避免了這個問題。

在現有的復雜系統中,將序列號引入到所有的交互中的成本是很高的。相反,Chubby 提供了一種方法,通過這種方法,序列號只能被引入到那些使用鎖的交互中。在任何時候,鎖的持有者都可以請求一個序號,這是一個不透明的字節串,描述鎖在剛獲取后的狀態。它包含鎖的名稱、獲取鎖的模式(獨占或共享)以及鎖的生成號( generation number)。如果客戶端希望它的操作受到鎖的保護,那么它就會將定序器 (sequencer) 傳遞給服務器(例如文件服務器)。接收服務器要做的工作是測試定序器 (sequencer) 是否仍然有效并具有適當的模式;如果不是,則應拒絕請求。可以根據服務器的 Chubby 緩存來檢查定序器的有效性,如果服務器不希望維護與 Chubby 的會話,也可以根據服務器觀察到的最新的定序器來檢查。定序器機制只需要向受影響的消息添加一個字符串,并且很容易向我們的開發人員解釋。

雖然我們發現定序器使用簡單,但重要的協議發展緩慢。因此,Chubby 提供了一種不完美但更簡單的機制,以減少向不支持定序器的服務器發送延遲或重新排序請求的風險。如果一個客戶端以正常的方式釋放了一個鎖,那么其他客戶端就可以立即使用這個鎖。但是,如果鎖因為持有者停止工作或不可訪問而變為空閑狀態,則鎖服務器將在一段被稱為鎖延遲?(lock-delay)?的時間段內阻止其他客戶端請求鎖。客戶端可以指定任何鎖延遲(目前上限是一分鐘);這個限制可以防止錯誤的客戶端使鎖(以及一些資源)在長時間內不可用。雖然不完美,但鎖延遲保護未修改的服務器和客戶端免受消息延遲和重啟造成的日常問題。

?

2.5 事件

Chubby 客戶端在創建句柄時可能訂閱一系列事件。這些事件通過來自 Chubby 庫的向上調用被異步傳遞到客戶端。活動包括:

  • 文件內容修改——通常用于監視通過文件發布的服務的位置。
  • 子節點 added, removed, 或 modified——用于實現鏡像。(除了允許發現新文件之外,為子節點返回事件還可以監視臨時文件而不影響它們的引用計數。)
  • Chubby master 故障恢復——警告客戶端其他事件可能已經丟失,因此必須重新檢查數據。
  • 句柄(及其鎖)已經失效——這通常意味著通信問題。
  • 鎖定獲取——可用于判斷什么時候 Primary?選出來了。
  • 來自另一個客戶端的沖突鎖請求允許緩存鎖。

事件是在相應的操作發生之后被交付的。因此,如果客戶端被告知文件內容已經更改,那么它隨后讀取文件時,保證能看到新數據(或最近的數據)。

上面提到的最后兩種事件很少用到,事后想來,可以忽略不計。例如,在 Primary 選舉之后,客戶端通常需要與新的 Primary 進行通信,而不是簡單地知道 Primary 的存在;因此,它們會等待 Primary 將地址寫入文件的文件修改事件。鎖沖突事件在理論上允許客戶端緩存其他服務器上的數據,使用 Chubby 鎖來維護緩存一致性。一個沖突的鎖請求將會告訴客戶端結束使用與鎖相關的數據:它將結束進行等待的操作、將修改刷新到原來的位置 (home location)、丟棄緩存的數據并釋放鎖。到目前為止,還沒有人采用這種方式。

?

2.6 API

客戶端將一個 Chubby 的句柄視為一個指向支持各種操作的不透明結構的指針。句柄僅由 Open() 創建,Close() 銷毀。

Open() 打開指定的文件或目錄以生成句柄,類似于 UNIX 文件描述符。只有這個調用使用節點名;其他的調用都在句柄上操作。相對于現有的目錄句柄計算名稱;庫提供了一個始終有效的 "/" 句柄。目錄句柄避免了在包含許多抽象層的多線程程序中使用程序范圍內的當前目錄的困難 (Directory handles avoid the difficulties of using a program-wide current directory in a multi-threaded program that contains many layers of abstraction)。

客戶端顯示多種選項

  • 句柄將如何使用(閱讀寫作和鎖定改變 ACL )只有當客戶端具有適當的權限時,才會創建句柄。
  • 應該交付的事件 (參見2.5)。
  • 鎖延遲 (參見2.4)。
  • 是否應該(或必須)創建新文件或目錄。如果創建了一個文件,調用者可以提供初始內容和初始的?ACL 名稱。其返回值表明這個文件實際上是否已經創建

Close() 關閉打開的句柄。不允許進一步使用該句柄。這個調用從來沒有失敗過。一個相關的調用?Poison() 會導致句柄上的未完成操作和后續操作失敗,而不關閉它這允許客戶端取消其他線程發出的 Chubby 調用,而不必擔心釋放它們訪問的內存。

作用于句柄的主要調用有

  • GetContentsAndStat() 返回文件的內容和元數據。文件的內容被原子地完整地讀取。我們避免了部分讀和寫來阻止大文件。一個相關的調用 GetStat() 只返回元數據,而 ReadDir() 返回子目錄的名稱和元數據。
  • SetContents() 寫一個文件的內容。可選地,客戶端可以提供內容生成編號(generation number),以允許客戶端模擬文件上的比較和交換只有在生成編號是當前值時內容才被改變。文件的內容總是以原子地、完整地寫入。一個相關的調用 SetACL()?節點關聯的 ACL 名稱執行類似的操作。
  • Delete() 刪除沒有子節點的節點。
  • Acquire(),TryAcquire(), Release() 獲取釋放鎖。
  • GetSequencer() 返回一個序號(參見2.4),它描述這個句柄持有的任何鎖。
  • SetSequalizer() 將一個序號與一個句柄相關聯。如果序號不再有效,則句柄上的后續操作將失敗。
  • CheckSequencer()?檢查序號是否有效(參見2.4)。

如果在創建句柄之后刪除了節點,即使隨后重新創建了文件,調用也會失敗。也就是說,句柄與文件實例相關聯,而不是與文件名相關聯。Chubby 可能在任意的調用上使用訪問控制,但總是檢查 Open() 調用(參見2.3)。

除了調用本身所需的任何其他參數外,上面的所有調用都使用一個操作參數。這個操作參數保存可能與任何調用相關聯的數據和控制信息。特別是通過操作參數,客戶可以

  • 提供一個回調,使調用異步,
  • 等待此類呼叫的完成,和/或
  • 獲取擴展的錯誤和診斷信息。

客戶端可以使用此 API 執行以下 Primary 選舉:所有潛在的 Primary 選舉都打開鎖文件并嘗試獲取鎖。其中一個成功并成為 Primary?,而其他的作為復制品。Primary?使用 SetContents() 將其標識寫入鎖文件,以便客戶端和副本能夠找到它,這些副本使用 GetContentsAndStat() 讀取文件,這可能是響應文件修改事件。理想情況下,Primary 通過 GetSequencer() 取得一個序號,然后將其傳遞給與之通信的服務器它們應該用?CheckSequencer() 確認它仍然是 Primary。鎖延遲可用于無法檢查序號的服務。

?

2.7?緩存

為了減少讀流量,Chubby?客戶端將文件數據和節點元數據(包括文件缺失)緩存在內存中的一個一致寫緩存中。緩存由下面描述的租約機制維護,并通過 Master?發送的失效操作維護一致,Master保存每個客戶端可能緩存的數據的列表。該協議確保客戶端要么看到一致的?Chubby?狀態,要么看到錯誤。

當要更改文件數據或元數據時,修改將被阻塞,而?Master?將數據的失效通知發送給可能已緩存數據的每個客戶端這個機制位于 KeepAlive RPC?之上,下一節將對此進行更詳細的討論。在收到無效通知時,客戶端刷新無效狀態并通過發出下一個 KeepAlive 調用進行確認。只有在服務器知道每個客戶端都將這些緩存失效之后,修改才會繼續進行,這可能是因為客戶端確認了失效,也可能是因為客戶端允許其緩存租約過期。

只需要進行一輪失效操作,因為?Master?在緩存過期信號沒有確認期間將這個節點視為不可緩存的。這種方法允許讀取總是被延遲處理這很有用,因為讀的數量遠遠超過寫的數量。另一種方法是在失效期間阻止訪問節點的調用這將減少過度渴望的客戶端在失效期間用未完成的訪問轟炸?Master?的可能性,代價是偶爾的延遲。如果這是一個問題,人們可能會想采用一種混合方案在檢測到過載時切換處理策略

緩存協議很簡單它在更改時使緩存的數據失效,并且永遠不會更新它。它只是簡單的更新而不是失效,但是只更新的協議可能會無理由地低效訪問文件的客戶端可能會無限期地接收更新,從而導致大量不必要的更新。

盡管提供嚴格一致性的開銷很大,我們還是拒絕了較弱的模型,因為我們覺得程序員會發現它們更難使用。類似地,像虛擬同步 (virtual synchrony) 這種要求客戶端在所有的消息中交換序號的機制,在一個有多種已經存在的通信協議的環境中也被認為是不合適的。

除了緩存數據和元數據之外,Chubby?客戶端還緩存打開的句柄。因此,如果客戶端打開了它之前打開的文件,那么只有第一個Open() 調用必然會導致?RPC?到達主機。這種緩存在一些次要的方面受到限制,因此它不會影響客戶端觀察到的語義臨時文件上的句柄在被應用程序關閉后,不能再保留在打開狀態而容許鎖定的句柄則可被重用,但是不能由多個應用程序句柄并發使用最后的這個限制是因為客戶端可能利用 Close() 或者 Poison() 的邊際效應:取消正在進行的向?Master?請求的 Accquire() 調用

Chubby 的協議允許客戶端緩存鎖——也就是說,持有鎖的時間比嚴格要求的長,希望它們可以被同一個客戶端再次使用。如果另一個客戶端請求了一個沖突鎖,則事件通知鎖持有者,這允許鎖持有者只在別的地方需要這個鎖時才釋放鎖

?

2.8 會話和?KeepAlives

Chubby?會話是?Chubby?的單元和?Chubby?客戶端之間的一種關系它存在一段時間,由定期的握手來維持,這種握手被稱為?KeepAlive。除非?Chubby 客戶端通知?Master?,否則客戶端的句柄、鎖和緩存的數據都是有效的,前提是它的會話仍然有效。(然而,會話維持的協議可能要求客戶端確認一個緩存過期信號以維持它的會話,請看下文)。

一個客戶端在第一次聯系一個 Chubby 單元的?Master?時請求一個新的會話。它顯式地結束會話,或者在它終止時,或者在會話處于空閑狀態時(一分鐘內沒有打開句柄和調用)。

每個會話都有一個相關的租期——一段延伸到將來的時間,在此期間,?Master?保證不會單方面終止會話。間隔的結束被稱作租期到期時間(lease timeout)。?Master?可以自由地向未來延長租期到期時間,但可能不會在時間上往回移動。

在三種情形下,?Master?延長租期到期時間在創建會話時、?Master?故障恢復時(見下面)以及響應來自客戶端的 KeepAlive RPC?時。在接收到 KeepAlive 時,?Master?通常會阻塞這個?RPC(不允許它返回),直到客戶端之前的租期接近到期。?Master?稍后允許?RPC?返回客戶端,并將新的租約超時通知客戶端。?Master?可以將超時時間延長任意數量。默認的延伸是 12s,但是一個載的?Master?可使用更高的值來減少它必須處理的 KeepAlive 調用的數量。在收到之前的回復后,客戶端立即啟動一個新的 KeepAlive。這樣,客戶端確保在?Master?上幾乎總是阻塞一個 KeepAlive 調用。

除了擴展客戶端的租期外,KeepAlive?的回復還用于將事件和緩存失效發送回客戶端。?Master?允許一個 KeepAlive 在有事件或者緩存過期需要遞送時提前返回。在 KeepAlive 應答上搭載事件可以確保客戶端在不確認緩存失效的情況下無法維護會話,并導致所有?Chubby?的?RPC?從客戶端流向?Master?。這樣既簡化了客戶端,也使得協議可以通過只允許單向發起連接的防火墻。

客戶端維護一個本地租約超時,這是?Master?租約超時的保守近似值。它跟?Master?的租期過期不一樣,是因為客戶端必須在兩方面做保守的假設。一是 KeepAlive 花在傳輸上的時間,一是?Master?的時鐘超前的度為了保持一致性,我們要求服務器的時鐘頻率相對于客戶端的時鐘頻率,不會快于某個常數量

如果客戶端的本地租約超時過期,它將不確定?Master?是否已終止了它的會話。客戶端清空并禁用其緩存,我們它的會話處于危險之中。客戶端等待一個稱為寬限期的間隔,默認為 45 秒。如果客戶端和?Master?在客戶端的寬限期結束之前成功 KeepAlive,則客戶端將再次啟用其緩存。否則,客戶端假定會話已經過期。這樣做是為了使 Chubby API 調用不會在一個 Chubby 單元變得不可訪問時無限期阻塞如果在通訊重新建立之前寬限期結束了,調用返回一個錯誤。

當寬限期開始時,Chubby 庫可以通過危險事件通知應用程序。當會話在通信問題中幸存下來時,安全事件告訴客戶端繼續如果會話超時,則發送一個過期事件。此信息允許應用程序在不確定其會話狀態時暫停自身,并在問題被證明是暫時的情況下無需重新啟動即可恢復。在啟動開銷很高的服務中,這在避免服務不可用方面可能是很重要的。

如果客戶端持有節點上的句柄 H,而 H 上的任何操作由于關聯的會話過期而失敗,則H上的所有后續操作 ( Close() 和 Poison() 除外 )都將以相同的方式失敗。客戶端可以使用它來保證網絡和服務器不可用時只導致操作序列的一個后綴丟失,而不是一個任意的子序列,從而允許使用最終寫入將復雜的更改標記為已提交。

?

2.9 故障恢復

當?Master?失敗或丟失?Master?身份時,它將丟棄關于會話、句柄和鎖的內存狀態。會話租約的權威計時器在?Master?上運行,因此,在選出新的?Master?之前,會話租約計時器將停止;這是合法的,因為它相當于延長客戶的租約。如果?Master?選舉發生得很快,客戶端可以在本地(近似)租約到期之前聯系新?Master?。如果選舉需要很長時間,客戶端就會清空他們的緩存,等待寬限期(grace period),同時試圖找到新的?Master?。因此,寬限期允許在超過正常租約超時的故障恢復間維護會話。

圖2 顯示了一個漫長的故障恢復事件中的事件序列,在這個事件中,客戶端必須使用其寬限期來保存其會話。時間從左到右遞增,但時間不是按比例遞增的。客戶端會話租約以粗箭頭顯示,新舊?Master?(上面的M1-3)和客戶端(下面的C13)都是這樣看的。向上的箭頭表示 KeepAlive 請求,向下的箭頭表示應答。原始的?Master?為客戶端提供了會話租賃M1,而客戶端則有一個保守的近似C1。?Master?承諾在通過 KeepAlive reply 2通知客戶前租賃 M2;客戶端能夠擴展其對租約 C2 的視圖。原?Master?在應答下一個 KeepAlive 之前死掉了,過了一段時間后另一個?Master?被選出。最終客戶端的近似租約(C2)到期。然后客戶端刷新它的緩存并為寬限期啟動一個計時器。

在此期間,客戶端無法確定其租約在?Master?處是否已經到期。它不會破壞它的會話,但它會阻止所有應用程序對其 API 的調用,以防止應用程序觀察到不一致的數據。在寬限期開始時,Chubby 庫向應用程序發送一個危險事件,允許它暫停自己,直到確定其會話的狀態。

最終,新的?Master?選舉成功了。?Master?最初使用的是一個保守的近似 M3 的會話租約,它的前身可能已經為客戶端提供了這個租約。從客戶端到新?Master?的第一個 KeepAlive 請求 (4) 被拒絕,因為它的?Master?代數不正確(下面詳細描述)。重試請求 (6) 成功,但通常不會進一步擴展主租約,因為 M3 是保守的。但是,應答 (7) 允許客戶端再次延長其租約 (C3),并可選地通知應用程序其會話不再處于危險中。因為寬限期足夠長,可以覆蓋租賃 C2 結束到租賃 C3 開始的這段時間,客戶端看到的只是延遲。如果寬限期小于這個間隔,客戶端將放棄會話并向應用程序報告失敗。

一旦客戶端聯系了新?Master?,客戶端庫和?Master?就會合作向應用程序提供沒有發生故障的假象。為了實現這一點,新?Master?必須重構前一個?Master?在內存中的狀態的保守近似值(conservative approximation)。這部分是通過讀取磁盤上穩定存儲的數據(通過普通的數據庫復制協議進行復制),部分是通過從客戶端獲取狀態,部分是通過保守的假設(conservative assumptions)實現的。數據庫記錄每個會話、持有的鎖和臨時文件。

新選出的?Master?過程如下:

1. 它首先選擇一個新的代編號(epoch number),客戶端需要在每次調用時顯示它。?Master?拒絕使用舊的 epoch number?的客戶端調用,并提供新的 epoch number。這可以確保新?Master?不會響應發送給前一個?Master?的舊包,即使是在同一臺機器上運行的包。

2. 新?Master?可以響應?Master?位置請求,但不首先處理與會話相關的傳入操作。

3.它為記錄在數據庫中的會話和鎖構建內存中的數據結構。會話租期被擴展到前一個?Master?可能使用的最大限度。

4. ?Master?現在允許客戶端執行 KeepAlives,但不允許執行其他與會話相關的操作。

5. 它向每個會話發出故障恢復事件;這將導致客戶端刷新它們的緩存(因為它們可能錯過了失效),并警告應用程序其他事件可能已經丟失。

6. ?Master?一直等待,直到每個會話確認故障恢復事件或讓其會話過期。

7. ?Master?允許所有操作繼續進行。

8. 如果客戶端使用在故障恢復之前創建的句柄(根據句柄中序列號的值確定),則?Master?將在內存中重新創建句柄的表示,并執行調用。如果重新創建的句柄關閉,主句柄將把它記錄在內存中,這樣就不能在?Master?epoch?中重新創建它;這確保延遲的或重復的網絡包不會意外地重新創建一個關閉的句柄。一個有問題的客戶端能在未來的時間中重建一個已關閉的句柄,但倘若該客戶端已經有問題的話,則這樣不會有什么危害。

9. 在一段時間之后(比如一分鐘),?Master?刪除沒有打開的文件句柄的臨時文件。在故障恢復后的這段時間內,客戶端應該刷新臨時文件的句柄。這種機制有一個不幸的后果,如果文件上的最后一個客戶端在故障恢復間丟失了會話,臨時文件可能不會立即消失。

與系統的其他部分相比,故障恢復代碼的執行頻率要低得多,因此讀者會毫不驚訝地發現,故障恢復代碼是有趣 bug 的豐富來源。

?

2.10 數據庫實現

Chubby?第一版使用帶復制的 Berkeley DB 版本作為它的數據庫。Berkeley DB 提供了?B-tree可以將字節字符串鍵映射到任意的字節字符串值。我們設置了一個按照路徑名稱中的節數排序的鍵比較函數,這樣就允許節點用它們的路徑名作為鍵,同時保證兄弟節點在排序順序中相鄰。因為 Chubby 不使用基于路徑的權限,所以只需在數據庫中進行一次查詢,就可以對每個文件進行訪問。

Berkeley DB 使用分布式一致協議在一組服務器上復制其數據庫日志。一旦?Master?租約被添加,這就與 Chubby 的設計相匹配,使得實現變得簡單。

雖然 Berkeley DB 的 B-tree 代碼使用廣泛且成熟,但是復制代碼是最近添加的,并且用戶較少。維護者必須優先維護和改進他們的最受歡迎的產品特性。雖然 Berkeley DB 的維護者解決了我們遇到的問題,但是我們覺得使用復制代碼會使我們承擔更多的風險。因此,我們使用類似于 Birrell 等人的設計的提前寫日志和快照來編寫一個簡單的數據庫。與前面一樣,數據庫日志使用分布式一致協議在副本之間分布。Chubby 很少使用 Berkeley DB 的特性,所以這次重寫使得整個系統變得非常簡單例如,雖然我們需要原子操作,但是我們不需要通用事務。

?

2.11 備份

每隔幾個小時,每個 Chubby 單元的?Master?就會將其數據庫的快照寫入不同大樓的 GFS 文件服務器。使用獨立的樓宇,既可確保備份不會因樓宇損毀而損毀,又可確保備份不會對系統造成循環依賴同一建筑物中的一個 GFS 單元可能依賴于這個?Chubby?的單元來選舉它的?Master?。備份既提供了災難恢復,也提供了一種方法來初始化新替換副本的數據庫,而無需對服務中的副本施加負載。

?

2.12 鏡像

Chubby 允許將文件集合從一個單元鏡像到另一個單元。鏡像非常快,因為文件很小,而且如果文件被添加、刪除或修改,事件機制會立即通知鏡像處理相關代碼。如果沒有網絡問題,變化會一秒之內便在世界范圍內的很多個鏡像中反映出來。如果無法訪問鏡像,則鏡像將保持不變,直到恢復連接為止。然后通過比較校驗和來識別更新的文件。

鏡像最常用來將配置文件復制到分布在世界各地的各種計算集群。一個名為 global 的特殊單元包含一個子樹 /ls/global/master,該子樹 /ls/cell/slave 被鏡像到其他每個?Chubby?的單元中。global 單元是特殊的,因為它的五個副本位于世界上分布廣泛的地方,所以它幾乎總是可以從從大部分國家/地區訪問。

從 global 單元中鏡像出的文件包括 Chubby 自己的訪問控制列表、各種文件(其中 Chubby 單元和其他系統向我們的監控服務顯示它們的存在)、允許客戶端定位大數據集(如 Bigtable 單元)的指針以及其他系統的許多配置文件。

?

3?擴展機理

Chubby 的客戶端是獨立的進程,因此 Chubby 必須處理比預期更多的客戶端我們已經看到 9 萬名客戶直接與一位?Chubby 服務器交流——遠遠超過所涉及的機器數量。因為每個單元只有一個?Master?,而且它的機器與客戶端的機器完全相同,所以客戶端可以以巨大的優勢壓倒?Master?。因此,最有效的擴展技術減少了與?Master?的通信。假設?Master?沒有嚴重的性能錯誤,那么在?Master?上對請求處理的微小改進幾乎沒有什么效果。我們使用幾種方法

  • 我們可以創建任意數量的?Chubby 單元;客戶端幾乎總是使用附近的計算單元(在 DNS 中找到)來避免依賴于遠程機器。我們的典型部署是使用一個?Chubby?單元作為數千臺機器的數據中心。
  • Master?在高負載的情況下,可以將租賃時間從默認的 12 秒增加到 60 秒左右,因此它需要處理更少的 KeepAlive RPC。( KeepAlives 是目前占主導地位的請求類型(見4.1),未能及時處理它們是服務器超載的典型故障模式客戶端在很大程度上對其他調用的延遲變化不敏感。)
  • Chubby 客戶端緩存文件數據、元數據、缺文件和打開句柄,以減少們在服務器上的調用數量。
  • 我們使用協議轉換服務器,將 Chubby 協議轉換成不太復雜的協議,如 DNS 和其他協議。我們將在下面討論其中的一些。

在這里,我們描述了兩種常見的機制,代理(proxies)和分區(partitioning),我們期望這兩種機制將允許 Chubby 進一步擴展。我們還沒有在生產中使用它們,但它們已經設計出來了,可能很快就會使用。我們目前沒有必要考慮將規模擴大到原來的 5 倍以上首先,希望放入數據中心或依賴于單個服務實例的機器數量是有限制的。其次,因為我們對?Chubby 客戶端和服務器使用類似的機器,所以增加每臺機器的客戶端數量的硬件改進也會增加每臺服務器的容量。

?

3.1 代理

可以通過可信的進程代理 Chubby 的協議(在兩邊使用相同的協議),這些進程將來自其他客戶端的請求傳遞給一個 Chubby 單元。代理可以通過處理 KeepAlive 和 read 請求來減少服務器負載它不能減少通過代理緩存的寫流量。但即使有積極的客戶端緩存,寫入流量仍遠小于 Chubby 正常負載的?1%,因此代理允許客戶端數量的顯著增加。如果一個代理處理 Nproxy?客戶端,那么?KeepAlive 流量將減少?Nproxy 倍而?Nproxy 可能是一萬甚至更大。代理緩存最多可以減少平均讀取共享量的讀取流量(大約是10倍)。但由于目前的閱讀量占了?Chubby 負載的 10% 以下,所以?KeepAlive 流量上的節省仍然是到目前為止更重要的成效

代理將一個額外的?RPC?添加到寫操作和第一次讀操作中。可以預期,代理將使計算單元暫時不可用的頻率至少是以前的兩倍,因為每個代理客戶端都依賴于兩臺可能失的機器它的代理和?Chubby?的?Master?。

提醒讀者注意,2.9節中描述的故障恢復策略對于代理來說并不理想。我們將在第4.4節中討論這個問題。

?

3.2 分區

如第 2.3 節所述,選擇了 Chubby 的接口,以便可以在服務器之間對計算單元的名稱空間進行分區。雖然我們還不需要它,但代碼可以按目錄對名稱空間進行分區。如果啟用,一個?Chubby?的單元將由 N 個分區組成,每個分區有一組副本和一個?Master?。目錄 D 中的每個節點 D/C 將存儲在分區 P(D/C) = hash(D) mod N 上。注意,D 的元數據可能存儲在不同的分區 P(D) = hash(D0) mod N 上,其中 D0 是 D 的父節點。

分區的目的是在分區之間幾乎沒有通信的情況下啟用很大的 Chubby 單元集(Chubby cells)。雖然 Chubby?沒有硬鏈接、目錄修改時間和跨目錄重命名操作,但仍有一些操作需要跨分區通信

  • ACL?本身就是文件,因此一個分區可以使用另一個分區進行權限檢查。但是,ACL 文件很容易被緩存只有 Open() 和 Delete() 調用需要 ACL 檢查大多數客戶端讀取不需要 ACL 的公共可訪問文件。
  • 當一個目錄被刪除時,可能需要一個跨分區調用來確保該目錄是空的。

因為每個分區都獨立于其他分區處理大多數調用,所以我們希望這種通信對性能或可用性的影響不大。

除非分區的數量 N 很大,否則每個客戶端應該會聯系大多數分區。因此,分區將任何給定分區上的讀寫流量減少了 N 倍,但不一定會減少 KeepAlive 流量。如果 Chubby 需要處理更多的客戶端,那么我們的策略涉及代理和分區的組合。

?

4 實際應用,意外和設計錯誤

4.1?實際應用和表現

下表給出了一個?Chubby cell?的快照統計數據;RPC 頻率在 10 分鐘內可見。這些數字在 Google 的 Chubby 單元中是很常見的

可以看到以下幾點:

  • 許多文件用于命名;看到 4.3。
  • 配置、訪問控制和元數據文件(類似于文件系統的超級塊)是常見的。
  • 負面緩存非常重要。
  • 平均 230k/24k≈10 個客戶端使用每個緩存文件。
  • 很少有客戶端持有鎖,共享鎖也很少見;這與鎖用于 Primary?選舉和在副本之間分區數據是一致的。
  • RPC?流量由會話 KeepAlives 控制有一些讀取(即緩存丟失)很少有寫或鎖獲取。

現在,我們簡要地描述一下單元中停機的典型原因。如果我們假設(樂觀地)一個單元是?"向上"?的,如果它有一個?Master?愿意服務,在我們的單元樣本上,我們記錄了在幾周內 61 次停機,總計 700 個?cell-days?的數據。我們排除了由于維護而導致數據中心關閉的停機。其他原因包括網絡擁塞、維護、過載和由于操作員、軟件和硬件引起的錯誤。大多數故障是 15 次或更少,52 次是 30?秒內;我們的大部分應用程序不會被 Chubby 的 30 秒內的不可用顯著地影響到。其余 9 次宕機是由網絡維護(4)、可疑的網絡連接問題(2)、軟件錯誤(2)和過載(1)引起的。

在好幾次?Chubby 單元年(cell-years)的運行中,我們有六次丟失了數據,由數據庫軟件錯誤(4)和運營人員錯誤(2)引起不涉及硬件錯誤。具有諷刺意味的是,操作錯誤與為避免軟件錯誤的升級有關我們有兩次糾正了由非?Master?的副本的軟件引起的損壞

Chubby?的數據適合在內存中,所以大多數操作的代價都很低。無論計算單元負載如何,我們的生產服務器上的平均請求延遲始終保持在1毫秒以內,直到計算單元接近過載,此時延遲顯著增加,會話被丟棄。過載通常發生在許多會(> 90、000)是活躍的時候,但是也能由異常條件引起當客戶端們同時地發起幾百萬讀請求時(在 4.3 節有描述),或者當客戶端庫的一個錯誤禁用了某些讀的緩存,導致每秒成千上萬的請求。因為大多數?RPC?都是 KeepAlives,所以服務器可以通過增加會話租期來維持許多客戶端平均請求延遲。當出現大量寫操作時,組提交(Group commit)會減少每個請求(單獨提交)所做的工作,但這種情況很少見。

在客戶端測量的?RPC?讀延遲受?RPC?系統和網絡的限制它們對于一個本地 Chubby 單元來說小于 1ms,但跨洲則需要 250ms。由于數據庫日志更新,寫操作(包括鎖操作)將進一步延遲 5-10 ms,但是如果最近失的客戶端緩存了該文件,則延遲最多數十秒。這種寫延遲的變化對服務器上的平均請求延遲影響很小,因為寫的頻率非常低。

如果會話沒有被丟棄,客戶端對延遲變化相當不敏感。在某一點上,我們在 Open() 中添加了人為的延遲來抑制濫用的客戶端(參見4.5)開發人員只注意到延遲超過 10 秒并被重復應用。我們發現,擴展 Chubby 的關鍵不是服務器性能減少與服務器的通信可能會產生更大的影響。在優化讀/寫服務器代碼路徑方面沒有付出重大努力我們檢查了沒有異常的 bug 存在,然后關注于更有效的擴展機制。在另一方面,如果一個性能缺陷影響到客戶端會每秒讀幾千次的本地 Chubby 緩存,開發者肯定會注意到。

?

4.2 Java 客戶端

Google?的基礎架構主要是用?C++?編寫的,但是越來越多的系統是用 Java 編寫的。這種趨勢給 Chubby 帶來了一個意想不到的問題,因為它有一個復雜的客戶端協議和一個重要的客戶端庫。Java 鼓勵整個應用程序的可移植性,但卻犧牲了增量采用的代價,因為它使得與其他語言的鏈接有些麻煩。通常用于訪問非原生(non-native)的庫的 Java 機制是 JNI,但是它被認為是緩慢而笨拙的。我們的 Java 程序員非常不喜歡 JNI,為了避免使用它,他們寧愿將大型庫轉換成 Java,并維護它們。

Chubby 的?C++?客戶端庫有 7000 行(與服務器相當),客戶端協議非常復雜。在 Java 中維護這個庫需要細心代價,而沒有緩存的實現會增加 Chubby 服務器的負擔。因此,我們的 Java 用戶運行協議轉換服務器的副本,該服務器導出一個簡單的?RPC?協議,該協議與 Chubby 的客戶端 API 緊密對應。即使事后來看,我們也不清楚如何才能避免編寫、運行和維護這個額外服務器的成本。

?

4.3 用作名稱服務

盡管 Chubby 被設計為一個鎖服務,但我們發現它最流行的用法是作為名稱服務器。

常規的 Internet 命名系統(DNS)中,緩存是基于時間的。DNS 條目有生存時間(TTL),如果在此期間沒有刷新 DNS 數據,則將丟棄這些數據。通常,選擇一個合適的 TTL 值是很簡單的,但是如果需要立即替換失敗的服務,TTL 會變得很小,以至于使 DNS 服務器超載

例如,我們的開發人員經常運行涉及數千個進程的任務,并且每個進程之間相互通信,這導致了二次級的?DNS 查。我們可能希望使用 60 秒的 TTL這將允許行為不端的客戶端被替換,而不會有過多的延遲,并且在我們的環境中不會被認為是一個不合理的短替換時間。在這種情況下,要維護單個任務的 DNS 緩存(最小為3000個客戶端),需要每秒 15 萬個查(相比之下,一個2-CPU? 2.6GHz 的 Xeon DNS 服務器每秒可以處理 5 萬個請求)更大的任務產生更惡劣的問題,并且多個任務可能同時執行。在引入 Chubby 之前,我們的 DNS 負載的波動性是?Google 面臨的一個嚴重問題。

相比之下,Chubby 的緩存使用顯示地失效(invalidations),因此恒定速率的會話 KeepAlive 請求可以在沒有更改的情況下在客戶端上無限期地維護任意數量的緩存條目。一個2-CPU 2.6GHz 的 Xeon Chubby??Master?可以處理與它直接通信的9萬個客戶端(沒有代理)這些客戶端包括了具有上文描述過的那種通訊模式的龐大任務。在不逐個輪詢每個名稱的情況下提供快速名稱更新的功能非常有吸引力,以至于現在 Google 的大部分系統都由 Chubby 提供名字服務

盡管 Chubby 的緩存允許一個單獨的單元能承受大量的客戶端,但負載峰值仍然是一個問題。當我們第一次部署基于 Chubby 的名稱服務時,啟動一個 3000 個進程任務(從而產生 900 萬個請求)可能會讓 Chubby??Master?崩潰。為了解決這個問題,我們選擇將名稱條目分組成批,這樣一次查詢就可以返回并緩存作業中大量相關進程(通常為100個)的名稱映射。

Chubby 提供的緩存語義要比名字服務需要的緩存語義更加精確名稱解析只需要及時通知,而不需要完全一致。因而,這里有一個時機,可以通過引入特別地為名字查找設計的簡單協議轉換服務器,來降低 Chubby 的負載。假如我們預見到將 Chubby 用作名字服務的用法,我們可能選擇實現完整的代理,而不是提供這種簡單但沒有必要的額外的服務器。

還有一個協議轉換服務器:Chubby?的 DNS 服務器。這使得存儲在 Chubby 中的命名數據對 DNS 客戶端可用。這種服務器很重要,它既能減少了 DNS 名字到 Chubby 名字之間的轉換,也能適應已經存在的不能輕易轉換的應用程序,例如瀏覽器。

?

4.4?故障恢復問題

Master?故障恢復的原始設計要求?Master?在創建新會話時向數據庫寫入新會話。在?Berkeley?DB 版本的鎖服務器中,當多個進程同時啟動時,創建會話的開銷就成為了一個問題。為了避免過載,服務器被修改為在數據庫中存儲會話,而不是在第一次創建會話時存儲,而是在嘗試第一次修改、鎖獲取或打開臨時文件時存儲。此外,活動會話被記錄在數據庫中,每個 KeepAlive 都有一定的概率。因此,只讀會話的寫操作在時間上是分散的。

雖然有必要避免過載,但這種優化有一個不好的結果,即比較新的只讀會話可能不會記錄在數據庫中,因此在發生故障恢復時可能會被丟棄。雖然這樣的會話不持有鎖,但這是不安全的如果所有記錄的會話都要在被丟棄會話的租約到期之前與新主會話檢入(check in),那么被丟棄的會話可以在一段時間內讀取過時的數據。這在實踐中很少見在大型系統中,幾乎可以肯定的是某些會話將無法檢入,從而迫使新?Master?等待最大的租約時間。然而,我們修改了故障恢復設計,以避免這種影響,并避免當前方案引入代理的復雜性。

在新的設計中,我們完全避免在數據庫中記錄會話,而是使用與?Master?當前重新創建句柄相同的方式重新創建它們。現在,新?Master?必須等待一個最壞情況下的租約超時,才能允許操作繼續進行,因為它無法知道是否所有會話都已檢入。同樣,這在實踐中幾乎沒有效果,因為可能不是所有會話都將檢入。

一旦可以在沒有磁盤狀態的情況下重新創建會話,代理服務器就可以管理?Master?不知道的會話。僅對代理可用的額外操作允許它們更改與鎖關聯的會話。這允許一個代理在代理失敗時從另一個代理接管客戶端。?Master?所需要的惟一必要的更改是保證不放棄與代理會話關聯的鎖或者臨時文件句柄,直到一個新的代理有機會獲得它們。

?

4.5 濫用的客戶端

Google?的項目團隊可以自由地設置他們自己的?Chubby 單元,但是這樣做會增加他們的維護負擔,并消耗額外的硬件資源。因此,許多服務使用共享的?Chubby 單元,這使得將客戶端與其他人的不當行為隔離開來非常重要。Chubby 打算在一家公司內運行,因此針對它的惡意拒絕服務攻擊很少見。然而,開發人員的錯誤、誤解和不同的期望會導致類似于攻擊的效果。

我們的一些補救措施是嚴厲的。例如,我們檢查項目團隊計劃使用 Chubby 的方式,并在檢查滿意之前拒絕訪問共享的 Chubby 名稱空間。這種方法的一個問題是,開發人員常常無法預測他們的服務在未來將如何使用,以及使用將如何增長。讀者會注意到,我們自己也未能預測到?Chubby?會被如何利用,這是多么諷刺。

我們審查的最重要方面是確定?Chubby 的資源(RPC速率、磁盤空間、文件數量)的使用是否隨用戶數量或項目處理的數據量線性增長(或更糟)。任何線性增長都必須通過一個可調整的補償參數來緩解,以將?Chubby 的負載降低到合理的范圍。然而,我們早期的審查不夠徹底。

一個相關的問題是大部分軟件文檔中缺少性能建議。一個團隊編寫的模塊可能在一年后被另一個團隊重用,從而導致災難性的結果。有時很難向接口設計人員解釋,他們必須更改接口并不是因為接口不好,而是因為其他開發人員可能不太了解?RPC?的成本。

下面我們列出一些我們遇到的問題。最初缺少可應付沖擊的緩存(aggressive caching)?,我們沒有意識到緩存缺少文件的關鍵需求,也沒有意識到重用打開的文件句柄。盡管嘗試過培訓,但我們的開發人員經常編寫循環,當文件不存在時無限重試,或者通過打開文件并在可能只打開文件一次的時候反復關閉它來輪詢文件。

最初,我們對付這些重試循環的方法是,在某個應用程序短時間內做了許多 Open() 同一個文件的嘗試時,引入指數級遞增的延時。在某些情況下,這暴露了開發人員承認的缺陷,但通常這需要我們花費更多的時間在培訓上。最后,很容易使重復的 Open() 調用所花費的代價沒有那么大

Chubby 從未打算用作存儲大量數據的系統,因此它沒有存儲配額。事后看來,這是缺乏經驗的Google?的一個項目編寫了一個模塊來跟蹤數據上傳,在?Chubby 中存儲一些元數據。這樣的上傳很少發生,而且僅限于一小部分人,所以空間是有限的。但是,其他兩個服務開始使用相同的模塊來跟蹤來自更廣泛用戶群的上傳。不可避免的是,這些服務不斷增長,直到?Chubby 的使用達到極限:在每個用戶操作中,一個1.5 mb的文件被全部重寫,服務使用的總體空間超過了所有其他?Chubby 客戶端的空間需求的總和。

我們引入了文件大小限制(256kBytes),并鼓勵服務遷移到更合適的存儲系統。但是,要對忙碌的人們維護的生產系統進行重大的更改是很困難的——大約花了一年的時間才將數據遷移到其他地方。

發布/訂閱?曾有數次將?Chubby 的事件機制作為 Zephyr 式的發布/訂閱系統的嘗試。Chubby 的重量級保證,以及它在維護緩存一致性時使用無效而不是更新的方法,使得它對于除了無意義的發布/訂閱示例之外的所有示例來說都非常緩慢和低效。幸運的是,在重新設計應用程序的成本太大之前,所有這些用途都被捕獲。

?

4.6 經驗教訓

在這里,我們列出了經驗教訓,以及如果有機會,我們可能會做的各種設計更改

開發者極少考慮可用性。 我們發現開發者極少考慮失敗的可能性,并傾向于認為像?Chubby 這樣的服務好像總是可用。例如,我們的開發人員曾經構建了一個系統,該系統使用了數百臺機器,在?Chubby 選出新?Master?時,啟動恢復過程需要幾十分鐘。這將單個故障的后果在時間和受影響的機器數量上都放大了 100 倍。我們希望開發人員為短時間的中斷做好計劃,以便這樣的事件對他們的應用程序影響很小或沒有影響。這是第 2.1 節討論的粗粒度鎖的參數之一。

開發人員也沒有意識到服務啟動與應用程序可用之間的區別。例如,global Chubby 單元幾乎總是處于上升狀態,因為同時處于下降狀態的數據中心很少超過兩個。但是,對于給定的客戶端,其觀察到的可用性通常低于客戶端的局部?Chubby 單元的觀察到的可用性。首先,本地單元不太可能與客戶端分區,其次,雖然本地單元可能經常由于維護而停機,但是相同的維護直接影響客戶端,所以客戶端不會觀察到?Chubby 的不可用性。

我們的 API 選擇也會影響開發人員處理?Chubby 停機的方式。例如,Chubby 提供了一個事件,允許客戶端檢測?Master?故障恢復何時發生。目的是讓客戶端檢查可能的更改,因為其他事件可能已經丟失。不幸的是,許多開發人員選擇在收到這個事件時關閉他們的應用程序,從而大大降低了系統的可用性。我們可以更好地發送冗余的"文件更改"事件,甚至確保在故障恢復間沒有丟失事件。

目前,我們使用三種機制來防止開發人員對?Chubby 的可用性過于樂觀,特別是global cell的可用性。首先,正如前面提到的,我們審查了項目團隊計劃如何使用?Chubby ,并建議他們不要使用那些將其可用性與?Chubby 緊密聯系在一起的技術。

其次,我們現在提供執行一些高級任務的庫,這樣開發人員就可以自動地從中斷中隔離出來。第三,我們使用每次?Chubby 停機的事后分析作為一種方法,不僅可以消除?Chubby 和我們的操作過程中的 bug,而且還可以降低應用程序對?Chubby 可用性的敏感性——這兩種方法都可以提高系統的整體可用性。

可以忽略細粒度鎖定的內容在 2.1 節的末尾,我們概述了一個服務器的設計,客戶端可以運行該服務器來提供細粒度鎖定。到目前為止,我們還不需要編寫這樣的服務器,這可能令人感到驚訝我們的開發人員通常發現,為了優化他們的應用程序,他們必須刪除不必要的通信,這通常意味著找到一種使用粗粒度鎖定的方法。

糟糕的 API 選擇通常會帶來意想不到的影響,我們的 API 發展得很好,但有一個錯誤很明顯。我們取消長時間運行的調用的方法是 Close() 和 Poison()?RPC,它們也會丟棄句柄的服務器狀態。這可以防止獲取鎖的句柄被共享,例如被多個線程共享。我們可以添加一個 Cancel() RPC?來允許更多地共享打開的句柄。

RPC的使用影響傳輸協議KeepAlives用于刷新客戶端的會話租約,也用于將事件和緩存失效從?Master?傳遞給客戶端這個設計有自動的符合預期的效應:一個客戶端不能在沒有應答緩存過期的情況下刷新會話狀態。

這似乎很理想,除了這樣會在傳輸協議的選擇中引入緊張情形以外TCP?的擁塞時回退(back off)策略不關心更高層的超時,例如 Chubby 的租期,因此基于?TCP?的 KeepAlive 在發生高網絡擁塞時導致許多丟失的會話。我們被迫通過 UDP 而不是?TCP?發送 KeepAlive RPC;UDP 沒有擁塞避免機制,因此我們只有當高層的時間界限必須滿足時才使用 UDP 協議。

我們可以使用一個附加的基于?TCP?的 GetEvent() RPC?來擴展協議,它將用于在正常情況下通信事件和失效,使用的方式與 KeepAlives 相同。KeepAlive 回復仍然包含未確認事件的列表,因而事件最終都將被應答。

?

5 與相關工作的比較

Chubby 是基于成熟的理念之上的。Chubby 的緩存設計源于對分布式文件系統的研究。它的會話和緩存標記的行為與 Echo 中的類似會話減少了系統中租約的開銷。在 VMS 中發現了鎖服務的思想,盡管該系統最初使用了允許低延遲交互的專用高速互連的互聯網絡。與緩存模型一樣,Chubby 的 API 也基于文件系統模型,其中包括這樣一個思想,即類似文件系統的名稱空間可方便地存放文件。

Chubby 與 Echo 或 AFS 等分布式文件系統在性能和存儲方面有所不同:客戶端不會讀取、寫入或存儲大量數據,除非數據被緩存,否則它們不會期望高吞吐量甚至低延遲。他們確實期望一致性、可用性和可靠性,但是當性能不那么重要時,這些屬性更容易實現。因為?Chubby 的數據庫很小,我們可以在線存儲它的許多副本(通常是五個副本和少數備份)。我們每天進行多次完全備份,通過數據庫狀態的校驗和,我們每隔幾個小時就相互比較副本。正常的文件系統性能和存儲需求的弱化使我們能夠一個 Chubby ?Master?為成千上萬的客戶端提供服務。我們通過提供一個中心點,許多客戶端在這個中心點共享信息和協同活動,解決了一類我們的系統開發人員面對的問題。

各種文獻描述了大量的文件系統和鎖服務器,所以不可能做一個徹底的比較。所以我們提供細節我們選擇與?Boxwood?的鎖服務器比較,因為它是最近設計的它也旨在在松耦合的環境中運行但其設計在很多方面不同于Chubby,一些設計是有趣的,一些設計是因為系統的差異所決定的

Chubby 在單個服務中實現鎖、可靠的小文件存儲系統以及會話/租賃機制。相反,Boxwood 將它們分為三個鎖服務、Paxos 服務(狀態的可靠存儲庫)和故障檢測服務。Boxwood?系統本身使用這三個組件,但另一個系統可以獨立使用這些構件。我們懷疑這種設計上的差異源于目標受眾的不同。Chubby 的目標受眾和應用程序是多樣化的它的用戶范圍從創建新分布式系統的專家到編寫管理腳本的新手。對于我們的環境,使用熟悉的 API 的大型共享服務似乎很有吸引力。相比之下,Boxwood 提供了一個工具包(至少在我們看來是這樣),它適用于少數更成熟的開發人員,他們從事的項目可能共享代碼,但不需要一起使用。

在許多情況下,Chubby 提供了比?Boxwood?更高級別的接口。例如,Chubby 組合了鎖和文件名空間,而 Boxwood 的鎖名稱是簡單的字節序列。Chubby?客戶端默認緩存文件狀態Boxwood 的 Paxos 服務的客戶端可以通過鎖服務實現緩存,但是很可能會使用 Boxwood 本身提供的緩存。

這兩個系統有明顯不同的默認參數,為不同的期望而選擇每個客戶端每 200 毫秒與每個 Boxwood 故障檢測器聯系一次,超時為1;?Chubby 的默認租賃時間是 12 秒,每隔 7 秒交換一次 KeepAlives。Boxwood 的子組件使用兩個或三個副本來實現可用性,而我們通常每個單元使用五個副本。然而,這些選擇本身并沒有表明深層次的設計差異,而是指出了這些系統中的參數必須如何調整以適應更多的客戶端機器,或者機架與其他項目共享的不確定性。

一個更有趣的區別是引入了?Chubby 的寬限期,這是?Boxwood?所缺乏的。(回憶一下,寬限期允許客戶在長時間的?Master?宕機期間不丟失會話或鎖。Boxwood 的?"寬限期"?相當于?Chubby 的 "會話租賃",是一個不同的概念。)同樣,這種差異是由于對兩個系統的規模和失敗概率的期望不同造成的。雖然?Master?故障恢復很少見,但是丟失的?Chubby 鎖對客戶來說代價是很昂貴的。

最后,這兩個系統中的鎖用于不同的目的。Chubby?的鎖重量更重,需要記序器來保證外部資源的安全,而?Boxwood?鎖重量更輕,主要用于?Boxwood?內部。

?

6 總結

Chubby 是一個分布式鎖服務,用于?Google?的分布式系統中粗粒度的活動同步它被廣泛用作名稱服務和配置信息存儲庫。

它的設計基于一些已經很好地融合在一起的眾所周知的思想:在幾個副本之間為容錯進行分布式協商,一致的客戶端緩存以減少服務器負載,同時保留簡單的語義,及時的更新通知,以及一個熟悉的文件系統接口。我們使用緩存、協議轉換服務器和簡單的負載調整,使它可以擴展到每個?Chubby 實例的數萬個客戶端進程。我們希望通過代理和分區進一步擴展它。

Chubby 已經成為?Google?的主要內部名稱服務它是 MapReduce 等系統常用的對接機制( rendezvous mechanism);存儲系統 GFS 和 Bigtable 使用?Chubby 從冗余副本中選擇一個?Master?;它是一個標準的存儲庫,用于存儲需要高可用性的文件,比如訪問控制列表。

?

7 感謝

許多人對?Chubby 系統做出了貢獻:Sharon Perl 在 Berkeley DB 上編寫了復制層Tushar Chandra 和 Robert Griesemer 編寫了替代 Berkeley DB 的復制數據庫Ramsey Haddad 將 API 連接到?Google?的文件系統接口Dave Presotto、Sean Owen、Doug Zongker 和 Praveen Tamara 分別編寫了?Chubby 的 DNS、Java 和命名協議轉換器,以及完整的?Chubby 的代理Vadim Furman 增加了打開處理和文件缺失的緩存Rob Pike、Sean Quinlan 和 Sanjay Ghemawat給出了寶貴的設計建議許多?Google?開發人員發現了早期的缺陷。

總結

以上是生活随笔為你收集整理的Google Chubby 论文翻译的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久都是精品 | 狠狠干天天操 | 天堂色网 | 午夜精品99 | 免费观看的毛片 | 久久乐视频| 三级av网址 | 色先锋资源网 | 日本www在线观看 | 精品在线免费视频 | 亚洲四虎av | 亚洲乱码av | 免费成人深夜在线观看 | 国产日本精品 | 纯爱无遮挡h肉动漫在线播放 | 欧美性猛交xxxx黑人猛交 | 美女网站全黄 | 98国产视频 | 国产一区二区精彩视频 | 久操操 | 69精品在线观看 | 91网在线看| 91久久人澡人人添人人爽欧美 | 日本高清免费aaaaa大片视频 | 国产永久在线观看 | 欧美一区二区久久久 | 欧美日韩一区二区在线视频 | 免费av在线网| 亚洲视频在线播放免费 | 国产精品久久欧美久久一区 | 免费古装一级淫片潘金莲 | 久草免费资源 | 欧美激情免费观看 | 欧美日韩视频一区二区三区 | 在线观看成人动漫 | 亚洲视频一二三 | 成人毛片一区二区三区 | 天天草比| 啪免费视频 | 99视频精品在线 | 精品裸体舞一区二区三区 | 伊人久久大香线 | 欧美成人不卡视频 | 日韩视频不卡 | 久人人 | 亚洲男人第一天堂 | 色哟哟视频在线 | 色老妹| 日韩欧美一级大片 | 欧美日韩性生活视频 | 欧美精品久久久久久久久老牛影院 | 72种无遮挡啪啪的姿势 | 亚洲视频1 | 99ri国产精品 | 男生把女生困困的视频 | 91精品综合久久久久久 | 日韩av无码中文字幕 | 呦呦色| 日韩中文字幕在线观看 | 午夜激情黄色 | 久久久久久久久久久久久久久久久 | 污污小说在线观看 | 成人免费看片39 | 欧美黑人一级爽快片淫片高清 | 波多野结衣绝顶大高潮 | 蜜臀久久99精品久久久 | 孕期1ⅴ1高h | 欧美透逼视频 | 久久狠狠爱 | 中文字幕网站 | 欧美不卡一二三 | 我不卡一区二区 | 美女打屁股网站 | 亚洲手机视频 | 久艹伊人| 女人被狂躁c到高潮 | 超碰在线进入 | 国产视频一区二区三区四区五区 | 国产亚洲av片在线观看18女人 | 黑人一级 | 波多野av在线 | 韩国电影一区 | 亚洲视频一区在线 | 成人黄色激情 | 黄色成人在线网站 | 成人午夜免费毛片 | 日本黄色三级网站 | 日韩av一区二区在线观看 | 在线观看日韩av电影 | 爱爱短视频 | 毛片免费一区二区三区 | 欧美在线视频第一页 | 黑白配高清国语在线观看 | 黄色综合网站 | 色欲无码人妻久久精品 | 91麻豆视频网站 | 欧美一级性 | 中国肥胖女人真人毛片 | 国产性―交一乱―色―情人 |