iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 11
1
Software Development

服務開發雜談系列 第 11

etcd 基礎認識與使用場景

服務之間的服務註冊與發現

因為微服務架構, 允許服務水平擴展.
在服務發現出現之前, 都是透過讀取靜態配置文件或環境變數, 來獲取服務的位置, 然後連線.
這在產線上出現不少問題:

  1. 某些服務已經不可用
  2. 負載均衡配置複雜, 集中式的負載均衡服務本身可能就是個瓶頸
  3. 無法立即感知新增出來的服務節點

服務的共享設置

一套系統之間不同模組或是服務中會有很多配置訊息,
例如: 資料庫位址, 連線的配置資訊
這些如果用靜態配置文件, 每次更新配置時, 會很想死, 要更新很多台

Kubernetes底層就是依賴于etcd實現了集群狀態跟配置的管理.
Vmware Cloud Foundry
etcd用來集群狀態儲存, 配置管理同步, 分散式鎖.

服務註冊與發現中心該用CAP的那一種組合?

對服務註冊來說, 每一個節點存的註冊訊息, 有稍微不一樣, 其實不會有太大的問題.
所以對服務消費者來說, 它更在意是否註冊中心能夠給予回應.
不外乎就是可能新註冊的對象沒太多人去打, 負載稍微不均衡一小段時間.
或者打了一個失效的節點, 服務消費者自己都會去從可用清單裡retry.
所以比起追求強一致性, 消費者更在意服務是否高度可用.
因此註冊中心, 大部分都選擇A+P.

etcd帶來的好處

  1. 健康檢查: 服務節點定期向etcd發送心跳更新自己訊息的TTL

  2. 服務主動註冊: 同一類型的服務啟動後, 主動註冊到相同服務目錄下

  3. 方便透過服務名稱就能查詢到服務提供給外部訪問的IP與Port

  4. 服務之間能彼此即時感知, 新增節點、丟棄不可用的服務節點.

  5. 服務之間共享同一份配置文件, 並且監聽著, 有更新, 服務立刻感知

  6. 可靠的分散式KV儲存, 底層用Raft保證一致性

  7. etcdV3套件使用gRPC跟etcd服務進行溝通; 相較于v2版本的http+json更加輕巧

  8. 能夠容忍單點故障, 能夠應付網路分區

額外好處

  1. 分散式鎖

  2. 分發任務進度匯報

  3. 分散式隊列

etcd 3大組成

  1. raft
  2. WAL日誌儲存
  3. 資料模型跟索引
    慢慢地研究並分享

etcd資料模型

etcd底層使用BoltDB作為KV儲存.
內部資料以B+Tree做儲存, 所以如果etcd的服務是用SSD的話, 搜尋效能會快上不少;
且支援事務操作, 也支援ACID.
BoltDB適合讀取密集或者是順序寫入的工作, 對於隨機寫入的工作就沒那麼突出的效能.
若是提交事務時, 有刪除操作, BoldDB會檢查是否需要重新平衡B+Tree的索引.
如果是寫入操作, 就有可能會檢查是否需要拆分樹的節點.

索引與多版本(MVCC)控管的實現

etcd實現了同一個Key的多版本機制; 也就是說同一個Key的每一次更新操作都被單獨紀錄下來了.
etcd把原始的key當成Btree的索引存放在記憶體中, 資料節點放的是"keyIndex"的資料節點.
所以每次etcd啟動時, 都會去BoltDB把所有的資料撈出來放在記憶體中.

搜尋流程

先用原始key去找到對應的keyIndex, 再拿這keyIndex取得revision訊息, 再去boldDB去硬碟內找到真正的key以及當時的資料.

內部結構

revision結構

// 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結構

// 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資料結構

// 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過往修改歷程


上一篇
CQRS亂談
下一篇
etcd 叢集基本安裝
系列文
服務開發雜談33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言