【1】etcd介紹
(1.1)etcd簡單介紹
etcd是CoreOS團隊於2013年6月發起的開源項目,它的目標是構建一個高可用的分布式鍵值(key-value)數據庫。
etcd內部采用 raft
協議作為一致性算法,etcd基於Go語言實現。
優點:
- 簡單。 使用Go編寫部署簡單;使用HTTP作為接口使用簡單;使用Raft算法保證強一致性讓用戶易於理解。
- 數據持久化。 etcd默認數據一更新就進行持久化。
- 安全。 etcd支持SSL客戶端安全認證。
核心詞匯:高可用、強一致性、KV數據存儲;
適合存儲少量核心重要數據;
不適合存儲大量數據;
etcd作為服務發現系統,有以下的特點:
- 簡單:安裝配置簡單,而且提供了HTTP API進行交互,使用也很簡單
- 安全:支持SSL證書驗證
- 快速:根據官方提供的benchmark數據,單實例支持每秒2k+讀操作
- 可靠:采用raft算法,實現分布式系統數據的可用性和一致性
(1.2)etcd常見應用場景
1. 服務注冊與服務發現 :為了解決微服務場景下,服務地址的注冊和發現問題。和配置中心功能類似,不同之處在於服務注冊和服務發現,還伴隨着狀態檢測。
用戶可以在etcd中注冊服務,並且對注冊的服務配置key TTL,定時保持服務的心跳以達到監控健康狀態的效果。
2. leader選舉組件 : 分布式場景下,常采用leader-follower模式來保證有狀態服務的高可用(即使leader掛掉,其他follower立馬補上),比如k8s和kafka partition高可用機制。
可以很方便的借助etcd來實現leader選舉機制,這里有個leader election實現:https://github.com/willstudy/leaderelection
3. 配置中心 :etcd是一個分布式的鍵值存儲系統,其優秀的讀寫性能、一致性和可用性的機制,非常適合用來做配置中心角色。
4. 分布式鎖 :etcd的強一致性保證,可以用來做分布式場景下的同步機制保證。
5. 消息訂閱和發布 :etcd內置watch機制,完全可以實現一個小型的消息訂閱和發布組件。
6. more and more :etcd優秀的特性,適合的場景很多。
詳情:
1. 服務發現服務發現(Service Discovery)
要解決的是分布式系統中最常用的問題之一,即在同一個分布式集群中的進程或服務如何才能找到對方並建立連接。
從本質上說,服務發現就是想要了解集群中是否有進程在監聽udp或tcp端口,並且通過名字就可以進行查找和連接。要解決服務發現的問題,需要有三大支柱:
(1)一個強一致性、高可用的服務存儲目錄。基於Raft算法的etcd天生就是這樣一個強一致性高可用的服務存儲目錄。
(2)一種注冊服務和監控服務健康狀態的機制。用戶可以在etcd中注冊服務,並且對注冊的服務設置key TTL,定時保持服務的心跳以達到監控健康狀態的效果
(3)一種查找和連接服務的機制。通過在etcd指定的主題下注冊的服務也能在對應的主題下查找到。
為了確保連接,可以在每個服務器上部署一個proxy模式的etcd,這樣就可以確保能訪問etcd集群的服務都能互相連接。下面我們一起看服務發現對應的具體應用場景。
(1)微服務協同工作架構中,服務動態添加。
多種微服務共同協作,構成一個功能相對強大的架構的案例越來越多。透明化的動態添加這些服務的需求也日益強烈。通過服務發現機制,在etcd中注冊某個服務名字的目錄,在該目錄下存儲可用的服務節點的IP。在使用服務的過程中,只要從服務目錄下查找可用的服務節點進行使用即可。
(2)PaaS平台中應用多實例與實力故障重啟透明化。
PaaS平台中的應用一般都有多個實例,通過域名,不僅可以透明地對多個實例進行訪問,而且還可以實現負載均衡。但是應用的某個實例隨時都有可能故障重啟,這時就需要動態地配置域名解析中的信息。通過etcd的服務發現功能就可以輕松解決這個動態配置的問題。
2. 信息發布與訂閱
在分布式系統中,最為適用的組件見通信方式是消息發布與訂閱機制。具體而言,即構建一個配置共享中心,數據提供者在這個配置中心發布信息,而信息使用者則訂閱他們關心的主題,一旦相關主題有信息發布,就會實時通知訂閱者。通過這種方式可以實現分布式系統配置的集中式管理與實時動態更新。
(1)應用中用到的一些信息存放在etcd上進行集中管理。這類場景的使用方式通常是這樣的:應用在啟動的時候主動從etcd獲取一次配置信息,同時,在etcd節點上注冊一個watcher並等待,以后每次配置有更新的時候,etcd都會實時通知訂閱者,以此達到獲取最新配置信息的目的。
(2)分布式搜索服務中,索引的源信息和服務器集群的節點狀態信息存放在etcd中,供各個客戶端訂閱使用。使用etcd的key TTL供可以確保機器狀態是實時更新的。
(3)分布式日志收集系統。這個系統的核心工作是收集分布在不同機器上的日志。收集器通常按照應用(或主題)來分配收集任務單元,因此可以在etcd上創建一個以應用(或主題)命名的目錄P,並將這個應用相關的所有機器IP,以子目錄的形式存儲在目錄P下,然后設置一個遞歸的etcd Watcher,遞歸式地監控應用目錄下所有信息的變動。這樣就試下了在機器IP(信息)發生變動時,能夠實時通知收集器調整任務分配。
(4)系統中信息需要動態自動獲取與人工干預修改信息請求內容的情況。通常的解決方案是對外暴露接口,來獲取一些運行時的信息或提交修改的請求,而引入etcd之后,只需要將這些信息存放到指定的etcd目錄中,即可通過HTTP接口直接被外部訪問。
3. 負載均衡
本節的負載均衡指軟負載均衡。在分布式系統中,為了保證服務的高可用以及數據的一致性,通常都會把數據和服務部署多份,以此達到對等服務,即使其中的某一個服務失效了,也不影響使用。這樣的實現雖然會導致一定程度上數據寫入性能的下降,但是卻能實現數據訪問時的負載均衡。因為每個對等服務節點上都存有完整的數據,所以用戶的訪問流量就可以分流到不同的機器上。
(1)etcd本身分布式架構存儲的信息訪問支持負載均衡。etcd集群化以后,每個etcd的核心節點都可以處理用戶的請求。所以,把數據量小但是訪問頻繁的消息數據直接存儲到etcd中也是個不錯的選擇。
(2)利用etcd維護一個負載均衡節點表。etcd可以監控一個集群中多個節點的狀態,當有一個請求發過來后,可以輪詢式地把請求轉發給存活着的多個節點。
4. 分布式通知與協調
與消息發布和訂閱有些相似。兩者都使用了etcd的watcher機制,通過注冊於異步通知截止,實現分布式環境下不同系統之間的通知與協調,從而對數據變更進行實時處理。實現方式通常為:不同系統都在etcd上對同一個目錄進行注冊,同時設置watcher監控該目錄的變化,當某個系統更新了etcd的目錄,那么設置了watcher的系統就會收到通知,並作出相應處理。
(1)通過etcd記性低耦合的心跳檢測。檢測系統和被檢測系統通過etcd上某個目錄關聯而非直接關聯起來,這樣可以大大減少系統的耦合性。
(2)通過etcd完成系統調度。某系統有控制台和推送系統兩部分組成,控制台的職責是控制推送系統進行相應的推送工作。管理人員在控制台做的一些操作,實際上只需要修改etcd上某些目錄節點的狀態,而etcd就會自動把這些變化通知給注冊了watcher的推送客戶端,推送系統再做出相應的推送任務。
(3)通過etcd完成工作匯報。大部分類似的任務分發系統,子任務啟動后,到etcd來注冊一個臨時工作目錄,並且定時將自己的精度進行匯報(將精度寫入到這個臨時目錄),這樣任務管理者就能夠實時知道任務進度。
5. 分布式鎖
因為etcd使用Raft算法保持了數據的強一致性,某次操作存儲到集群中的值必然是全局一致的,所以很容易實現分布式鎖。鎖服務有兩種使用方式,一是保持獨占,二是控制時序。
(1)保持獨占,即所有試圖獲取鎖的用戶最終只有一個可以得到。etcd為此提供了一套實現分布式鎖原子操作CAS的API。通過設置prevExist值,可以保證在多個節點同時創建某個目錄時,只有一個成功,而該用戶即可認為是獲得了鎖。
(2)控制時序,即所有試圖獲取鎖的用戶都會進入等待隊列,獲得鎖的順序是全局唯一的,同時決定了隊列執行順序。etcd為此也提供了一套API。
(1.3)基本使用(增刪查改、事務、版本)
基本操作:
基本使用,put/get/del / watch
事務:會有compares =》 success requests / failure requests 三個判斷步驟(txn 開啟事務,-i 是交互式事務)
同時compares 也可以用 create("key") = "47" key的版本信息,mod(key) key的修改版本
【2】etcd集群架構(體系結構)
(2.1)架構的組件
(1)gPRC Server: 響應接收客戶端連接請求,集群節點之間的通信
(2)wal(預寫式日志):用來保證強一致性;log cache=》收到請求命令信息后(增刪改),操作信息 以append方式記錄日志;
在集群模式,主庫會把日志信息發送到從庫,有一半及以上節點收到並回復主節點確認已收到后,把請求進行提交;(其實就是mysql的半同步形式)
然后再把 log cache 持久化到 log file;
(3)snapshot:快照數據,與redis差別不大,用來主從復制中的主從初始化;
(4)boltdb:
key的存儲:每個key就是一個索引,用b+樹結構,因為它會存儲key每一次操作的歷史操作(get key -w josn 顯示版本信息,get key --rev=47 獲取key的歷史版本值)
事務:會有compares =》 success requests / failure requests 三個判斷步驟(txn 開啟事務,-i 是交互式事務)
同時compares 也可以用 create("key") = "47" key的版本信息,mod(key) key的修改版本
(2.2)一個請求的處理過程
1》client: 發起請求到 gRPC Server
2》gRPC Server:接受連接請求,然后把請求命令信息發到主庫的 wal 日志文件
3》wal:把請求命令信息廣播同步到從庫,有一半及以上從庫收到且落盤到wal文件后,返回同意確認標識給主庫
4》主庫對命令請求進行提交落盤,然后再次廣播給從庫讓從庫也提交落盤
5》返回給客戶端
(2.3)集群節點的狀態
《1》followers:從節點 《2》candidate:候選者 《3》leader:主節點
leader election:當主庫無響應;=》flowers 變成 candidate =》 然后根據多數的 vote 票數后 =》 candidate 變成 leader
數據變更:所有的數據變更,都是先修改 leader,然后 leader同步到其他 followers;
(2.4)集群提交/選舉詳細原理
【1】leader選舉:
2個超時字段:
一般選舉超時是心跳超時的10倍
(1)選舉超時(election timeout):選舉時使用,這個時間是隨機的,默認1000ms(v3.5) ;
- 當我們的選舉超時最先過期的 follower 自動立馬變成候選者(candidate);
- 然后開始新一輪的選舉任期(term),term+1 ,(該值會主從復制 同步給從庫)
- 重新隨機選舉超時
- 該 candidate 節點會給自己投一票,然后廣播給其他節點拉票
- 其他 follower 節點收到拉票后,重置選舉超時,然后如果手里有票,那么就給發起拉票的節點投票
- 每個人手里只有一張票
- 只有候選者才能給自己投票且
- 當收到被人的拉票后,只要手里有票,誰先發過就給誰投
(2)心跳超時(heartbeat timeout):檢測節點之間網絡是否正常,默認100ms(v3.5)
當 follower 收到 leader的數據同步包,都會重置兩個超時事件;
平票案例:
如果 3個節點的集群,leader掛了;2個 follower 恰巧同時成為了 candidate ;
這時候2個節點各自擁有一票,要是這樣成了,那不是會腦裂?
這個時候,會重新重置選票,然后重置,選舉超時,再來一輪,新一輪誰先成為 candidate,那么誰就是主;
要是依舊那么巧,又同時,那么繼續上一行內容的行為,以此反復直到會有一個人 先成為 candidate;( 每有一次這種情況,term同時也會+1 )
(2.5)主從日志復制
1》client: 發起請求到 gRPC Server
2》gRPC Server:接受連接請求,然后把請求命令信息發到主庫的 wal
3》wal:把請求命令信息廣播同步到從庫,有一半及以上從庫收到同意后,返回同意確認標識給主庫
4》主庫對命令請求進行提交落盤 然后再次廣播給從庫讓從庫也提交落盤
5》返回給客戶端
【3】常見原理
(3.1)深入key版本信息
(1)raft_term:leader任期(每次選舉的時候,都會+1),64位整數,全局單調遞增
(2)revision: 全局的版本號 =》 對應數據庫修改的版本,即只要對 etcd 進行增刪改,版本號都會 +1 (無論是對什么key 操作都會 ) ,64 位整數,全局單調遞增
(3)create_revision:創建key時候的版本號,即在創建key時的全局版本號(revision 的值);
(4)modify_revision:修改key的時候的全局版本號
(5)lease:租約(有效期):就是一個全局對象,設置好過期時間,然后某些key來與這個全局對象綁定,這個全局對象到了過期時間,key也會對應過期被刪除;
有點和 redis expire key ttl 形式類似;
但區別是,etcd的租約 有針對多個key的優化;常見情況如下:
《1》我們有需求設置大量key在同一時間過期
《2》建一個全局對象,這個全局對象設置好過期時間,然后把key與這個 lease全局對象綁定
《3》這樣,我們從原本的掃描這些key的過期情況,轉而變成只掃描這個全局對象;如果這個全局對象過期,那么其綁定的多個具體key也過期了;
基本操作演示 如下:
【3.2】持久化問題
《1》不會丟數據,會先寫到wal 里面,再寫到 snap 快照文件里;
《2》當生成 snap 快照,則被持久化 相關的 wal 文件及被持久化的操作記錄都會被清理掉;
WAL:
快照:
默認情況下,將在每 10,000 次更改后創建快照。如果 etcd 的內存使用和磁盤使用過高,請嘗試通過在命令行上設置以下內容來降低快照閾值:
# Command line arguments:
$ etcd --snapshot-count=5000
# Environment variables:
$ ETCD_SNAPSHOT_COUNT=5000 etcd
【深入業務實現】
(1)服務發現
tcd比較多的應用場景是用於服務發現,服務發現(Service Discovery)要解決的是分布式系統中最常見的問題之一,即在同一個分布式集群中的進程或服務如何才能找到對方並建立連接。
從本質上說,服務發現就是要了解集群中是否有進程在監聽upd或者tcp端口,並且通過名字就可以進行查找和鏈接。
要解決服務發現的問題,需要下面三大支柱,缺一不可。
- 一個強一致性、高可用的服務存儲目錄。
基於Ralf算法的etcd天生就是這樣一個強一致性、高可用的服務存儲目錄。
- 一種注冊服務和健康服務健康狀況的機制。
用戶可以在etcd中注冊服務,並且對注冊的服務配置key TTL,定時保持服務的心跳以達到監控健康狀態的效果。
- 一種查找和連接服務的機制。
通過在etcd指定的主題下注冊的服務業能在對應的主題下查找到。為了確保連接,我們可以在每個服務機器上都部署一個proxy模式的etcd,這樣就可以確保訪問etcd集群的服務都能夠互相連接。

