一、etcd介紹:
ETCD 是一個高可用的分布式鍵值數據庫,可用於服務發現。ETCD 采用 raft 一致性算法,基於 Go 語言實現。etcd作為一個高可用鍵值存儲系統,天生就是為集群化而設計的。由於Raft算法在做決策時需要多數節點的投票,所以etcd一般部署集群推薦奇數個節點,推薦的數量為3、5或者7個節點構成一個集群。
二、特點:
實際上,etcd作為一個受到Zookeeper與doozer啟發而催生的項目,除了擁有與之類似的功能外,更具有以下4個特點{![引自Docker官方文檔]}。
- 簡單:基於HTTP+JSON的API讓你用curl命令就可以輕松使用。
- 安全:可選SSL客戶認證機制。
- 快速:每個實例每秒支持一千次寫操作。
- 可信:使用Raft算法充分實現了分布式。

三、etcd關鍵詞匯
- Raft:etcd所采用的保證分布式系統強一致性的算法。
- Node:一個Raft狀態機實例。
- Member: 一個etcd實例。它管理着一個Node,並且可以為客戶端請求提供服務。
- Cluster:由多個Member構成可以協同工作的etcd集群。
- Peer:對同一個etcd集群中另外一個Member的稱呼。
- Client: 向etcd集群發送HTTP請求的客戶端。
- WAL:預寫式日志,etcd用於持久化存儲的日志格式。
- snapshot:etcd防止WAL文件過多而設置的快照,存儲etcd數據狀態。
- Proxy:etcd的一種模式,為etcd集群提供反向代理服務。
- Leader:Raft算法中通過競選而產生的處理所有數據提交的節點。
- Follower:競選失敗的節點作為Raft中的從屬節點,為算法提供強一致性保證。
- Candidate:當Follower超過一定時間接收不到Leader的心跳時轉變為Candidate開始Leader競選。
- Term:某個節點成為Leader到下一次競選開始的時間周期,稱為一個Term。
- Index:數據項編號。Raft中通過Term和Index來定位數據。
四、etcd應用場景:
1、服務發現:
服務發現(Service Discovery)要解決的是分布式系統中最常見的問題之一,即在同一個分布式集群中的進程或服務如何才能找到對方並建立連接。從本質上說,服務發現就是想要了解集群中是否有進程在監聽udp或tcp端口,並且通過名字就可以進行查找和連接。
2、消息發布與訂閱:
在分布式系統中,最為適用的組件間通信方式是消息發布與訂閱機制。具體而言,即構建一個配置共享中心,數據提供者在這個配置中心發布消息,而消息使用者則訂閱他們關心的主題,一旦相關主題有消息發布,就會實時通知訂閱者。通過這種方式可以實現分布式系統配置的集中式管理與實時動態更新
- 應用中用到的一些配置信息存放在etcd上進行集中管理。這類場景的使用方式通常是這樣的:應用在啟動的時候主動從etcd獲取一次配置信息,同時,在etcd節點上注冊一個Watcher並等待,以后每次配置有更新的時候,etcd都會實時通知訂閱者,以此達到獲取最新配置信息的目的。
- 分布式搜索服務中,索引的元信息和服務器集群機器的節點狀態信息存放在etcd中,供各個客戶端訂閱使用。使用etcd的
key TTL功能可以確保機器狀態是實時更新的。 - 分布式日志收集系統。這個系統的核心工作是收集分布在不同機器上的日志。收集器通常按照應用(或主題)來分配收集任務單元,因此可以在etcd上創建一個以應用(或主題)命名的目錄P,並將這個應用(或主題)相關的所有機器ip,以子目錄的形式存儲在目錄P下,然后設置一個遞歸的etcd Watcher,遞歸式地監控應用(或主題)目錄下所有信息的變動。這樣就實現了在機器IP(消息)發生變動時,能夠實時通知收集器調整任務分配。
- 系統中信息需要動態自動獲取與人工干預修改信息請求內容的情況。通常的解決方案是對外暴露接口,例如JMX接口,來獲取一些運行時的信息或提交修改的請求。而引入etcd之后,只需要將這些信息存放到指定的etcd目錄中,即可通過HTTP接口直接被外部訪問。
3、負載均衡:
在分布式系統中,為了保證服務的高可用以及數據的一致性,通常都會把數據和服務部署多份,以此達到對等服務,即使其中的某一個服務失效了,也不影響使用。這樣的實現雖然會導致一定程度上數據寫入性能的下降,但是卻能實現數據訪問時的負載均衡。因為每個對等服務節點上都存有完整的數據,所以用戶的訪問流量就可以分流到不同的機器上。
- etcd本身分布式架構存儲的信息訪問支持負載均衡。etcd集群化以后,每個etcd的核心節點都可以處理用戶的請求。所以,把數據量小但是訪問頻繁的消息數據直接存儲到etcd中也是個不錯的選擇,如業務系統中常用的二級代碼表。二級代碼表的工作過程一般是這樣,在表中存儲代碼,在etcd中存儲代碼所代表的具體含義,業務系統調用查表的過程,就需要查找表中代碼的含義。所以如果把二級代碼表中的小量數據存儲到etcd中,不僅方便修改,也易於大量訪問。
- 利用etcd維護一個負載均衡節點表。etcd可以監控一個集群中多個節點的狀態,當有一個請求發過來后,可以輪詢式地把請求轉發給存活着的多個節點。類似KafkaMQ,通過Zookeeper來維護生產者和消費者的負載均衡。同樣也可以用etcd來做Zookeeper的工作。
4、分布式通知與協調:
這里討論的分布式通知與協調,與消息發布和訂閱有些相似。兩者都使用了etcd中的Watcher機制,通過注冊與異步通知機制,實現分布式環境下不同系統之間的通知與協調,從而對數據變更進行實時處理。實現方式通常為:不同系統都在etcd上對同一個目錄進行注冊,同時設置Watcher監控該目錄的變化(如果對子目錄的變化也有需要,可以設置成遞歸模式),當某個系統更新了etcd的目錄,那么設置了Watcher的系統就會收到通知,並作出相應處理。
- 通過etcd進行低耦合的心跳檢測。檢測系統和被檢測系統通過etcd上某個目錄關聯而非直接關聯起來,這樣可以大大減少系統的耦合性。
- 通過etcd完成系統調度。某系統有控制台和推送系統兩部分組成,控制台的職責是控制推送系統進行相應的推送工作。管理人員在控制台做的一些操作,實際上只需要修改etcd上某些目錄節點的狀態,而etcd就會自動把這些變化通知給注冊了Watcher的推送系統客戶端,推送系統再做出相應的推送任務。
- 通過etcd完成工作匯報。大部分類似的任務分發系統,子任務啟動后,到etcd來注冊一個臨時工作目錄,並且定時將自己的進度進行匯報(將進度寫入到這個臨時目錄),這樣任務管理者就能夠實時知道任務進度。
5、分布式鎖:
因為etcd使用Raft算法保持了數據的強一致性,某次操作存儲到集群中的值必然是全局一致的,所以很容易實現分布式鎖。鎖服務有兩種使用方式,一是保持獨占,二是控制時序。
- 保持獨占,即所有試圖獲取鎖的用戶最終只有一個可以得到。etcd為此提供了一套實現分布式鎖原子操作CAS(
CompareAndSwap)的API。通過設置prevExist值,可以保證在多個節點同時創建某個目錄時,只有一個成功,而該用戶即可認為是獲得了鎖。 - 控制時序,即所有試圖獲取鎖的用戶都會進入等待隊列,獲得鎖的順序是全局唯一的,同時決定了隊列執行順序。etcd為此也提供了一套API(自動創建有序鍵),對一個目錄建值時指定為
POST動作,這樣etcd會自動在目錄下生成一個當前最大的值為鍵,存儲這個新的值(客戶端編號)。同時還可以使用API按順序列出所有當前目錄下的鍵值。此時這些鍵的值就是客戶端的時序,而這些鍵中存儲的值可以是代表客戶端的編號。
五、搭建集群
主機信息:
| 角色 | 系統 | 節點 |
| master | CentOS-7 | 192.168.10.5 |
| node-1 | CentOS-7 | 192.168.10.6 |
| node-2 | CentOS-7 | 192.168.10.7 |
配置阿里epel源:
mv /etc/yum.repos.d/epel.repo /etc/yum.repos.d/epel.repo.backup
mv /etc/yum.repos.d/epel-testing.repo /etc/yum.repos.d/epel-testing.repo.backup
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
安裝配置存儲etcd(高可用):
1、在三台安裝etcd(集群)、做高可用
[root@node1 ~]# yum -y install etcd [root@node2 ~]# yum -y install etcd [root@master ~]# yum -y install etcd [root@master ~]# etcd --version etcd Version: 3.2.22 Git SHA: 1674e68 Go Version: go1.9.4 Go OS/Arch: linux/amd64
2 配置文件修改
master節點
[root@master ~]# egrep -v "^$|^#" /etc/etcd/etcd.conf
ETCD_DATA_DIR="/var/lib/etcd/default.etcd" #etcd數據保存目錄 ETCD_LISTEN_PEER_URLS="http://192.168.10.5:2380" #集群內部通信使用的URL ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" #供外部客戶端使用的url ETCD_NAME="etcd01" #etcd實例名稱 ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.10.5:2380" #廣播給集群內其他成員訪問的URL ETCD_ADVERTISE_CLIENT_URLS="http://0.0.0.0:2379" #廣播給外部客戶端使用的url ETCD_INITIAL_CLUSTER="etcd01=http://192.168.10.5:2380,etcd02=http://192.168.10.6:2380,etcd03=http://192.168.10.7:2380" #初始集群成員列表 ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" #集群的名稱 ETCD_INITIAL_CLUSTER_STATE="new" #初始集群狀態,new為新建集群
node-1
[root@node1 etcd]# egrep -v "^$|^#" /etc/etcd/etcd.conf ETCD_DATA_DIR="/var/lib/etcd/default.etcd" ETCD_LISTEN_PEER_URLS="http://192.168.10.6:2380" ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" ETCD_NAME="etcd02" ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.10.6:2380" ETCD_ADVERTISE_CLIENT_URLS="http://0.0.0.0:2379" ETCD_INITIAL_CLUSTER="etcd01=http://192.168.10.5:2380,etcd02=http://192.168.10.6:2380,etcd03=http://192.168.10.7:2380" ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" ETCD_INITIAL_CLUSTER_STATE="exist"
node-2
[root@node2 ~]# egrep -v "^$|^#" /etc/etcd/etcd.conf ETCD_DATA_DIR="/var/lib/etcd/default.etcd" ETCD_LISTEN_PEER_URLS="http://192.168.10.7:2380" ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" ETCD_NAME="etcd03" ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.10.7:2380" ETCD_ADVERTISE_CLIENT_URLS="http://0.0.0.0:2379" ETCD_INITIAL_CLUSTER="etcd01=http://192.168.10.5:2380,etcd02=http://192.168.10.6:2380,etcd03=http://192.168.10.7:2380" ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" ETCD_INITIAL_CLUSTER_STATE="exist"
分別進行啟動:
[root@master etcd]# systemctl start etcd [root@master etcd]# systemctl status etcd ● etcd.service - Etcd Server Loaded: loaded (/usr/lib/systemd/system/etcd.service; disabled; vendor preset: disabled) Active: active (running) since Tue 2019-01-08 17:28:34 CST; 2h 32min ago Main PID: 114077 (etcd) Tasks: 7 Memory: 48.7M CGroup: /system.slice/etcd.service └─114077 /usr/bin/etcd --name=etcd01 --data-dir=/var/lib/etcd/default.etcd --listen-client-urls=http://0.0.0.0:2379 Jan 08 20:00:08 master etcd[114077]: 4c5d727d37966a87 became candidate at term 16 Jan 08 20:00:08 master etcd[114077]: 4c5d727d37966a87 received MsgVoteResp from 4c5d727d37966a87 at term 16 Jan 08 20:00:08 master etcd[114077]: 4c5d727d37966a87 [logterm: 11, index: 44] sent MsgVote request to 315fd62e577c4037 at term 16 Jan 08 20:00:08 master etcd[114077]: 4c5d727d37966a87 [logterm: 11, index: 44] sent MsgVote request to f617da66fb9b90ad at term 16 Jan 08 20:00:08 master etcd[114077]: 4c5d727d37966a87 received MsgVoteResp from f617da66fb9b90ad at term 16 Jan 08 20:00:08 master etcd[114077]: 4c5d727d37966a87 [quorum:2] has received 2 MsgVoteResp votes and 0 vote rejections Jan 08 20:00:08 master etcd[114077]: 4c5d727d37966a87 became leader at term 16 Jan 08 20:00:08 master etcd[114077]: raft.node: 4c5d727d37966a87 elected leader 4c5d727d37966a87 at term 16 Jan 08 20:00:09 master etcd[114077]: the clock difference against peer 315fd62e577c4037 is too high [4.285950016s > 1s] Jan 08 20:00:09 master etcd[114077]: the clock difference against peer f617da66fb9b90ad is too high [4.120954945s > 1s]
[root@master etcd]# netstat -tunlp|grep etcd tcp 0 0 192.168.10.5:2380 0.0.0.0:* LISTEN 114077/etcd tcp6 0 0 :::2379 :::* LISTEN 114077/etcd
3、etc集群測試
集群數據操作命令:
查看集群節點
[root@node1 etcd]# etcdctl member list 315fd62e577c4037: name=etcd03 peerURLs=http://192.168.10.7:2380 clientURLs=http://0.0.0.0:2379 isLeader=false 4c5d727d37966a87: name=etcd01 peerURLs=http://192.168.10.5:2380 clientURLs=http://0.0.0.0:2379 isLeader=true f617da66fb9b90ad: name=etcd02 peerURLs=http://192.168.10.6:2380 clientURLs=http://0.0.0.0:2379 isLeader=false
查看集群健康狀態:
[root@master etcd]# etcdctl cluster-health
member 315fd62e577c4037 is healthy: got healthy result from http://0.0.0.0:2379
member 4c5d727d37966a87 is healthy: got healthy result from http://0.0.0.0:2379
member f617da66fb9b90ad is healthy: got healthy result from http://0.0.0.0:2379
cluster is healthy
設置鍵值:
在一個節點設置值
[root@master etcd]# etcdctl set /test/key "test kubernetes" test kubernetes
在另一個節點獲取值
[root@node1 etcd]# etcdctl get /test/key
test kubernetes
- key存在的方式和zookeeper類似,為
/路徑/key - 設置完之后,其他集群也可以查詢到該值
- 如果
dir和key不存在,該命令會創建對應的項
更新鍵值:
[root@master etcd]# etcdctl update /test/key "test kubernetes cluster" test kubernetes cluster
[root@node1 etcd]# etcdctl get /test/key test kubernetes cluster
刪除鍵值:
[root@master etcd]# etcdctl rm /test/key PrevNode.Value: test kubernetes cluster
當鍵不存在時,會報錯 [root@node1 etcd]# etcdctl get /test/key Error: 100: Key not found (/test/key) [15]
etcd幫助:
[root@master etcd]# etcdctl help NAME: etcdctl - A simple command line client for etcd. WARNING: Environment variable ETCDCTL_API is not set; defaults to etcdctl v2. Set environment variable ETCDCTL_API=3 to use v3 API or ETCDCTL_API=2 to use v2 API. USAGE: etcdctl [global options] command [command options] [arguments...] VERSION: 3.2.22 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
參考文檔:
https://github.com/etcd-io/etcd
https://yq.aliyun.com/articles/623228
https://blog.csdn.net/hxpjava1/article/details/78275995
