etcd簡介及叢集安裝部署使用

莫忘歸 發表於 2021-04-22

1. etcd介紹

1.1 簡介

etcd是一個鍵值儲存倉庫,用於配置共享和服務發現。etcd在使用中可作為一個高可用強一致性的服務發現儲存倉庫。

etcd作為一個高可用鍵值儲存系統,天生就是為叢集化而設計的。由於Raft演算法在做決策時需要多數節點的投票,所以etcd一般部署叢集推薦奇數個節點,推薦的數量為3、5或者7個節點構成一個叢集。

etcd包含以下特點:

  • 簡單:基於HTTP+JSON的API讓你用curl就可以輕鬆使用。
  • 安全:可選SSL客戶認證機制。
  • 快速:每個例項每秒支援2k+次寫操作。
  • 可信:使用Raft演算法充分實現了分散式。
  • 資料持久化:預設資料一更新就進行持久化。

Raft演算法:工程上使用較為廣泛的強一致性、去中心化、高可用的分散式協議。Raft是一個共識演算法(consensus algorithm),所謂共識,就是多個節點對某個事情達成一致的看法,即使是在部分節點故障、網路延時、網路分割的情況下。

1.2 基礎知識

每個 etcd cluster 都是有若干個 member 組成的,每個 member 是一個獨立執行的 etcd 例項,單臺機器上可以執行多個 member。

在正常執行的狀態下,叢集中會有一個 leader,其餘的 member 都是 followers。leader 向 followers 同步日誌,保證資料在各個 member 都有副本。leader 還會定時向所有的 member 傳送心跳報文,如果在規定的時間裡 follower 沒有收到心跳,就會重新進行選舉。

客戶端所有的請求都會先傳送給 leader,leader 向所有的 followers 同步日誌,等收到超過半數的確認後就把該日誌儲存到磁碟,並返回響應客戶端。

每個 etcd 服務有三大主要部分組成:raft 實現、WAL 日誌儲存、資料的儲存和索引。WAL 會在本地磁碟(就是之前提到的 --data-dir)上儲存日誌內容(wal file)和快照(snapshot)。

1.3 etcd的核心元件

image

從 etcd 的架構圖中我們可以看到,etcd 主要分為四個部分。

  • HTTP Server:用於處理使用者傳送的 API 請求以及其它 etcd 節點的同步與心跳資訊請求。
  • Store:用於處理 etcd 支援的各類功能的事務,包括資料索引、節點狀態變更、監控與反饋、事件處理與執行等等,是 etcd 對使用者提供的大多數 API 功能的具體實現。
  • Raft:Raft 強一致性演算法的具體實現,是 etcd 的核心。
  • WAL:Write Ahead Log(預寫式日誌),是 etcd 的資料儲存方式。除了在記憶體中存有所有資料的狀態以及節點的索引以外,etcd 就通過 WAL 進行持久化儲存。WAL 中,所有的資料提交前都會事先記錄日誌。Snapshot 是為了防止資料過多而進行的狀態快照;Entry 表示儲存的具體日誌內容。

通常,一個使用者的請求傳送過來,會經由 HTTP Server 轉發給 Store 進行具體的事務處理,如果涉及到節點的修改,則交給 Raft 模組進行狀態的變更、日誌的記錄,然後再同步給別的 etcd 節點以確認資料提交,最後進行資料的提交,再次同步。

1.4 讀寫資料

為了保證資料的強一致性,etcd叢集中所有的資料流向都是一個方向,從 Leader (主節點)流向 Follower,也就是所有 Follower 的資料必須與 Leader 保持一致,如果不一致會被覆蓋。

簡單點說就是,使用者可以對etcd叢集中的所有節點進行讀寫,讀取非常簡單因為每個節點儲存的資料是強一致的。對於寫入來說,如果寫入請求來自Leader節點即可直接寫入然後Leader節點會把寫入分發給所有Follower;如果寫入請求來自其他Follower節點,那麼寫入請求會給轉發給Leader節點,由Leader節點寫入之後再分發給叢集上的所有其他節點。

