elasticsearch入門系列">elasticsearch入門系列
782
2022-05-29
2.2 etcd架構簡介
etcd在設計的時候重點考慮了如下的四個要素。
1.簡單
支持RESTful風格的HTTP+JSON的API。
從性能角度考慮,etcd v3增加了對gRPC的支持,同時也提供rest gateway進行轉化。
使用Go語言編寫,跨平臺,部署和維護簡單。
使用Raft算法保證強一致性,Raft算法可理解性好。
2.安全
支持TLS客戶端安全認證。
3.性能
單實例支持每秒一千次以上的寫操作(v2),極限寫性能可達10K+Qps(v3)。
4.可靠
使用Raft算法充分保證了分布式系統(tǒng)數(shù)據(jù)的強一致性。etcd集群是一個分布式系統(tǒng),由多個節(jié)點相互通信構成整體的對外服務,每個節(jié)點都存儲了完整的數(shù)據(jù),并且通過Raft協(xié)議保證了每個節(jié)點維護的數(shù)據(jù)都是一致的。Raft協(xié)議的工作原理這里不再贅述,詳見1.4節(jié)即可了解。
簡單地說,etcd可以扮演兩大角色,具體如下。
持久化的鍵值存儲系統(tǒng)。
分布式系統(tǒng)數(shù)據(jù)一致性服務提供者。
在分布式系統(tǒng)中,如何管理節(jié)點間的狀態(tài)一直是一個難題,etcd像是專門為集群環(huán)境的服務發(fā)現(xiàn)和注冊而設計的,它提供了數(shù)據(jù)TTL失效、數(shù)據(jù)改變監(jiān)視、多值、目錄、分布式鎖原子操作等功能,可以方便地跟蹤并管理集群節(jié)點的狀態(tài)。
etcd(server)大體上可以分為網(wǎng)絡層(http(s) server)、Raft模塊、復制狀態(tài)機和存儲模塊。etcd的架構如圖2-1所示。
圖2-1 etcd server模塊組成
網(wǎng)絡層:提供網(wǎng)絡數(shù)據(jù)讀寫功能,監(jiān)聽服務端口,完成集群節(jié)點之間數(shù)據(jù)通信,收發(fā)客戶端數(shù)據(jù)。
Raft模塊:Raft強一致性算法的具體實現(xiàn)。
存儲模塊:涉及KV存儲、WAL文件、Snapshot管理等,用于處理etcd支持的各類功能的事務,包括數(shù)據(jù)索引、節(jié)點狀態(tài)變更、監(jiān)控與反饋、事件處理與執(zhí)行等,是etcd對用戶提供的大多數(shù)API功能的具體實現(xiàn)。
復制狀態(tài)機:這是一個抽象的模塊,狀態(tài)機的數(shù)據(jù)維護在內存中,定期持久化到磁盤,每次寫請求都會持久化到WAL文件,并根據(jù)寫請求的內容修改狀態(tài)機數(shù)據(jù)。除了在內存中存有所有數(shù)據(jù)的狀態(tài)以及節(jié)點的索引之外,etcd還通過WAL進行持久化存儲?;赪AL的存儲系統(tǒng)其特點就是所有的數(shù)據(jù)在提交之前都會事先記錄日志。Snapshot是為了防止數(shù)據(jù)過多而進行的狀態(tài)快照。復制狀態(tài)機的工作原理在這里也不多做贅述,詳見1.2.3節(jié)。
通常,一個用戶的請求發(fā)送過來,會經(jīng)由HTTP(S)Server轉發(fā)給存儲模塊進行具體的事務處理,如果涉及節(jié)點狀態(tài)的更新,則交給Raft模塊進行仲裁和日志的記錄,然后再同步給別的etcd節(jié)點,只有當半數(shù)以上的節(jié)點確認了該節(jié)點狀態(tài)的修改之后,才會進行數(shù)據(jù)的持久化。
各個節(jié)點在任何時候都有可能變成Leader、Follower、Candidate等角色,同時為了減少創(chuàng)建鏈接開銷,etcd節(jié)點在啟動之初就會創(chuàng)建并維持與集群其他節(jié)點之間的鏈接。
etcd集群的各個節(jié)點之間需要通過網(wǎng)絡來傳遞數(shù)據(jù),具體表現(xiàn)為如下幾個方面。
1)Leader向Follower發(fā)送心跳包,F(xiàn)ollower向Leader回復消息。
2)Leader向Follower發(fā)送日志追加信息。
3)Leader向Follower發(fā)送Snapshot數(shù)據(jù)。
4)Candidate節(jié)點發(fā)起選舉,向其他節(jié)點發(fā)起投票請求。
5)Follower將收到的寫操作轉發(fā)給Leader。
因此,etcd集群節(jié)點之間的網(wǎng)絡拓撲是一個任意2個節(jié)點之間均有長鏈接相互連接的網(wǎng)狀結構,如圖2-2所示。
圖2-2 etcd集群拓撲關系
2.2.1 etcd數(shù)據(jù)通道
在etcd的實現(xiàn)中,etcd根據(jù)不同的用途,定義了各種不同的消息類型。這些不同的消息,最終都將通過protocol buffer格式進行編碼。這些消息攜帶的數(shù)據(jù)大小可能不盡相同。例如傳輸Snapshot的數(shù)據(jù)量就比較大,甚至會超過1GB,而Leader到Follower節(jié)點之間的心跳消息可能只有幾十KB。因此,網(wǎng)絡層必須要能夠高效地處理不同數(shù)據(jù)量的消息。etcd在實現(xiàn)中,對這些消息采取了分類處理的方式,它抽象出了2種類型的消息傳輸通道,即Stream類型通道和Pipeline類型通道。這2種消息傳輸通道都使用HTTP傳輸數(shù)據(jù)。打個比方,Stream就像是在點與點之間維護的雙向傳輸帶,消息打包后,放到傳輸帶上,傳給對方,對方將回復消息打包好并放到反向傳輸帶上;而Pipeline就如同擁有N輛汽車,將大消息打包放到汽車上,開到對端,然后再開回來,最多可以同時發(fā)送N個消息。下面將分別闡述這兩種不同類型通道的數(shù)據(jù)流。
1. Stream類型通道
Stream類型通道用于處理數(shù)據(jù)量較少的消息,例如,心跳、日志追加消息等。點到點之間只維護1個HTTP長鏈接,交替向鏈接中寫入數(shù)據(jù)和讀取數(shù)據(jù)。
Stream類型通道是節(jié)點啟動后主動與其他每一個節(jié)點建立鏈接,它通過Channel 與Raft模塊傳遞消息。每一個Stream類型通道關聯(lián)2個go routine(Go語言的協(xié)程),其中一個用于建立HTTP鏈接,并從鏈接上讀取數(shù)據(jù)并解碼成消息,再通過Channel傳給Raft模塊,另外一個通過Go語言的Channel 從Raft模塊中收取消息,然后寫入Stream類型通道。
如果深入研究代碼細節(jié)的話,則是etcd使用Golang的HTTP包實現(xiàn)Stream類型通道,具體過程如下所示。
1)Server端監(jiān)聽端口,并在對應的url上掛載相應的Handler(當前請求到達時,Handler的ServeHTTP方法會被調用)。
2)客戶端發(fā)送HTTP GET請求。
3)調用Server端的Handler的ServeHTTP訪問(框架層傳入http.Response-Writer和http.Request對象),其中http.ResponseWriter對象將作為參數(shù) 傳入Writter-Goroutine,該go routine的主循環(huán)就是將Raft模塊傳出的消息寫入這個responseWriter對象里。http.Request的成員變量Body傳入Reader-Gorouting(就這么稱呼吧)中,該go routine的主循環(huán)就是不斷讀取Body上的數(shù)據(jù),并解碼成消息,然后通過Go語言的Channel傳給Raft模塊。
2. Pipeline類型通道
Pipeline類型通道用于處理數(shù)據(jù)量大的消息,例如,Snapshot。這種類型的消息需要與心跳等消息分開處理,否則會阻塞心跳包的傳輸,進而影響集群的穩(wěn)定性。使用Pipeline類型通道進行通信時,點到點之間不維護HTTP長鏈接,它只通過短鏈接傳輸數(shù)據(jù),用完即關閉。
Pipeline類型通道也可以傳輸小數(shù)據(jù)量的消息,不過,是在當且僅當Stream類型鏈接不可用時,它才會這樣做。
此外,Pipeline類型通道還可用來并行發(fā)出多個消息,它維護著一組go routine,每一個go routine都可向對端發(fā)出POST請求(攜帶數(shù)據(jù)),收到回復后,鏈接關閉。
etcd使用Golang的HTTP包實現(xiàn)Pipeline類型通道的具體過程如下所示。
1)根據(jù)參數(shù)配置,啟動N個go routine。
2)每一個go routine的主循環(huán)都阻塞在消息Channel上,待收到消息之后,通過POST請求發(fā)出數(shù)據(jù),并等待回復。
專屬分布式存儲服務 分布式
版權聲明:本文內容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內刪除侵權內容。