⑴ etcdraft vs kafka
在最新版本的fabric中,現在存在三種共識排序方式——solo、kafka、etcdraft,其中kafka和etcdraft是多機部署模式。受此啟發,對fabric和kafka做一個對比。
ETCD 是用於共享配置和服務發現的分布式,一致性的KV存儲系統。
Kafka 是由[Apache軟體基金會]開發的一個開源流處理平台,是一種高吞吐量的[分布式]發布訂閱消息系統。
etcd和kafka都是分布式的系統,數據在各個節點之間需要保持一致。kafka是藉助zookeeper來實現數據一致性,etcd是使用raft協議來保持數據一致性。下面詳細介紹一下kafka和etcd分別通過什麼方式來保證數據一致的.
2.1.1 首先介紹兩個重要概念
2.1.2 數據同步過程
(1). 主節點接收到數據數據後,會把本地leo+1。
(2). 把數據分發給從節點。
(3). 從節點leo+1。
(4). 從節點執行完成後返回給主節點。
(5). 等ISR列表中的從節點都返回後,主節點執行hw+1。
*對於Leader新寫入的msg,Consumer不能立刻消費,Leader會等待該消息被所有ISR中的replica同步後,更新HW,此時該消息才能被Consumer消費,即Consumer最多隻能消費到HW位置。這樣就保證了如果Leader Broker失效,該消息仍然可以從新選舉的Leader中獲取。對於來自內部Broker的讀取請求,沒有HW的限制。
⑵ 基於 etcd 的 watch
一直在思考下面一個問題,在APIServer集群的情況下,狀態是如何同步的。比如下面一個場景。
Refector1 連接是ApiServer1, Reflector 2連接的是ApiServer2, 當ApiServer1 收到一個update Pod 的請求時, Refelctor1 可以收到,但是這個請求沒有發生在ApiServer2 上,如何讓Reflector 2 也能感知到Pod 的event 呢?
這里的關鍵就是ETCD集群也可以有watch 機制,如果ApiServer1,寫入ETCD,ApiServer2能夠watch ETCD 的event的話,那就可以實現在ApiServer集群內部的Event 同步了。下面是個簡單的例子。
K8S 就是利用這個etcd機制來實現ApiServer 的同步,這對集群功能來說是至關重要的。下面介紹 kubernetes 針對 etcd 的 watch 場景,k8s 在性能優化上面的一些設計, 逐個介紹緩存、定時器、序列化緩存、bookmark 機制、forget 機制、 針對數據的索引與 ringbuffer 等組件的場景以及解決的問題, 希望能幫助到那些對 apiserver 中的 watch 機制實現感興趣的朋友。
k8s 中並沒有將業務的具體處理邏輯耦合在 rest 介面中,rest 介面只負責數據的存儲, 通過控制器模式,分離數據存儲與業務邏輯的耦合,保證 apiserver 業務邏輯的簡潔。
控制器通過 watch 介面來感知對應的資源的數據變更,從而根據資源對象中的期望狀態與當前狀態之間的差異, 來決策業務邏輯的控制,watch 本質上做的事情其實就是將感知到的事件發生給關注該事件的控制器。
這里我們先介紹基於 etcd 實現的基礎的 watch 模塊。
一個數據變更本質上無非就是三種類型:新增、更新和刪除, 其中新增和刪除都比較容易因為都可以通過當前數據獲取,而更新則可能需要獲取之前的數據, 這里其實就是藉助了 etcd 中 revision 和 mvcc 機制來實現,這樣就可以獲取到之前的狀態和更新後的狀態, 並且獲取後續的通知。
事件管道則是負責事件的傳遞,在 watch 的實現中通過兩級管道來實現消息的分發, 首先通過 watch etcd 中的 key 獲取感興趣的事件,並進行數據的解析, 完成從 bytes 到內部事件的轉換並且發送到輸入管道 (incomingEventChan) 中, 然後後台會有線程負責輸入管道中獲取數據,並進行解析發送到輸出管道 (resultChan) 中, 後續會從該管道來進行事件的讀取發送給對應的客戶端。
事件緩沖區是指的如果對應的事件處理程序與當前事件發生的速率不匹配的時候, 則需要一定的 buffer 來暫存因為速率不匹配的事件, 在 go 裡面大家通常使用一個有緩沖的 channel 構建。
到這里基本上就實現了一個基本可用的 watch 服務,通過 etcd 的 watch 介面監聽數據, 然後啟動獨立 goroutine 來進行事件的消費,並且發送到事件管道供其他介面調用。
kubernetes 中所有的數據和系統都基於 etcd 來實現,如何減輕訪問壓力呢, 答案就是緩存,watch 也是這樣,本節我們來看看如何實現 watch 緩存機制的實現, 這里的 cacher 是針對 watch 的。
Reflector 是 client-go 中的一個組件,其通過 listwatch 介面獲取數據存儲在自己內部的 store 中, cacher 中通過該組件對 etcd 進行 watch 操作,避免為每個組件都創建一個 etcd 的 watcher。
watchCache 負責存儲 watch 到的事件,並且將 watch 的事件建立對應的本地索引緩存, 同時在構建 watchCache 還負責將事件的傳遞, 其將 watch 到的事件通過 eventHandler 來傳遞給上層的 Cacher 組件。
cacheWatcher 顧名思義其是就是針對 cache 的一個 watcher(watch.Interface) 實現, 前端的 watchServer 負責從 ResultChan 裡面獲取事件進行轉發。
Cacher 基於 etcd 的 store 結合上面的 watchCache 和 Reflector 共同構建帶緩存的 REST store, 針對普通的增刪改功能其直接轉發給 etcd 的 store 來進行底層的操作,而對於 watch 操作則進行攔截, 構建並返回 cacheWatcher 組件。
看完基礎組件的實現,接著我們看下針對 watch 這個場景 k8s 中還做了那些優化,學習針對類似場景的優化方案。
如果我們有多個 watcher 都 watch 同一個事件,在最終的時候我們都需要進行序列化, cacher 中在分發的時候,如果發現超過指定數量的 watcher, 則會在進行 dispatch 的時候, 為其構建構建一個緩存函數,針對多個 watcher 只會進行一次的序列化。
在上面我們提到過事件緩沖區,但是如果某個 watcher 消費過慢依然會影響事件的分發, 為此 cacher 中通過是否阻塞(是否可以直接將數據寫入到管道中)來將 watcher 分為兩類, 針對不能立即投遞事件的 watcher, 則會在後續進行重試。
針對阻塞的 watcher 在進行重試的時候,會通過 dispatchTimeoutBudget 構建一個定時器來進行超時控制, 那什麼叫 Budget 呢,其實如果在這段時間內,如果重試立馬就成功,則本次剩餘的時間, 在下一次進行定時的時候,則可以使用之前剩餘的余額,但是後台也還有個線程,用於周期性重置。
針對上面的 TimeBudget 如果在給定的時間內依舊無法進行重試成功, 則就會通過 forget 來刪除對應的 watcher, 由此針對消費特別緩慢的 watcher 則可以通過後續的重試來重新建立 watch, 從而減小對 a piserver 的 watch 壓力。
bookmark 機制是大阿里提供的一種優化方案,其核心是為了避免單個某個資源一直沒有對應的事件, 此時對應的 informer 的 revision 會落後集群很大, bookmark 通過構建一種 BookMark 類型的事件來進行 revision 的傳遞, 從而讓 informer 在重啟後不至於落後特別多。
watchCache 中通過 store 來構建了對應的索引緩存,但是在 listwatch 操作的時候, 則通常需要獲取某個 revision 後的所有數據, 針對這類數據 watchCache 中則構建了一個 ringbuffer 來進行歷史數據的緩存。
⑶ 京東hotkey源碼解析
京東hotkey是一個經過京東大促驗證的hotkey防禦中間件,大概原理是通過上報key訪問數到統計伺服器集群,統計伺服器集群將hotkey通知到客戶端,讓hotkey能緩存到本地內存中,做到毫秒級的Scale-Out。處理方式有點像美團cat實時收集數據進行統計,只不過美團cat沒有反向通知邏輯而已。非常貼近工作實踐,值得一看。
首先看一下緩存入口Cache的get方法,JdHotKeyStore.getValue是獲取hotkey的方法,並且會進行訪問次數的統計上報,如果獲取到hotkey不為空,則直接返回,否則從redis獲取並調用JdHotKeyStore.smartSet判斷是否有hotkey,有則設置值,最後返回。
JdHotKeyStore.getValue會先調用inRule校驗此key是否有對應規則,如果沒有對應規則則不處理,然後調用getValueSimple從本地內存中獲取hotkey的存儲對象ValueModel,如果沒有獲取到,則調用HotKeyPusher.push開始計數;如果獲取到,會調用isNearExpire判斷是否快過期了,如果是也計數,然後取出ValueModel里的value是否有設置對應值,有才返回。最後調用KeyHandlerFactory.getCounter().collect進行對應規則的計數。下面來一步步分析此流程。
inRule會去KeyRule緩存中獲取對應的規則,經過層層調用會到KeyRuleHolder的findByKey方法,然後繼續調用其findRule方法選擇對應的KeyRule,如果沒有KeyRule就直接返回了,否則會拿到它的ration(hotkey緩存時間),拿到對應ration的本地緩存。實際上這里為了方法的通用性,用了get來代替contain的判斷。
findRule的邏輯比較特別,作者已經留下了注釋,優先全匹配->prefix匹配-> * 通配,這樣做是為了更精確選擇對應的規則。比如配置了sku_的前綴規則,但是茅台sku的流量突升,需要針對茅台sku的本地緩存再長一點時間讓系統平穩渡過高峰期,那就配置一個sku_moutai_sku_id的全匹配規則,這樣不會干擾到其他sku的緩存規則。
那麼KEY_RULES的規則是怎麼來的呢?這就要說到etcd了,其實可以把etcd當做zookeeper,也有對配置crud,然後通知客戶端的功能。這里是做了定時拉取+監聽變化的雙重保證,這里跟攜程apollo的處理非常像:不要把雞蛋放在一個籃子,兜底功能真的很重要。每5秒定時從etcd拉取規則,開啟監聽器有變化就去etcd拉取規則。fetchRuleFromEtcd從ectd的rule_path獲取rules,然後轉化成ruleList繼續調用notifyRuleChange進行本地處理。
notifyRuleChange會往EventBus發送KeyRuleInfoChangeEvent的通知,進而進入KeyRuleHolder的putRules方法,這里可以看到維護了KEY_RULES和RULE_CACHE_MAP。
回到原有流程,getValueSimple方法的鏈路比較長,主要是通過key的規則,獲取到對應的ration,然後從對應ration的本地緩存中獲取ValueModel。
接下來是HotKeyPusher.push,如果是remove則在etcd創建一個節點然後再刪除,達到集群刪除的效果。如果是探測並且key在規則內,則調用KeyHandlerFactory.getCollector().collect進行統計。
KeyHandlerFactory.getCollector().collect方法交替使用兩個map,對count進行累加,這樣清理map的時候就不需要停頓了,交替使用是避免停頓的有效方式。
接回上文,還有一個 KeyHandlerFactory.getCounter().collect收集的是規則的訪問次數,也是取到對應的規則,然後對規則的訪問總數、熱次數進行累加。
兩個指標的收集已經分析完畢,那怎麼發送到worker呢?來到PushSchelerStarter,這里會啟動對兩個指標的定時線程池,分別會定時調用NettyKeyPusher的send和sendCount方法。
NettyKeyPusher的send和sendCount方法都是為統計數據選擇對應的worker然後進行請求,chooseChannel就是根據key哈希到其中一個worker上,然後發送請求即可。
最後當worker統計到hotkey時,client需要接收worker推送過來的hotkey進行存儲,可以看到NettyClientHandler會向EventBus發送ReceiveNewKeyEvent事件,ReceiveNewKeyListener收到此事件後將調用receiveNewKeyListener.newKey,將hotkey放到本地緩存,client端的處理流程就結束了。
由上文可知,client與worker的交互只有推送統計數據到worker,worker接收處理,最後推送hotkey到client。因此worker端只需要分析兩個部分:統計數據匯總、推送hotkey。
首先看到HotKey的處理邏輯是在HotKeyFilter中,首先會對totalReceiveKeyCount進行累加,然後調用publishMsg,如果統計信息超時1秒或者在白名單中就不處理,否則繼續調用keyProcer.push。
keyProcer.push將未過時的統計信息丟進queue中。
worker端會開啟指定數量的KeyConsumer,不斷消費queue中的統計數據。根據統計數據的類型調用KeyListener的removeKey和newKey。
KeyListener的removeKey和newKey方法對Cache中的滑動窗口SlidingWindow進行刪除或者累加,刪除或者達到一定訪問數就會推送到根據appname選出所有client進行推送。
京東的hotkey處理是通過計數來動態判斷是否為hotkey,然後緩存再本地內存中,做到毫秒級的scale out。那還有沒有其他解決方案?下面是我的觀點:
1.如果面對一些緩存key很少的場景,比如活動頁信息(同時進行的活動頁不可能超過1000),完全就可以直接將緩存放在本地內存中,到了刷新時間就從redis拉取最新緩存即可,不需要動態計算hotkey。也就是常見的多級緩存。
2.同樣是動態判斷hotkey,但會將hotkey遷移到專門的、更多節點、更高性能的hotkey redis集群中,集群中每個節點都有同一個hotkey緩存,這樣就可以做到請求的分散,避免流量都流向同一個redis節點,判斷是hotkey就去hotkey集群中取,不需要存在本地內存中了,維護起來會比較簡單。
⑷ 租約:如何檢測你的客戶端存活
Leader選舉本質是要解決什麼問題?
Lease是基於主動型上報模式,提供的一種活性檢測機制。
etcd在啟動的時候,創建Lessor模塊的時候,它會啟動兩個常駐goroutine,一個是RevokeExpiredLeade任務,定時檢查是否有過期Lease,
發起撤銷過期的Lease操作。一個是CheckpointScheledLease,定時觸發更新Lease的剩餘到期時間的操作。
Lease模塊提供Grant、Revoke、LeaseTimeToLive、LeaseKeepAlive API 給客戶端:
Lease Server收到請求之後,完成Raft模塊完成同步,Apply模塊通過Lessor模塊的Grant介面執行日誌內容。
Lessor 的Grant介面會把Lease保存到內存的ItemMap數據結構中,然後持久化Lease保存到boltdb的Lease bucket,
返回一個唯一的LeaseID的client。
etcd重啟後,如何知道每個Lease上關聯了那些Key?
etcd的MVCC模塊在持久化存儲key-value的時候,保存到boltdb的value是個結構體(mvccpb.KeyValue),重啟的時候,
重建關聯各個Lease的key集合列表。
Lease續期是將Lease的過期時間更新為當前系統時間加其TTL。關鍵問題在於續期的性能能否滿足業務訴求。
etcd v3 做了調整:
淘汰過期Lease的工作由Lessor模塊的一個非同步goroutine模塊,定期從最小堆中取出已過期的Lease,執行刪除Lease 和
其關聯的key列表數據的RevokeExpiredLease任務。
etcd Lessor主循環每隔500ms執行一次撤銷Lease檢查(RevokeExpiredLease),每次輪詢堆頂的元素,若過期則加入到待
淘汰列表,直到堆頂的Lease過期時間大於當前,則結束本輪輪詢。
Leader如何通知其他Follower節點他們?
Leasor模塊將已經確定過期的LeaseID,保存在一個名為expiredC的channel中,而etcd server的主循環定期channel中獲取
LeaseID,發起revoke請求,通過Raft Log傳遞給Follower節點。各個節點收到Revoke Lease請求後,獲取關聯到此Lease上的
Key列表,從boltdb刪除key,從Leasor的Lease Map內存中刪除此Lease對象,最後還需要從boltdb的Lease bucket刪除這個Lease。
集群Leader發生切換後,新的Leader基於Lease Map消息,按Lease過期時間構建一個最小堆的,etcd早期在重建的時候會自動給所有
Lease續期。如果Leader切換太頻繁,切換時間小於Lease的TTL,會導致Lease永遠無法刪除,大量key堆積,db大小超過配額等。
etcd啟動的時候,Leader節點後台會運行此非同步任務,定期批量地將Lease剩餘的TTL基於Raft Log同步給Follower節點,Follower節點
收到CheckPoint請求後,更新內存數據結構LeaseMap的剩餘TTL信息。
當Leader節點收到KeepAlive請求的時候,它會通過checkpoint機制把此Lease的剩餘TTL重置,並同步Follower節點,盡量確保續期後
集群各個節點的Lease剩餘TTL一致性。
如果不想使用CheckPoint功能,可以通過experimental-enable-lease-checkpoint參數開關。
⑸ 生產etcd伺服器掉電故障修復
客戶現場集群異常掉電,我們於中午進行遠程恢復集群。啟動etcd服務時。出現如下錯誤
查看資料說是:
One of the member was bootstrapped via discovery service. You must remove the previous data-dir to clean up the member information. Or the member will ignore the new configuration and start with the old configuration. That is why you see the mismatch.
大概意思:
其中一個成員是通過discovery service引導的。必須刪除以前的數據目錄來清理成員信息。否則成員將忽略新配置,使用舊配置。這就是為什麼你看到了不匹配。
看到了這里,問題所在也就很明確了,啟動失敗的原因在於data-dir (/var/lib/etcd/default.etcd)中記錄的信息與 etcd啟動的選項所標識的信息不太匹配造成的。
解決方案:將該節點的etcd從集群中移除,並刪除相關數據(後面可同步恢復)。再重新加入etcd集群。
1.查看現有etcd節點
2.將報錯節點移除
3.修改/usr/lib/systemd/system/etcd.service
4.刪除數據
5.重新將etcd節點進行添加
6.啟動etcd,重新加入的節點會向前兩個節點重新同步數據
⑹ RPC 框架使用 Etcd 作為注冊中心
對 etcd 來說,鍵值對( key-value pair )是最小可操作單元,每個鍵值對都有許多欄位,以 protobuf 格式定義。
除了鍵和值之外, etcd 還將附加的修訂元數據作為鍵消息的一部分 。該修訂信息按創建和修改的時間對鍵進行排序,這對於管理分布式同步的並發性非常有用。etcd客戶端的分布式共享鎖使用創建修改來等待鎖定所有權。類似地,修改修訂用於檢測軟體事務內存讀集沖突並等待領導人選舉更新。
申請租約
授權租約
撤銷
租約續約
⑺ etcd是什麼東西它和ZooKeeper有什麼區別
etcd是一個高可用的鍵值存儲系統,主要用於共享配置和服務發現。etcd是由CoreOS開發並維護的,靈感來自於 ZooKeeper 和 Doozer,它使用Go語言編寫,並通過Raft一致性演算法處理日誌復制以保證強一致性。Raft是一個來自Stanford的新的一致性演算法,適用於分布式系統的日誌復制,Raft通過選舉的方式來實現一致性,在Raft中,任何一個節點都可能成為Leader。Google的容器集群管理系統Kubernetes、開源PaaS平台Cloud Foundry和CoreOS的Fleet都廣泛使用了etcd。
etcd 集群的工作原理基於 raft 共識演算法 (The Raft Consensus Algorithm)。etcd 在 0.5.0 版本中重新實現了 raft 演算法,而非像之前那樣依賴於第三方庫 go-raft 。raft 共識演算法的優點在於可以在高效的解決分布式系統中各個節點日誌內容一致性問題的同時,也使得集群具備一定的容錯能力。即使集群中出現部分節點故障、網路故障等問題,仍可保證其餘大多數節點正確的步進。甚至當更多的節點(一般來說超過集群節點總數的一半)出現故障而導致集群不可用時,依然可以保證節點中的數據不會出現錯誤的結果。
⑻ etcd的應用場景
提到etcd很多人第一反應就是一個鍵值存儲倉庫。不過etcd官方文檔的定義卻是這樣的:
etcd作為一個受到ZooKeeper與doozer啟發而催生的項目,除了擁有與之類似的功能外,更專注於以下四點。
接下來將針對剖析一些etcd的經典使用場景,來看看etcd這個基於Raft強一致性演算法的分布式存儲倉庫能給我們帶來哪些幫助。
在分布式系統中「服務發現」也是比較常見的問題:在同一個集群環境中不同的應用或服務,如何能夠找到對方並建立連接,來完成後續的行為。本質上來說,服務發現就是想要知道集群中是否有進程在監聽udp或tcp埠,並能通過名字就可以查找和連接。而要解決服務發現的問題,需要滿足如下三個方面,缺一不可。
來看服務發現對應的具體場景:
在分布式系統中,最適用的一種組件間通信方式就是消息發布與訂閱。即構建一個配置共享中心,數據提供者在這個配置中心發布消息,而消息使用者則訂閱他們關心的主題,一旦主題有消息發布,就會實時通知訂閱者。通過這種方式可以做到分布式系統配置的集中式管理與動態更新。
在場景一中也提到了負載均衡,本文所指的負載均衡均為軟負載均衡。分布式系統中,為了保證服務的高可用以及數據的一致性,通常都會把數據和服務部署多份,以此達到對等服務,即使其中的某一個服務失效了,也不影響使用。由此帶來的壞處是數據寫入性能下降,而好處則是數據訪問時的負載均衡。因為每個對等服務節點上都存有完整的數據,所以用戶的訪問流量就可以分流到不同的機器上。
這里說到的分布式通知與協調,與消息發布和訂閱有些相似。都用到了etcd中的Watcher機制,通過注冊與非同步通知機制,實現分布式環境下不同系統之間的通知與協調,從而對數據變更做到實時處理。實現方式通常是這樣:不同系統都在etcd上對同一個目錄進行注冊,同時設置Watcher觀測該目錄的變化(如果對子目錄的變化也有需要,可以設置遞歸模式),當某個系統更新了etcd的目錄,那麼設置了Watcher的系統就會收到通知,並作出相應處理。
因為etcd使用Raft演算法保持了數據的強一致性,某次操作存儲到集群中的值必然是全局一致的,所以很容易實現分布式鎖。鎖服務有兩種使用方式,一是保持獨占,二是控制時序。
分布式隊列的常規用法與場景五中所描述的分布式鎖的控制時序用法類似,即創建一個先進先出的隊列,保證順序。
另一種比較有意思的實現是在保證隊列達到某個條件時再統一按順序執行。這種方法的實現可以在/queue這個目錄中另外建立一個/queue/condition節點。
通過etcd來進行監控實現起來非常簡單並且實時性強。
這樣就可以第一時間檢測到各節點的健康狀態,以完成集群的監控要求。
另外,使用分布式鎖,可以完成Leader競選。這種場景通常是一些長時間CPU計算或者使用IO操作的機器,只需要競選出的Leader計算或處理一次,就可以把結果復制給其他的Follower。從而避免重復勞動,節省計算資源。
這個的經典場景是搜索系統中建立全量索引。如果每個機器都進行一遍索引的建立,不但耗時而且建立索引的一致性不能保證。通過在etcd的CAS機制同時創建一個節點,創建成功的機器作為Leader,進行索引計算,然後把計算結果分發到其它節點。
etcd實現的這些功能,ZooKeeper都能實現。那麼為什麼要用etcd而非直接使用ZooKeeper呢?
相較之下,ZooKeeper有如下缺點:
而etcd作為一個後起之秀,其優點也很明顯。
最後,etcd作為一個年輕的項目,真正告訴迭代和開發中,這既是一個優點,也是一個缺點。優點是它的未來具有無限的可能性,缺點是無法得到大項目長時間使用的檢驗。然而,目前CoreOS、Kubernetes和CloudFoundry等知名項目均在生產環境中使用了etcd,所以總的來說,etcd值得你去嘗試。
從etcd的架構圖中我們可以看到,etcd主要分為四個部分。
通常,一個用戶的請求發送過來,會經由HTTP Server轉發給Store進行具體的事務處理,如果涉及到節點的修改,則交給Raft模塊進行狀態的變更、日誌的記錄,然後再同步給別的etcd節點以確認數據提交,最後進行數據的提交,再次同步。
⑼ k8s etcd 與持久化存儲
1、是什麼
2、etcd架構及工作原理
(1) 數據流程
一個用戶的請求發送過來,會經過HTTP Server轉發給store進行具體事務處理,如果涉及到節點的修改,則需要交給raft模塊進行狀態的變更,日誌的記錄,然後再同步給別的etcd節點確認數據提交,最後進行數據提交,再次同步
(2)工作原理
Etcd使用 Raft協議 來維護集群內各個節點狀態的 一致性 。簡單說,ETCD集群是一個分布式系統,由多個節點相互通信構成整體對外服務, 每個節點都存儲了完整的數據 ,並且通過Raft協議保證每個節點維護的數據是一致的
(3) 主要組成部分
(4)etcd集群中的術語
3、k8s中的etcd
(1)etcd在k8s中的作用: etcd在kubernetes集群是用來存放數據並通知變動的
(2)為什麼k8s選擇etcd:
PV 目前支持的類型包括:gcePersistentDisk 、AWSElasticBlockStore 、AzureFile 、AzureDisk 、FC ( Fibre Channel ) 、Flocker、NFS 、iSCSI 、RBD (Rados Block Device )、CephFS 、Cinder、GlusterFS 、V sphere Volume 、Quobyte Volumes 、VMware Photon 、Portwonc
Volumes 、ScaleIO Volumes 和HostPath (僅供單機測試)。
如果某個Pod 想申請某種類型的PY ,則首先需要定義一個PersistentVolurneClaim ( PVC )對象,然後,在Pod 的Volume 定義中引用上述PVC 即可:
⑽ ETCD——基礎原理
一個ETCD集群一般由3個或者5個節點組成,兩個quorum一定存在交集,則
即:3個節點容忍1個節點故障,5個節點容忍2個節點故障,以此類推。
首先,所有的數據都保存在B+樹(灰色),當我們指定了版本信息之後,會直接到灰色B+樹中去獲取相關的數據;同時,還有另外一個B+樹,它維護了key和revions的映射關系,查詢key的數據時候,會根據key查詢到revision,再通過revision查詢到相應的key。
etcd 使用 raft 協議來維護集群內各個節點狀態的一致性。簡單說,etcd 集群是一個分布式系統,由多個節點相互通信構成整體對外服務,每個節點都存儲了完整的數據,並且通過 Raft 協議保證每個節點維護的數據是一致的。
每個 etcd 節點都維護了一個狀態機,並且,任意時刻至多存在一個有效的主節點。主節點處理所有來自客戶端寫操作,通過 Raft 協議保證寫操作對狀態機的改動會可靠的同步到其他節點。
etcd 的設計目標是用來存放非頻繁更新的數據,提供可靠的 Watch插件,它暴露了鍵值對的歷史版本,以支持低成本的快照、監控歷史事件。這些設計目標要求它使用一個持久化的、多版本的、支持並發的數據數據模型。
當 etcd 鍵值對的新版本保存後,先前的版本依然存在。從效果上來說,鍵值對是不可變的,etcd 不會對其進行 in-place 的更新操作,而總是生成一個新的數據結構。為了防止歷史版本無限增加,etcd 的存儲支持壓縮(Compact)以及刪除老舊版本。
邏輯視圖
從邏輯角度看,etcd 的存儲是一個扁平的二進制鍵空間,鍵空間有一個針對鍵(位元組字元串)的詞典序索引,因此范圍查詢的成本較低。
鍵空間維護了多個修訂版本(Revisions),每一個原子變動操作(一個事務可由多個子操作組成)都會產生一個新的修訂版本。在集群的整個生命周期中,修訂版都是單調遞增的。修訂版同樣支持索引,因此基於修訂版的范圍掃描也是高效的。壓縮操作需要指定一個修訂版本號,小於它的修訂版會被移除。
一個鍵的一次生命周期(從創建到刪除)叫做 「代 (Generation)」,每個鍵可以有多個代。創建一個鍵時會增加鍵的版本(version),如果在當前修訂版中鍵不存在則版本設置為1。刪除一個鍵會創建一個墓碑(Tombstone),將版本設置為0,結束當前代。每次對鍵的值進行修改都會增加其版本號 — 在同一代中版本號是單調遞增的。
當壓縮時,任何在壓縮修訂版之前結束的代,都會被移除。值在修訂版之前的修改記錄(僅僅保留最後一個)都會被移除。
物理視圖
etcd 將數據存放在一個持久化的 B+ 樹中,處於效率的考慮,每個修訂版僅僅存儲相對前一個修訂版的數據狀態變化(Delta)。單個修訂版中可能包含了 B+ 樹中的多個鍵。
鍵值對的鍵,是三元組(major,sub,type)
鍵值對的值,包含從上一個修訂版的 Delta。B+ 樹 —— 鍵的詞法位元組序排列,基於修訂版的范圍掃描速度快,可以方便的從一個修改版到另外一個的值變更情況查找。
etcd 同時在內存中維護了一個 B 樹索引,用於加速針對鍵的范圍掃描。索引的鍵是物理存儲的鍵面向用戶的映射,索引的值則是指向 B+ 樹修該點的指針。
元數據存儲——Kubernetes
Service Discovery(Name Service)
Distributed Coordination: Leader Election