1.5 選舉Leader節點

  Raft演算法使用隨機Timer來初始化Leader選舉流程。 假設叢集中有三個節點,每個節點上都執行了Timer(每個Timer的持續時間是隨機的),第一個節點率先完成了Timer,隨後它就會向其他兩個節點傳送成為Leader的請求,其他節點接收到請求後會以投票回應然後第一個節點被選舉為Leader。

Leader 會定時向所有的 member 傳送心跳報文,如果在規定的時間裡 Follower 沒有收到心跳,就會重新進行選舉。

1.6 是否成功寫入

  etcd認為寫入請求被Leader節點處理並分發給了多數節點後,就是一個成功的寫入。如何界定多數節點呢?很簡單,假設總結點數是N,那麼多數節點就是 >= N/2+1

此特性是由於Raft演算法在做決策時需要多數節點的投票,所以etcd一般部署叢集推薦奇數個節點,推薦的數量為3、5或者7個節點構成一個叢集。

2. Linux下載安裝

兩種下載方法:

wget https://github.com/etcd-io/etcd/releases/download/v3.2.32/etcd-v3.2.32-linux-amd64.tar.gz
或
curl -L https://github.com/etcd-io/etcd/releases/download/v3.2.32/etcd-v3.2.32-linux-amd64.tar.gz -o /opt/etcd-v3.2.32-linux-amd64.tar.gz

解壓

tar -zxvf etcd-v3.2.32-linux-amd64.tar.gz
etcd 為服務端執行檔案
etcdctl 為客戶端執行檔案

3. 單機模式啟動

# 啟動
/opt/etcd-v3.2.32-linux-amd64/etcd --data-dir=default.etcd --name default \
		--initial-advertise-peer-urls http://ip:2380 --listen-peer-urls http://ip:2380 \
		--advertise-client-urls http://ip:2379 --listen-client-urls http://ip:2379

etcd啟動後在埠2379上監聽客戶端通訊,在埠2380上監聽服器到服務之間的通訊。

執行命令測試

執行客戶端命令前需要指定使用哪個版本的api
export ETCDCTL_API=3

./etcdctl put mykey "this is a test"
./etcdctl get mykey

4. 指定各叢集成員的方式配置叢集

建立執行檔案

touch etcd-static.sh

在每個etcd節點上,指定叢集成員。

# 指定叢集token
# 如果你所在的網路環境配置了多個etcd叢集,為了避免意外發生,最好使用-initial-cluster-token引數為每個叢集單獨配置一個token認證。這樣就可以確保每個叢集和叢集的成員都擁有獨特的ID。
TOKEN=token-01

CLUSTER_STATE=new
NAME_1=machine-1
NAME_2=machine-2
NAME_3=machine-3
HOST_1=192.168.199.140
HOST_2=192.168.199.141
HOST_3=192.168.199.142
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380

每個節點新增一下各節點對應啟動命令列

THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
/opt/etcd-v3.2.32-linux-amd64/etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
	
THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
/opt/etcd-v3.2.32-linux-amd64/etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
	
THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
/opt/etcd-v3.2.32-linux-amd64/etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

後臺啟動服務:

nohup sh etcd-static.sh &

5. 使用discovery service的方式配置叢集

如果你本地沒有可用的etcd叢集,etcd官網提供了一個可以公網訪問的etcd儲存地址。你可以通過如下命令得到etcd服務的目錄,並把它作為--discovery引數使用。

執行:curl 'https://discovery.etcd.io/new?size=3'
輸出:https://discovery.etcd.io/d343fbdbc42552549ec02c2710cdca2c

執行得到的輸出內容作為-discovery引數使用

同樣的,當你完成了叢集的初始化後,這些資訊就失去了作用。當你需要增加節點時,需要使用etcdctl來進行操作。為了安全,請務必每次啟動新etcd叢集時,都使用新的discovery token進行註冊。

