Quota模塊
etcdserver:mvcc:database space exceeded錯誤:
- 默認db配額僅為2G
- etcd v3 是個MVCC數據庫,保存了key的歷史版本
etcd server收到put/txn等寫請求的時候,會首先檢查當前etcd db大小加上請求的key-value大小只是否超過了配額二鳄。
如果超過配額,會產生一個告警請求,告警類型為NO SPACE,并通過Raft日志同步給其他節(jié)點,告知db無空間,并將告警持久化
到db中瞭吃。
etcd設置建議配額不超過8G拆火。APPLY模塊在執(zhí)行每個命令的時候,都會去檢查當前是否存在NO SPACE告警,如果有則拒絕寫入昙啄。
在調大配額之后,需要發(fā)送一個取消告警的命令,以消除所有告警迫卢。
檢查etcd的壓縮是否開啟、配置是否合理停局。在配置etcd db配額,就不要設置小于0的,這樣是禁用配額功能拷邢。
KVServer模塊
Preflight Check
為了保證集群穩(wěn)定性,避免雪崩,任何提交到raft模塊的請求,都會做一些簡單的限速判斷。
- 如果Raft模塊以提交的日志索引比已應用到狀態(tài)機的日志索引超過5000,就會返回一個etcdserver: too many requests錯誤給client平斩。
- 如果token無效,返回一個auth:invalid auth token錯誤給client亚享。
- 如果寫入的包大小超過默認的1.5MB,就會返回etcdserver:request is too large的錯誤給client。
Propose
在經過檢查之后,會生成一個唯一的ID,將此請求關聯到一個對應的消息通知channel,然后raft模塊發(fā)起Propose一個提案,向raft模塊發(fā)起的提案后,
KVServer模塊會等待此put請求,等待寫入結果通過消息通知channel返回或者超時绘面。etcd默認超時時間是7秒,如果一個請求超時未返回結果,則可能會出現你熟悉的
WAL模塊
Raft模塊收到提案后,如果當前節(jié)點是Follower,它會轉發(fā)給Leader,只有Leader才能處理寫請求,Leader收到提案后,通過Raft模塊輸出待轉發(fā)給Follower
節(jié)點的消息和待持久化的日志條目欺税。
etcdserver 從Raft模塊獲取到以上消息和日志條目后,作為Leader,它會將put提案消息廣播給集群各個節(jié)點,同時需要把集群Leader任期號、投票信息揭璃、
以提交索引晚凿、提案內容持久化到一個WAL日志文件中,用于保證集群的一致性,可恢復性瘦馍。
WAL記錄是按照順序追加寫入組成,每個記錄由類型(Type)歼秽、數據(Data)、循環(huán)冗余校驗碼(CRC)組成情组。
WAL記錄類型目前支持5種,分別是文件元數據記錄燥筷、日志條目記錄、狀態(tài)信息記錄院崇、CRC記錄肆氓、快照記錄:
- 文件元數據記錄包含節(jié)點ID、集群ID信息,它在WAL文件創(chuàng)建的時候寫入;
- 日志條目記錄包含Raft日志信息,如put提案內容;
- 狀態(tài)信息記錄底瓣,包含集群的任期號谢揪、節(jié)點投票信息等,一個日志文件種會有多條,以最后的記錄為準;
- CRC記錄包含上一個WAL文件最后的CRC信息,用于校驗數據文件的完整性、準確性等;
- 快照記錄包含快照的任期號、日志索引信息,用于檢查快照文件的準確性键耕。
WAL模塊是如何持久化一個put提案的日志條目記錄:
- Raft日志條目的數據結構:Term是Leader任期號,隨著Leader選舉增加;Index是日志條目的索引,單調遞增增加;Type是日志類型;Data是日志數據寺滚。
- 將Raft日志條目內容序列化到WAL記錄的Data字段,然后計算Data的CRC值,設置Type為Entry Type柑营。
- 計算WAL記錄的長度,順序先寫入WAL長度,然后寫入記錄內容,調用fsync持久化到磁盤,完成將日志條目保存到持久化存儲中屈雄。
- 當一半以上節(jié)點持久化此日志條目后,Raft模塊就會通過channel告知etcdserver模塊,put提案已經被集群多數節(jié)點確認,提案狀態(tài)為已提交,
- etcdserver模塊從channel取出提案內容,添加到先進先出調度隊列,隨后通過Apply模塊按入隊順序,異步、一次執(zhí)行提案內容官套。
每個提案被提交前都會被持久化到WAL文件中,以保證集群的一致性和可恢復性酒奶。
Apply模塊
etcd的冪等性是根據Raft日志條目中的索引字段。etcd通過引入consistent index字段,來存儲系統當前已經執(zhí)行過的日志條目索引,實現冪等性奶赔。
Apply模塊基于consistent index和事務實現了冪等性惋嚎。
MVCC
MVCC主要是由兩部分組成,一個是內存索引模塊treeIndex,保存key的歷史版本信息,另一個是boltdb模塊,用來持久化存儲key-value數據。
treeIndex
版本號在etcd里面發(fā)揮著重大作用,它是etcd的邏輯時鐘站刑。etcd啟動的時候默認版本號是1,從最小值1開始枚舉到最大值,未讀到數據的數據則結束,最后讀出來的
版本號即時當前etcd的最大版本號currentRevision另伍。
boltdb
boltdb是一個基于B+tree實現的key-value嵌入式db,通過提供桶機制實現類似于MySQL表的邏輯隔離。
將修改的數據放入到一個名為key的桶里,在啟動etcd時自動創(chuàng)建绞旅。
boltdb value的值是將包含key名稱摆尝、key創(chuàng)建是時版本號、最后一次修改的版本號因悲、修改菜蔬堕汞、value值、租賃信息序列化為二進制數據晃琳。
etcd使用合并再合并解決寫性能差的問題:
- put/delete操作時,都會基于當前版本號遞增生成新的版本號,因此屬于順序寫入,可以遞增boltdb的bucket.FillPercent參數,使每個page填充更多數據,
減少page的分裂次數并降低db空間讯检。- etcd通過多次合并多個寫事物請求,通常情況下,是異步機制定時(默認每隔100ms)將批量事務一次性提交,從而大大提高吞吐量,這樣,讀請求可能無法從
boltdb獲取到最新數據。- etcd bucket buffer來保存暫未提交的事務數據卫旱。在更新boltdb的時候,etcd也會同步數據到bucket buffer人灼。
etcd在執(zhí)行讀請求過程中設置磁盤IO嗎
etcd在啟動時候通過mmap機制將etcd db文件映射到etcd進程地址空間,并設置mmap的MAP_POPULATE flag,它會告訴Linux內核預讀文件,Linux就會將文件內容
拷貝到物理內存中,此時會產生磁盤I/O。節(jié)點在內存足夠的請求下,后續(xù)處理讀請求過程中就不會產生磁盤I/O了顾翼。
如果etcd節(jié)點內存不足時,可能會導致db文件對應的內存頁被換出,當讀請求命中的文件未在內存中時,就會產生缺頁異常,導致讀過程中產生磁盤IO,
可以通過觀察etcd進程
可以通過觀察etcd進程的majflt字段來判斷etcd是否產生了主缺頁中斷投放。