k8s集群使用etcd作為它的數據后端,etcd是一種無狀態的分布式數據存儲集群. 數據以key-value的形式存儲在其中. 今天同事針對etcd集群的運作原理做了一個講座,總結一下.
A. etcd 數據的組織形式
etcd的API分為兩種, 分別用export ETCDCTL_API=3和export ETCDCTL_API=2來區分. 兩種API的調用接口不同, 其數據組織形式也不同. API_2下,其key和value都存儲在內存中.
而API_3下,key存儲在內存中,value存儲在硬盤中. 顯然, API_3更有優勢,因為key是相較於value來說要短小的多. 這里我們討論的是更為常用的API_3下的數據組織.
在etcd中,key以B樹的形式存儲在內存中, value以B+樹的形式存儲在硬盤中. 為什么要以B/B+樹的形式來存儲呢? 這涉及到一個所有的數據系統都要面對的問題, 如何花更少的時間
將數據從硬盤中讀取出來. 眾所周知, 計算機的存儲體系里, cache> 內存>>> 磁盤, 也就是說對於etcd來說,訪問一個數據最大的時間消耗在磁盤訪問. 那么就要想方設法降低訪問磁盤的
次數. 這個時候B/B+樹的優勢就體現出來了. 下面詳細分析一下.
B/B+樹模型的源頭是AVL(二叉平衡樹). 對於AVL來說, 它每一個節點只存儲一個數據, 因此對於一個很龐大的AVL樹來說, 訪問一個數據的時間復雜度是log2 n. 這里n是這棵AVL樹
存儲的數據總數. 假設有一個數據總量為1023的AVL, 訪問某個數據最壞的情況下需要訪問10個節點. 由於AVL樹的節點之間不像數元素在內存中連續存儲, 這10次節點訪問操作
很有可能包含多次磁盤訪問. 因此拖慢了訪問速度. 而對於B/B+樹來說, 設計者將每一個節點的大小設置為內存一個分頁的大小(一般是4kb), 而內存的一個分頁的大小又等同於磁盤一個數據塊的大小.因此, B/B+樹相對於AVL來說的優勢在於,它在硬盤中讀取數據時, 單位是4kb的數據塊而不是單個數據. 這樣, 它將數據塊讀取到內存中后再進一步查找,從而大大減少了磁盤I/O的次數. 關於B/B+樹在數據庫系統應用中更為詳細的介紹網上有很多相關資料.不再贅述.至於B樹和B+樹的區別,B+樹只在葉子節點中存儲data, 在非葉子節點中只存儲search_key, B樹在非葉子節點中存儲的就是真正的數據.
B. etcd中如何存儲一個key-value
了解了B/B+樹的概念后, 我們分析一下etcd如何將數據存儲到硬盤中. 首先,etcd中有個概念叫revision, 這個revision可以理解為是一個全局變量. 用戶每次執行一個操作, 例如插入一個
key-pair, 這個revision就會自增1, 可以理解為這個revision就是一個全局的ID,表示已經執行了多少次操作, 每一次操作都有唯一的revision來識別. 對於內存中的B樹來說, 它在進行查找時所使用的search-key是etcd key, 節點中存儲的就是revision信息.而硬盤中存儲的B+樹的search-key就是revision值, 其節點中存儲的是etcd key和etcd value. 通過這樣的組織結構, etcd做到了保存每一個key 的每一個歷史記錄.
至此,我們可以梳理一下etcd查找關鍵字,例如"spe",的過程, 首先etcd根據"spe"去內存中遍歷B樹, 找到這個key所對應的revision, 這里revision是一組數字,包含了"spe"的每一次修改. 從
這一組revision中找到最大的那一個,如果用戶指定了某個revision的話, 那么就取出用戶指定的那個. 然后拿着revision去硬盤中查找B+樹, 依次將節點讀入內存進行查找.直至到達葉子節點,並且最終找到想要的值.