因為微服務架構, 允許服務水平擴展.
在服務發現出現之前, 都是透過讀取靜態配置文件或環境變數, 來獲取服務的位置, 然後連線.
這在產線上出現不少問題:
一套系統之間不同模組或是服務中會有很多配置訊息,
例如: 資料庫位址, 連線的配置資訊
這些如果用靜態配置文件, 每次更新配置時, 會很想死, 要更新很多台
Kubernetes底層就是依賴于etcd實現了集群狀態跟配置的管理.
Vmware Cloud Foundry
etcd用來集群狀態儲存, 配置管理同步, 分散式鎖.
對服務註冊來說, 每一個節點存的註冊訊息, 有稍微不一樣, 其實不會有太大的問題.
所以對服務消費者來說, 它更在意是否註冊中心能夠給予回應.
不外乎就是可能新註冊的對象沒太多人去打, 負載稍微不均衡一小段時間.
或者打了一個失效的節點, 服務消費者自己都會去從可用清單裡retry.
所以比起追求強一致性, 消費者更在意服務是否高度可用.
因此註冊中心, 大部分都選擇A+P.
健康檢查: 服務節點定期向etcd發送心跳更新自己訊息的TTL
服務主動註冊: 同一類型的服務啟動後, 主動註冊到相同服務目錄下
方便透過服務名稱就能查詢到服務提供給外部訪問的IP與Port
服務之間能彼此即時感知, 新增節點、丟棄不可用的服務節點.
服務之間共享同一份配置文件, 並且監聽著, 有更新, 服務立刻感知
可靠的分散式KV儲存, 底層用Raft保證一致性
etcdV3套件使用gRPC跟etcd服務進行溝通; 相較于v2版本的http+json更加輕巧
能夠容忍單點故障, 能夠應付網路分區
分散式鎖
分發任務進度匯報
分散式隊列
etcd底層使用BoltDB作為KV儲存.
內部資料以B+Tree做儲存, 所以如果etcd的服務是用SSD的話, 搜尋效能會快上不少;
且支援事務操作, 也支援ACID.
BoltDB適合讀取密集或者是順序寫入的工作, 對於隨機寫入的工作就沒那麼突出的效能.
若是提交事務時, 有刪除操作, BoldDB會檢查是否需要重新平衡B+Tree的索引.
如果是寫入操作, 就有可能會檢查是否需要拆分樹的節點.
etcd實現了同一個Key的多版本機制; 也就是說同一個Key的每一次更新操作都被單獨紀錄下來了.
etcd把原始的key當成Btree的索引存放在記憶體中, 資料節點放的是"keyIndex"的資料節點.
所以每次etcd啟動時, 都會去BoltDB把所有的資料撈出來放在記憶體中.
先用原始key去找到對應的keyIndex, 再拿這keyIndex取得revision訊息, 再去boldDB去硬碟內找到真正的key以及當時的資料.
// A revision indicates modification of the key-value space.
// The set of changes that share same main revision changes the key-value space atomically.
// main, sub的組成, 加上key就能保證key唯一且遞增
type revision struct {
// main is the main revision of a set of changes that happen atomically.
// 目前的事務操作ID(timestamp), 每次事務操作時, 遞增1
main int64
// sub is the sub revision of a change in a set of changes that happen
// atomically. Each change has different increasing sub revision in that
// set.
// 子ID, 從0開始; 同一個事務內的操作遞增1
sub int64
}
如果一個事務操作是
tx1: 1234567
put keyA value1;
delete keyA
那對應的revision 會是 {1234567, 0}, {1234567,1}
// generation contains multiple revisions of a key.
type generation struct {
ver int64
created revision // when the generation is created (put in first revision).
revs []revision // 每次不斷更新時, 就會追加更新revision訊息
}
因為MVCC(多版本控管), 不可能讓所有版本都追到同一個revs中;
除了不會讓revs長度無限膨脹之外, 所以有generation的概念(分片的概念),
也因為長度有限,便於快速搜尋.
ver從0開始, 0表示第一個版本;
created表示這generation被建立的時間
revs表示該世代所有版本.
// keyIndex stores the revisions of a key in the backend.
// Each keyIndex has at least one key generation.
// Each generation might have several key versions.
// Tombstone on a key appends an tombstone version at the end
// of the current generation and creates a new empty generation.
// Each version of a key has an index pointing to the backend.
// 紀錄了一個key, 從建立到被刪除的過程.
// 每次刪除key的操作, 就會在該generation最後, 添加一個tombstone紀錄; 並且增加一個全新的空generation紀錄到generations內
type keyIndex struct {
key []byte //原始Key值
modified revision // 紀錄最新一次修改對應的revision
generations []generation //紀錄各generation
}
key當前用戶操作的key
modified最新一次修改對應的revision
generations過往修改歷程