另外,如果你初始化時啟動的節點超過了指定的數量,多餘的節點會自動轉化為Proxy模式的etcd。

建立執行檔案

touch etcd-dynamic.sh

每個節點如下配置

# 指定叢集token
# 如果你所在的網路環境配置了多個etcd叢集,為了避免意外發生,最好使用-initial-cluster-token引數為每個叢集單獨配置一個token認證。這樣就可以確保每個叢集和叢集的成員都擁有獨特的ID。
TOKEN=token-01

CLUSTER_STATE=new
DISCOVERY=https://discovery.etcd.io/d343fbdbc42552549ec02c2710cdca2c

THIS_NAME=節點自己的名稱
THIS_IP=節點自己的host
/opt/etcd-v3.2.32-linux-amd64/etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--discovery ${DISCOVERY} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

後臺啟動服務:

nohup sh etcd-dynamic.sh &

6. 常用引數說明

--name:方便理解的節點名稱,預設為default,在叢集中應該保持唯一,可以使用hostname。

--data-dir:資料儲存的目錄,預設為${name}.etcd。

--snapshot-count:指定有多少事務(transaction)被提交時,觸發擷取快照儲存到磁碟,預設值10000。

--heartbeat-interval:leader 多久傳送一次心跳到 followers。預設值是100ms。

--eletion-timeout:重新投票的超時時間,如果follow在該時間間隔沒有收到心跳包,會觸發重新投票,預設為1000ms。

--listen-peer-urls:和同伴通訊的地址,比如http://ip:2380,如果有多個,使用逗號分隔。需要所有節點都能夠訪問,所以不要使用localhost!

--initial-advertise-peer-urls:該節點同伴監聽地址,這個值會告訴叢集中其他節點。

--listen-client-urls:對外提供服務的地址:比如 http://ip:2379,http://127.0.0.1:2379,客戶端會連線到這裡和etcd互動。

--advertise-client-urls:對外公告的該節點客戶端監聽地址,這個值會告訴叢集中其他節點。

--initial-cluster:叢集中所有節點的資訊,格式為 node1=http://ip1:2380,node2=http://ip2:2380,…。注意:這裡的node1是節點的 --name 指定的名字;後面的 ip1:2380 是 --initial-advertise-peer-urls 指定的值。

--initial-cluster-state:新建叢集的時候,這個值為 new;假如已經存在的叢集,這個值為 existing。

--initial-cluster-token:建立叢集的 token,這個值每個叢集保持唯一。這樣的話,如果你要重新建立叢集,即使配置和之前一樣,也會再次生成新的叢集和節點 uuid;否則會導致多個叢集之間的衝突,造成未知的錯誤。

所有以 --init 開頭的配置都是在 bootstrap 叢集的時候才會用到,後續節點的重啟會被忽略。

7. 叢集模式下客戶端命令列

執行客戶端命令前需要指定使用哪個版本的api

export ETCDCTL_API=3
  • 獲取叢集節點
./etcdctl --endpoints=192.168.199.140:2379,192.168.199.141:2379,192.168.199.142:2379 member list

加上引數:--write-out=table,可以以表的形式輸出
  • 檢視節點狀態
./etcdctl --endpoints=192.168.199.140:2379,192.168.199.141:2379,192.168.199.142:2379 endpoint status --write-out=table
  • 向叢集中設定值
./etcdctl --endpoints=192.168.199.140:2379,192.168.199.141:2379,192.168.199.142:2379 put key "value"
  • 獲取叢集中的值
./etcdctl --endpoints=192.168.199.140:2379,192.168.199.141:2379,192.168.199.142:2379 get key

可以跟引數:--prefix,獲取所有有相同字首的資料
  • 刪除叢集中資料
./etcdctl --endpoints=192.168.199.140:2379,192.168.199.141:2379,192.168.199.142:2379 del key

可以跟引數:--prefix,刪除所有有相同字首的資料

8. etcd-manager安裝

官網下載安裝包安裝

https://etcdmanager.io/