(2)應用舉例概述
1.服務發現
(1) 先用LeaseGrant獲取租約ID;
(2)Key:系統名稱/服務名稱/服務版本/服務唯一ID
Value:服務地址
(3)用Put方法存儲並有租約
(4)定時用LeaseKeepAlive方法刷新
這樣服務發現和心跳都有了
2.訂閱發布
(1)創建Topic節點
(2)用put方法在該節點下發布值:key:主題名稱 value:數據的
(3)訂閱方用 WatchRange方法監視Topic節點
3.負責均衡
類似服務發現,創建一個服務Key,輪訓地址,同時記錄當前的地址
4.分布式鎖
(1)etcd提供了全局鎖方法,通過相同key就可以創建全局鎖
利用該功能可以創建系統唯一ID
5.隊列
(1)創建 queue節點
(2)用Watch方法監視該節點
【4】ETCD 單實例
(4.1)下載安裝與啟動連接
mkdir /soft
cd /soft
wget https://github.com/etcd-io/etcd/releases/download/v3.5.1/etcd-v3.5.1-linux-amd64.tar.gz
tar -zxf etcd-v3.5.1-linux-amd64.tar.gz
mv etcd-v3.5.1-linux-amd64 etcd
cd etcd
mkdir bin
cp etcd* ./bin/
echo "export PATH=${PATH}:`pwd`/bin" >>/etc/profile
source /etc/profile
ls 查看里面的文件
是一些文檔和兩個二進制文件 etcd 和 etcdctl;
etcd 是server端,etcdctl是客戶端
啟動看看:
nohup ./etcd &
{"level":"info","ts":"2022-01-04T17:59:56.291+0800","caller":"etcdmain/etcd.go:72","msg":"Running: ","args":["./etcd"]}
{"level":"warn","ts":"2022-01-04T17:59:56.291+0800","caller":"etcdmain/etcd.go:104","msg":"'data-dir' was empty; using default","data-dir":"default.etcd"} {"level":"info","ts":"2022-01-04T17:59:56.291+0800","caller":"embed/etcd.go:131","msg":"configuring peer listeners","listen-peer-urls":["http://localhost:2380"]} {"level":"info","ts":"2022-01-04T17:59:56.292+0800","caller":"embed/etcd.go:139","msg":"configuring client listeners","listen-client-urls":["http://localhost:2379"]} {"level":"info","ts":"2022-01-04T17:59:56.292+0800","caller":"embed/etcd.go:307","msg":"starting an etcd server","etcd-version":"3.5.1","git-sha":"e8732fb5f","go-version":"go1.16.3","go-os":"linux","go-arch":"amd64","max-cpu-set":1,"max-cpu-available":1,"member-initialized":false,"name":"default","data-dir":"default.etcd","wal-dir":"","wal-dir-dedicated":"","member-dir":"default.etcd/member","force-new-cluster":false,"heartbeat-interval":"100ms","election-timeout":"1s","initial-election-tick-advance":true,"snapshot-count":100000,"snapshot-catchup-entries":5000,"initial-advertise-peer-urls":["http://localhost:2380"],"listen-peer-urls":["http://localhost:2380"],"advertise-client-urls":["http://localhost:2379"],"listen-client-urls":["http://localhost:2379"],"listen-metrics-urls":[],"cors":["*"],"host-whitelist":["*"],"initial-cluster":"default=http://localhost:2380","initial-cluster-state":"new","initial-cluster-token":"etcd-cluster","quota-size-bytes":2147483648,"pre-vote":true,"initial-corrupt-check":false,"corrupt-check-time-interval":"0s","auto-compaction-mode":"periodic","auto-compaction-retention":"0s","auto-compaction-interval":"0s","discovery-url":"","discovery-proxy":"","downgrade-check-interval":"5s"} {"level":"info","ts":"2022-01-04T17:59:56.295+0800","caller":"etcdserver/backend.go:81","msg":"opened backend db","path":"default.etcd/member/snap/db","took":"1.297072ms"} {"level":"info","ts":"2022-01-04T17:59:56.328+0800","caller":"etcdserver/raft.go:448","msg":"starting local member","local-member-id":"8e9e05c52164694d","cluster-id":"cdf818194e3a8c32"} {"level":"info","ts":"2022-01-04T17:59:56.328+0800","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"8e9e05c52164694d switched to configuration voters=()"} {"level":"info","ts":"2022-01-04T17:59:56.328+0800","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"8e9e05c52164694d became follower at term 0"} {"level":"info","ts":"2022-01-04T17:59:56.328+0800","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"newRaft 8e9e05c52164694d [peers: [], term: 0, commit: 0, applied: 0, lastindex: 0, lastterm: 0]"} {"level":"info","ts":"2022-01-04T17:59:56.328+0800","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"8e9e05c52164694d became follower at term 1"} {"level":"info","ts":"2022-01-04T17:59:56.328+0800","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"8e9e05c52164694d switched to configuration voters=(10276657743932975437)"} {"level":"warn","ts":"2022-01-04T17:59:56.329+0800","caller":"auth/store.go:1220","msg":"simple token is not cryptographically signed"} {"level":"info","ts":"2022-01-04T17:59:56.331+0800","caller":"mvcc/kvstore.go:415","msg":"kvstore restored","current-rev":1} {"level":"info","ts":"2022-01-04T17:59:56.333+0800","caller":"etcdserver/quota.go:94","msg":"enabled backend quota with default value","quota-name":"v3-applier","quota-size-bytes":2147483648,"quota-size":"2.1 GB"} {"level":"info","ts":"2022-01-04T17:59:56.333+0800","caller":"etcdserver/server.go:843","msg":"starting etcd server","local-member-id":"8e9e05c52164694d","local-server-version":"3.5.1","cluster-version":"to_be_decided"} {"level":"info","ts":"2022-01-04T17:59:56.337+0800","caller":"embed/etcd.go:276","msg":"now serving peer/client/metrics","local-member-id":"8e9e05c52164694d","initial-advertise-peer-urls":["http://localhost:2380"],"listen-peer-urls":["http://localhost:2380"],"advertise-client-urls":["http://localhost:2379"],"listen-client-urls":["http://localhost:2379"],"listen-metrics-urls":[]} {"level":"info","ts":"2022-01-04T17:59:56.338+0800","caller":"etcdserver/server.go:728","msg":"started as single-node; fast-forwarding election ticks","local-member-id":"8e9e05c52164694d","forward-ticks":9,"forward-duration":"900ms","election-ticks":10,"election-timeout":"1s"} {"level":"info","ts":"2022-01-04T17:59:56.338+0800","caller":"embed/etcd.go:580","msg":"serving peer traffic","address":"127.0.0.1:2380"} {"level":"info","ts":"2022-01-04T17:59:56.338+0800","caller":"embed/etcd.go:552","msg":"cmux::serve","address":"127.0.0.1:2380"} {"level":"info","ts":"2022-01-04T17:59:56.338+0800","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"8e9e05c52164694d switched to configuration voters=(10276657743932975437)"} {"level":"info","ts":"2022-01-04T17:59:56.338+0800","caller":"membership/cluster.go:421","msg":"added member","cluster-id":"cdf818194e3a8c32","local-member-id":"8e9e05c52164694d","added-peer-id":"8e9e05c52164694d","added-peer-peer-urls":["http://localhost:2380"]} {"level":"info","ts":"2022-01-04T17:59:56.930+0800","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"8e9e05c52164694d is starting a new election at term 1"} {"level":"info","ts":"2022-01-04T17:59:56.930+0800","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"8e9e05c52164694d became pre-candidate at term 1"} {"level":"info","ts":"2022-01-04T17:59:56.930+0800","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"8e9e05c52164694d received MsgPreVoteResp from 8e9e05c52164694d at term 1"} {"level":"info","ts":"2022-01-04T17:59:56.930+0800","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"8e9e05c52164694d became candidate at term 2"} {"level":"info","ts":"2022-01-04T17:59:56.930+0800","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"8e9e05c52164694d received MsgVoteResp from 8e9e05c52164694d at term 2"} {"level":"info","ts":"2022-01-04T17:59:56.930+0800","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"8e9e05c52164694d became leader at term 2"} {"level":"info","ts":"2022-01-04T17:59:56.930+0800","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"raft.node: 8e9e05c52164694d elected leader 8e9e05c52164694d at term 2"} {"level":"info","ts":"2022-01-04T17:59:56.931+0800","caller":"etcdserver/server.go:2476","msg":"setting up initial cluster version using v2 API","cluster-version":"3.5"} {"level":"info","ts":"2022-01-04T17:59:56.931+0800","caller":"membership/cluster.go:584","msg":"set initial cluster version","cluster-id":"cdf818194e3a8c32","local-member-id":"8e9e05c52164694d","cluster-version":"3.5"} {"level":"info","ts":"2022-01-04T17:59:56.931+0800","caller":"api/capability.go:75","msg":"enabled capabilities for version","cluster-version":"3.5"} {"level":"info","ts":"2022-01-04T17:59:56.931+0800","caller":"etcdserver/server.go:2500","msg":"cluster version is updated","cluster-version":"3.5"} {"level":"info","ts":"2022-01-04T17:59:56.931+0800","caller":"etcdserver/server.go:2027","msg":"published local member to cluster through raft","local-member-id":"8e9e05c52164694d","local-member-attributes":"{Name:default ClientURLs:[http://localhost:2379]}","request-path":"/0/members/8e9e05c52164694d/attributes","cluster-id":"cdf818194e3a8c32","publish-timeout":"7s"} {"level":"info","ts":"2022-01-04T17:59:56.931+0800","caller":"embed/serve.go:98","msg":"ready to serve client requests"} {"level":"info","ts":"2022-01-04T17:59:56.932+0800","caller":"embed/serve.go:140","msg":"serving client traffic insecurely; this is strongly discouraged!","address":"127.0.0.1:2379"} {"level":"info","ts":"2022-01-04T17:59:56.932+0800","caller":"etcdmain/main.go:47","msg":"notifying init daemon"} {"level":"info","ts":"2022-01-04T17:59:56.932+0800","caller":"etcdmain/main.go:53","msg":"successfully notified init daemon"}
日志信息如下:
-
name表示節點名稱,默認為default。
-
data-dir 保存日志和快照的目錄,默認為當前工作目錄default.etcd/目錄下。
-
在http://localhost:2380和集群中其他節點通信。
-
在http://localhost:2379提供HTTP API服務,供客戶端交互。
-
heartbeat為100ms,該參數的作用是leader多久發送一次心跳到
-
followers,默認值是100ms。
-
election為1000ms,該參數的作用是重新投票的超時時間,如果follow在該+ 時間間隔沒有收到心跳包,會觸發重新投票,默認為1000ms。
-
snapshot count為10000,該參數的作用是指定有多少事務被提交時,觸發+ 截取快照保存到磁盤。
-
集群和每個節點都會生成一個uuid。
-
啟動的時候會運行raft,選舉出leader。
-
上面的方法只是簡單的啟動一個etcd服務,但要長期運行的話,還是做成一個服務好一些。下面將以systemd為例,介紹如何建立一個etcd服務。

利用 etcdctl 命令進行連接
本地連接, 默認使用 http://127.0.0.1:2379 作為默認 endpoint
假如需要執行遠程連接, 可以通過定義 endpoint 實現 ex: etcd --endpoint http://10.199.205.229:2379
實際上etcd服務端監聽的地址是這個參數控制的,默認就是127.0.0.1:2379
--listen-client-urls http://0.0.0.0:2379
(4.2)etcd 兩種 API 與 REST API
當前 etcdctl 支持 ETCDCTL-API=2 ETCDCTL_API=3 兩種不同的操作類型
不同的 api 類型使用的命令參數不一樣
通過環境變量切換方法定義當前 api 類型
版本2:
[root@terry ~]# etcdctl --help
NAME:
etcdctl - A simple command line client for etcd. USAGE: etcdctl [global options] command [command options] [arguments...] VERSION: 3.2.7 COMMANDS: backup backup an etcd directory cluster-health check the health of the etcd cluster mk make a new key with a given value mkdir make a new directory rm remove a key or a directory rmdir removes the key if it is an empty directory or a key-value pair get retrieve the value of a key ls retrieve a directory set set the value of a key setdir create a new directory or update an existing directory TTL update update an existing key with a given value updatedir update an existing directory watch watch a key for changes exec-watch watch a key for changes and exec an executable member member add, remove and list subcommands user user add, grant and revoke subcommands role role add, grant and revoke subcommands auth overall auth controls help, h Shows a list of commands or help for one command
版本3:(當前最新,就是我們現在用的這種)見(4.3)
REST API
# curl http://10.1.2.61:2379/v2/members
查看集群成員,其中,id是集群成員的全局唯一的身份標識,name是成員的名字,peerURLs是成員之間通信的入口,clientURLs是成員跟用戶通信的訪問入口
# curl http://10.1.2.61:2379/v2/keys # curl -fs -X PUT http://10.1.2.61:2379/v2/keys/_test # curl -X GET http://10.1.2.61:2379/v2/keys/_test
(4.3)etcd 基本操作
我們可以 ./etcdctl --help 查看,命令如下:
NAME: etcdctl - A simple command line client for etcd3. USAGE: etcdctl [flags] VERSION: 3.5.1 API VERSION: 3.5 COMMANDS: alarm disarm Disarms all alarms alarm list Lists all alarms auth disable Disables authentication auth enable Enables authentication auth status Returns authentication status check datascale Check the memory usage of holding data for different workloads on a given server endpoint. check perf Check the performance of the etcd cluster compaction Compacts the event history in etcd defrag Defragments the storage of the etcd members with given endpoints del Removes the specified key or range of keys [key, range_end) elect Observes and participates in leader election endpoint hashkv Prints the KV history hash for each endpoint in --endpoints endpoint health Checks the healthiness of endpoints specified in `--endpoints` flag endpoint status Prints out the status of endpoints specified in `--endpoints` flag get Gets the key or a range of keys help Help about any command lease grant Creates leases lease keep-alive Keeps leases alive (renew) lease list List all active leases lease revoke Revokes leases lease timetolive Get lease information lock Acquires a named lock make-mirror Makes a mirror at the destination etcd cluster member add Adds a member into the cluster member list Lists all members in the cluster member promote Promotes a non-voting member in the cluster member remove Removes a member from the cluster member update Updates a member in the cluster move-leader Transfers leadership to another etcd cluster member. put Puts the given key into the store role add Adds a new role role delete Deletes a role role get Gets detailed information of a role role grant-permission Grants a key to a role role list Lists all roles role revoke-permission Revokes a key from a role snapshot restore Restores an etcd member snapshot to an etcd directory snapshot save Stores an etcd node backend snapshot to a given file snapshot status [deprecated] Gets backend snapshot status of a given file txn Txn processes all the requests in one transaction user add Adds a new user user delete Deletes a user user get Gets detailed information of a user user grant-role Grants a role to a user user list Lists all users user passwd Changes password of user user revoke-role Revokes a role from a user version Prints the version of etcdctl watch Watches events stream on keys or prefixes OPTIONS: --cacert="" verify certificates of TLS-enabled secure servers using this CA bundle --cert="" identify secure client using this TLS certificate file --command-timeout=5s timeout for short running command (excluding dial timeout) --debug[=false] enable client-side debug logging --dial-timeout=2s dial timeout for client connections -d, --discovery-srv="" domain name to query for SRV records describing cluster endpoints --discovery-srv-name="" service name to query when using DNS discovery --endpoints=[127.0.0.1:2379] gRPC endpoints -h, --help[=false] help for etcdctl --hex[=false] print byte strings as hex encoded strings --insecure-discovery[=true] accept insecure SRV records describing cluster endpoints --insecure-skip-tls-verify[=false] skip server certificate verification (CAUTION: this option should be enabled only for testing purposes) --insecure-transport[=true] disable transport security for client connections --keepalive-time=2s keepalive time for client connections --keepalive-timeout=6s keepalive timeout for client connections --key="" identify secure client using this TLS key file --password="" password for authentication (if this option is used, --user option shouldn't include password) --user="" username[:password] for authentication (prompt if password is not supplied) -w, --write-out="simple" set the output format (fields, json, protobuf, simple, table) # 額外的局部選項 OPTIONS: --consistency="l" Linearizable(l) or Serializable(s) --count-only[=false] Get only the count --from-key[=false] Get keys that are greater than or equal to the given key using byte compare -h, --help[=false] help for get --keys-only[=false] Get only the keys --limit=0 Maximum number of results --order="" Order of results; ASCEND or DESCEND (ASCEND by default) --prefix[=false] Get keys with matching prefix --print-value-only[=false] Only write values when using the "simple" output format --rev=0 Specify the kv revision --sort-by="" Sort target; CREATE, KEY, MODIFY, VALUE, or VERSION
etcd get --from-key "" 獲取所有key
我們簡單介紹最基礎幾個
- put:插入、更新
- get:查詢
- del:刪除
- txn:事務
- watch:持續觀察
那么,從之前的介紹,這些我們都用過了;
【5】ETCD集群搭建 與 基礎操作
(5.1)安裝
官網:https://etcd.io/docs/v3.5/tutorials/how-to-setup-cluster/
三個機器都運行(記得修改好 host相關ip信息成你自己的ip地址)
TOKEN=token-01 CLUSTER_STATE=new NAME_1=machine-3 NAME_2=machine-4 NAME_3=machine-5 HOST_1=192.168.175.131 HOST_2=192.168.175.132 HOST_3=192.168.175.148 CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380
三個機器分別對應執行
# 在機器1 運行 THIS_NAME=${NAME_1} THIS_IP=${HOST_1} nohup 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://0.0.0.0:2379 \ --initial-cluster ${CLUSTER} \ --initial-cluster-state ${CLUSTER_STATE} \
--initial-cluster-token ${TOKEN} & # 在機器2 運行 THIS_NAME=${NAME_2} THIS_IP=${HOST_2} nohup 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://0.0.0.0:2379 \ --initial-cluster ${CLUSTER} \ --initial-cluster-state ${CLUSTER_STATE} \
--initial-cluster-token ${TOKEN} & # 在機器3運行 THIS_NAME=${NAME_3} THIS_IP=${HOST_3} nohup 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://0.0.0.0:2379 \ --initial-cluster ${CLUSTER} \ --initial-cluster-state ${CLUSTER_STATE} \
--initial-cluster-token ${TOKEN} &
參數釋義:
–name:節點名稱,默認為 default,在集群中應該保持唯一
–data-dir:服務運行數據保存的路徑,默認為 ${name}.etcd
–snapshot-count:指定有多少事務(transaction)被提交時,觸發截取快照保存到磁盤
–listen-peer-urls:和同伴通信的地址,比如 http://ip:2380,如果有多個,使用逗號分隔。需要所有節點都能夠訪問,所以不要使用 localhost
–listen-client-urls:對外提供服務的地址:比如 http://ip:2379,http://127.0.0.1:2379,客戶端會連接到這里和 etcd 交互
–advertise-client-urls:對外公告的該節點客戶端監聽地址,這個值會告訴集群中其他節點
–initial-advertise-peer-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;否則會導致多個集群之間的沖突,造成未知的錯誤
–heartbeat-interval:leader 多久發送一次心跳到 followers。默認值 100ms
–eletion-timeout:重新投票的超時時間,如果 follow 在該時間間隔沒有收到心跳包,會觸發重新投票,默認為 1000 ms
安裝后結果:
(5.2)使用 etcdctl 連接到集群
export ETCDCTL_API=3 //添加環境變量
HOST_1=192.168.175.131
HOST_2=192.168.175.132
HOST_3=192.168.175.148
ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379
etcdctl --write-out=table --endpoints=$ENDPOINTS member list
(5.3)etcdtcl基本操作【必看】
在etcd集群上的任意一個節點都可以做增刪改查,會自動提交到主節點,然后復制分發同步到從節點;
詳細原理見 【2】中描述
# 前置信息 指定連接主機 HOST_1=192.168.175.131 HOST_2=192.168.175.132 HOST_3=192.168.175.148 ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379
# put 新建 etcdctl --endpoints=$ENDPOINTS put foo "Hello World!" # get 查詢 etcdctl --endpoints=$ENDPOINTS get foo etcdctl --endpoints=$ENDPOINTS --write-out="json" get foo
etcdctl get a c # 獲取 a~c 之間的所有key,包含a,c;
# get --from-key "" 獲取所有key,獲取大於等於該 key值的 key
etcdctl get --from-key ""
etcdctl get --from-key c # 獲取大於等於 key c 對應 value 值的 key value 信息
# get --rev=N 訪問第N個版本的 key
etcdctl get --prefix --rev=4 foo # 訪問第4個版本的key
# --prefix 通過前綴獲取 etcdctl --endpoints=$ENDPOINTS put web1 value1 etcdctl --endpoints=$ENDPOINTS put web2 value2 etcdctl --endpoints=$ENDPOINTS put web3 value3 etcdctl --endpoints=$ENDPOINTS get web -–prefix 獲取前幾字節web所有 etcdctl get –prefix / //獲取鍵的第一個字節為 / 的所有信息 # del 刪除,通過前綴刪除 etcdctl --endpoints=$ENDPOINTS put key myvalue etcdctl --endpoints=$ENDPOINTS del key etcdctl --endpoints=$ENDPOINTS put k1 value1 etcdctl --endpoints=$ENDPOINTS put k2 value2etcdctl --endpoints=$ENDPOINTS del k -–prefix 刪除前幾字節為k的所有 etcdctl del –prefix / //刪除鍵的第一個字節為 / 的所有信息 # txn:事務 etcdctl --endpoints=$ENDPOINTS put user1 bad etcdctl --endpoints=$ENDPOINTS txn --interactive compares: value("user1") = "bad" success requests (get, put, delete): del user1 failure requests (get, put, delete): put user1 good
# watch 持續監視 etcdctl --endpoints=$ENDPOINTS watch stock1 etcdctl --endpoints=$ENDPOINTS put stock1 1000 etcdctl --endpoints=$ENDPOINTS watch stock --prefix etcdctl --endpoints=$ENDPOINTS put stock1 10 etcdctl --endpoints=$ENDPOINTS put stock2 20 # lease 租約 etcdctl --endpoints=$ENDPOINTS lease grant 300 # lease 2be7547fbc6a5afa granted with TTL(300s) etcdctl --endpoints=$ENDPOINTS put sample value --lease=2be7547fbc6a5afa etcdctl --endpoints=$ENDPOINTS get sample etcdctl --endpoints=$ENDPOINTS lease keep-alive 2be7547fbc6a5afa etcdctl --endpoints=$ENDPOINTS lease revoke 2be7547fbc6a5afa # or after 300 seconds etcdctl --endpoints=$ENDPOINTS get sample
# lock 分布式鎖 etcdctl --endpoints=$ENDPOINTS lock mutex1 # another client with the same name blocks etcdctl --endpoints=$ENDPOINTS lock mutex1 # 集群狀態查看 etcdctl --write-out=table --endpoints=$ENDPOINTS member list etcdctl --write-out=table --endpoints=$ENDPOINTS endpoint status etcdctl --write-out=table --endpoints=$ENDPOINTS endpoint health # snapshot 快照查看 快照只能從一個 etcd 節點請求,所以--endpointsflag 應該只包含一個端點。 ENDPOINTS=$HOST_1:2379 etcdctl --endpoints=$ENDPOINTS snapshot save my.db # 保存當前時間點數據到快照 etcdctl --write-out=table --endpoints=$ENDPOINTS snapshot status my.db # 查看快照大小
(5.4)啟用賬戶密碼、角色
參考官網:https://etcd.io/docs/v3.5/op-guide/authentication/rbac/
(1)用戶創建
# --new-user-password='123456' :直接配置密碼 不加則是交互式 # --interactive=false :取消交互式,直接明文輸入密碼 etcdctl user list etcdctl user add myusername --new-user-password='123456' etcdctl user get myusername etcdctl user passwd myusername --interactive=false etcdctl user delete myusername # 要啟用登錄驗證,必須要有用戶 root etcdctl user add root etcdctl auth enable # 禁用登錄驗證 etcdctl --user root:rootpw auth disable # etcd 賬戶登錄 etcdctl --user user:password get foo etcdctl --user user get foo etcdctl --user user --password password get foo
(5.5)備份還原操作
備份:
恢復集群首先需要來自 etcd 成員的密鑰空間快照。可以使用etcdctl snapshot save
命令從實時成員獲取快照,也可以通過member/snap/db
從 etcd 數據目錄復制文件來獲取快照。
例如,以下命令將服務的密鑰空間快照$ENDPOINT
到文件snapshot.db
:
$ ETCDCTL_API=3 etcdctl --endpoints $ENDPOINT snapshot save snapshot.db
還原:
要恢復集群,只需要一個快照“db”文件。集群恢復etcdctl snapshot restore
創建新的 etcd 數據目錄;所有成員都應使用相同的快照進行恢復。
恢復會覆蓋一些快照元數據(特別是成員 ID 和集群 ID);該成員失去了以前的身份。此元數據覆蓋可防止新成員無意中加入現有集群。
因此,為了從快照啟動集群,還原必須啟動一個新的邏輯集群。
可以在還原時選擇性地驗證快照完整性。
如果快照是使用 拍攝的etcdctl snapshot save
,它將具有由 進行檢查的完整性散列etcdctl snapshot restore
。
如果快照是從數據目錄復制過來的,則沒有完整性哈希,只能使用--skip-hash-check
.
利用備份還原出一個新的集群:
恢復使用etcd的集群配置標志使用新的集群配置初始化新集群的新成員,但保留 etcd 數據內容。
繼續上一個示例,以下內容為三成員集群創建新的 etcd 數據目錄 ( m1.etcd, m2.etcd, m3.etcd): $ ETCDCTL_API=3 etcdctl snapshot restore snapshot.db \ --name m1 \ --initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \ --initial-cluster-token etcd-cluster-1 \ --initial-advertise-peer-urls http://host1:2380 $ ETCDCTL_API=3 etcdctl snapshot restore snapshot.db \ --name m2 \ --initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \ --initial-cluster-token etcd-cluster-1 \ --initial-advertise-peer-urls http://host2:2380 $ ETCDCTL_API=3 etcdctl snapshot restore snapshot.db \ --name m3 \ --initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \ --initial-cluster-token etcd-cluster-1 \ --initial-advertise-peer-urls http://host3:2380 接下來,etcd從新的數據目錄開始: $ etcd \ --name m1 \ --listen-client-urls http://host1:2379 \ --advertise-client-urls http://host1:2379 \ --listen-peer-urls http://host1:2380 & $ etcd \ --name m2 \ --listen-client-urls http://host2:2379 \ --advertise-client-urls http://host2:2379 \ --listen-peer-urls http://host2:2380 & $ etcd \ --name m3 \ --listen-client-urls http://host3:2379 \ --advertise-client-urls http://host3:2379 \ --listen-peer-urls http://host3:2380 & 現在恢復的 etcd 集群應該可用並為快照給出的密鑰空間提供服務。
【6】etcd 集群維護
(6.0)命令匯總
# 前置信息 指定連接主機
HOST_1=192.168.175.131
HOST_2=192.168.175.132
HOST_3=192.168.175.148
ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379 # 查看集群成員列表
etcdctl --endpoints=$ENDPOINTS --write-out=table member list
# 查看集群成員存活情況
etcdctl --endpoints=$ENDPOINTS --write-out=table endpoint health
# 查看集群狀態
etcdctl --endpoints=$ENDPOINTS --write-out=table endpoint status
# 更新節點
etcdctl member list
etcdctl member update memberID http://ip:2380
# 刪除節點
etcdctl member list
etcdctl member remove memberID
etcdctl member list
ps -ef|grep etcd
(6.1)狀態查看
集群創建信息見(5.1)
下面直接是查看集群狀態
# 前置信息 指定連接主機 HOST_1=192.168.175.131 HOST_2=192.168.175.132 HOST_3=192.168.175.148 ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379 # 查看集群成員列表 etcdctl --endpoints=$ENDPOINTS --write-out=table member list # 查看集群成員存活情況 etcdctl --endpoints=$ENDPOINTS --write-out=table endpoint health # 查看集群狀態 etcdctl --endpoints=$ENDPOINTS --write-out=table endpoint status
(6.2)刪除節點
刪除節點:(刪除 192.168.175.148,machine-5)
HOST_1=192.168.175.131 HOST_2=192.168.175.132 HOST_3=192.168.175.148 ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379
# 查看集群成員列表,獲取節點ID
etcdctl --endpoints=$ENDPOINTS --write-out=table member list
# 根據節點ID,刪除節點
etcdctl --endpoints=$ENDPOINTS member remove 6d8e4e127db7ab6c
# 再次查看集群成員列表
etcdctl --endpoints=$ENDPOINTS --write-out=table member list
(6.3)增加節點
# 注意,如果是一個集群脫機下來的節點,那么務必要刪除 data-dir 下的所有數據
即本文啟動命令 etcd --data-dir=data.etcd 對應的目錄,不刪則會報錯
{"level":"warn","ts":"2022-01-06T16:59:32.830+0800","caller":"etcdserver/server.go:1142","msg":"server error","error":"the member has been permanently removed from the cluster"} {"level":"warn","ts":"2022-01-06T16:59:32.830+0800","caller":"etcdserver/server.go:1143","msg":"data-dir used by this member must be removed"}
因為這里面會記錄集群相關信息(如 id、token 等),也會記錄數據信息
增加節點操作如下:
TOKEN=token-01 CLUSTER_STATE=new NAME_1=machine-3 NAME_2=machine-4 NAME_3=machine-5 HOST_1=192.168.175.131 HOST_2=192.168.175.132 HOST_3=192.168.175.148 CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380 ENDPOINTS=${HOST_1}:2379,${HOST_2}:2379
# 注意,如果是一個別的集群脫機下來的節點,那么務必要刪除 datadir 下的所有數據
etcdctl --endpoints=$ENDPOINTS member add {NAME_3} --peer-urls=http://${HOST_3}:2380
返回結果
Member 6eb8fc8f1b2e6002 added to cluster 7e6769581016e8e2 ETCD_NAME="{NAME_3}" ETCD_INITIAL_CLUSTER="{NAME_3}=http://192.168.175.148:2380,machine-4=http://192.168.175.132:2380,machine-3=http://192.168.175.131:2380" ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.175.148:2380" ETCD_INITIAL_CLUSTER_STATE="existing"
我們再去其他節點查看,雖然節點加進來了,但是並沒有啟動
正式啟動、加入:使用--initial-cluster-state existing
標志啟動新成員:
TOKEN=token-01 CLUSTER_STATE=existing NAME_1=machine-3 NAME_2=machine-4 NAME_3=machine-5 HOST_1=192.168.175.131 HOST_2=192.168.175.132 HOST_3=192.168.175.148 CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380 THIS_NAME=${NAME_3} THIS_IP=${HOST_3} nohup 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://0.0.0.0:2379 \ --initial-cluster ${CLUSTER} \ --initial-cluster-state ${CLUSTER_STATE} \ --initial-cluster-token ${TOKEN} &
再查看
HOST_1=192.168.175.131 HOST_2=192.168.175.132 HOST_3=192.168.175.148 ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379 # 查看集群成員列表,獲取節點ID etcdctl --endpoints=$ENDPOINTS --write-out=table member list
(6.4)etcd的重要參數
參考:官網維護網頁 https://etcd.io/docs/v3.5/op-guide/maintenance/
(1)etcd --snapshot-count(3.2之前默認 10000,3.2及之后默認100000):
Raft WAL日志保留在內存中,當內存中有超過 該參數值的 key變動,就會把數據持久化到 snapshot 中,同時清理掉內存、磁盤中已經持久化的 WAL日志信息;
(2)etcd --auto-compaction-retention=1(自動壓縮,單位小時),同時壓縮省下來的空間只能給etcd用,要是想還給OS,則需要做碎片處理
-
3.1及之前版本是默認是10小時;也就是說如果10小時之前該key版本號是1000,那么10小時后,清理的時候就是key版本號1000以前的所有歷史數據;
-
假設每小時更新100次,那么10小時后key版本號就從1000變成2000,那么下一個10小時后就變成3000(這個時候清理10小時前的,那就是清理2000以前的所有版本號)
-
3.2版本默認是1小時一次,原理同上。上面的 1000,2000,3000 變成 1100,1200,1300 而已;
-
3.3.0-3.3.2版本中,有了不同的改變;
--auto-compaction-mode=revision --auto-compaction-retention=1000 自動Compact上"latest revision" ,默認每5分鍾壓縮一次,壓縮上次至現在1000個;那么壓縮版本規律就是 1000,2000,3000;
例如版本號當前是30000,那么每5分鍾 清除當前版本號-1000之前的所有歷史數據,也就是刪除29000版本號之前的所有數據;
--auto-compaction-mode=periodic --auto-compaction-retention=72h,根據時間,第一次會等待72h再清理,之后根據該值的1/10,也就是每7.2小時記錄的版本號之前的數據清理一遍
--auto-compaction-mode=periodic --auto-compaction-retention=30m,根據時間,第一次會等待30m再清理,之后根據該值的1/10,也就是每3分鍾清理一次3分鍾之前記錄的版本號之前的的數據
- 也就是說當
--auto-compaction-retention=10h
,etcd 首先等待 10 小時進行第一次壓縮,然后每隔一小時(10 小時的 1/10)進行一次壓縮
- 也就是說當
-
3.3.3及之后:
--auto-compaction-mode=revision --auto-compaction-retention=1000自動Compact上"latest revision" ,只保留最新的1000個版本號值;
例如版本號當前是30000,那么每5分鍾 清除當前版本號-1000之前的所有歷史數據,也就是刪除29000版本號之前的所有數據;
--auto-compaction-mode=periodic --auto-compaction-retention=72h,根據時間,第一次會等待72h再清理,之后每小時清理一次
--auto-compaction-mode=periodic --auto-compaction-retention=30m,根據時間,第一次會等待30m再清理,之后也是每30分鍾一次
(3)etcd --quota-backend-bytes=$((16*1024*1024)):垃圾不要使用,
存儲空間大小限制(存儲超過該值會讓集群變只讀、只能刪除,直到存儲大小低於該值)
(4)表碎片整理 :注意,會導致不可讀寫
$ etcdctl defrag
Finished defragmenting etcd member[127.0.0.1:2379]
要在 etcd 未運行時直接對 etcd 數據目錄進行碎片整理,請使用以下命令:
$ etcdctl defrag --data-dir <path-to-etcd-data-dir>
【7】使用 prometheus 監控 etcd
如下圖,看到這個就懂了吧,直接用prometheus 在配置文件里配置即可;
【etcd和同類型產品的對比】
(1) etcd vs redis
etcd誕生之日起,就定位成一種分布式存儲系統,並在k8s 服務注冊和服務發現中,為大家所認識。它偏重的是節點之間的通信和一致性的機制保證,並不強調單節點的讀寫性能。
而redis最早作為緩存系統出現在大眾視野,也注定了redis需要更加側重於讀寫性能和支持更多的存儲模式,它不需要care一致性,也不需要側重事務,因此可以達到很高的讀寫性能。
總結一下,redis常用來做緩存系統,etcd常用來做分布式系統中一些關鍵數據的存儲服務,比如服務注冊和服務發現。
(2) etcd vs consul
consul定位是一個端到端的服務框架,提供了內置的監控檢查、DNS服務等,除此之外,還提供了HTTP API和Web UI,如果要實現簡單的服務發現,基本上可以開箱即用。
但是缺點同樣也存在,封裝有利有弊,就導致靈活性弱了不少。除此之外,consul還比較年輕,暫未在大型項目中實踐,可靠性還未可知。
(3) etcd vs zookeeper
etcd站在了巨人的肩膀上。。
【etcd性能表現】
來自於官網介紹:https://etcd.io/docs/v3.4.0/op-guide/performance/ 大致總結一下:
- 讀:1w ~ 10w 之間
- 寫:1w左右
建議:
- etcd需要部署到ssd盤(強烈建議)
- 多個寫采用batch操作。
- 非必要情況下,避免range操作。
etcd集群更偏重一致性和穩定性,並不強調高性能,在絕大部分場景下均不會到達etcd性能瓶頸,如果出現瓶頸的話,需要重新review架構設計,比如拆分或者優化流程。
【本文參考轉載自文章】
官網:官網:https://etcd.io/docs/v3.5/tutorials/how-to-setup-cluster/
https://www.jianshu.com/p/f68028682192
https://zhuanlan.zhihu.com/p/339902098
etcd 入門篇:https://blog.csdn.net/jkwanga/article/details/106444556
etcd 集群維護:https://blog.csdn.net/hai330/article/details/118357407