etcd是一個開源的分佈式鍵值對數據庫,他的每個節點都有一份數據的copy,當有節點故障時保證了高可用性。etcd使用Raft算法來保證一致性。html
第一次接觸etcd是在學習k8s時。k8s用etcd作的服務發現。後來在開發一個分佈式系統時須要用到服務發現,就想試一下用etcd作服務發現。效果仍是很不錯的。node
這篇講一下etcd集羣的搭建和使用。linux
官方推薦的集羣個數爲奇數個,如圖當節點爲3個和爲4個時的容錯都是1, 節點5個和6個時,容錯爲2...git
集羣的節點越多,容錯性會越強,可是數據的同步份數也會越多,寫性能會變差一些。合理的集羣大小,就是平衡容錯性和可寫性。github
準備三臺服務器 redis
172.31.43.166 |
etcd0 |
172.31.43.114 |
etcd1 |
172.31.34.237 |
etcd2 |
分別在三臺服務器上下載etcd。這裏下載的是版本3.3.8算法
ETCD_VER=v3.3.8 GITHUB_URL=https://github.com/coreos/etcd/releases/download DOWNLOAD_URL=${GITHUB_URL} rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz rm -rf /tmp/etcd-download-test && mkdir -p /tmp/etcd-download-test curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/etcd-download-test --strip-components=1 rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz /tmp/etcd-download-test/etcd --version ETCDCTL_API=3 /tmp/etcd-download-test/etcdctl version
而後將兩個文件都放到系統可執行目錄 /usr/local/bin/ 或 /usr/bin/數據庫
cd /tmp/etcd-download-test
sudo cp etcd* /usr/local/bin/
建立一個文件夾用來保存etcd的數據api
sudo mkdir -p /data/etcd sudo chown -R root:$(whoami) /data/etcd sudo chmod -R a+rw /data/etcd
在這裏我使用static方式去搭建服務。服務器
編寫systemd服務文件,分別在每臺機器上編寫服務文件:
cat > /tmp/etcd0.service <<EOF
[Unit]
Description=etcd
Documentation=https://github.com/coreos/etcd
Conflicts=etcd.service
Conflicts=etcd2.service
[Service]
Type=notify
Restart=always
RestartSec=5s
LimitNOFILE=40000
TimeoutStartSec=0
ExecStart=/usr/local/bin/etcd --name etcd0 \
--data-dir /data/etcd \
--initial-advertise-peer-urls http://172.31.43.166:2380 \
--listen-peer-urls http://172.31.43.166:2380 \
--listen-client-urls http://172.31.43.166:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://172.31.43.166:2379 \
--initial-cluster-token etcd-cluster-pro \
--initial-cluster etcd0=http://172.31.43.166:2380,etcd1=http://172.31.43.114:2380,etcd2=http://172.31.34.237:2380 \
--initial-cluster-state new
[Install]
WantedBy=multi-user.target
EOF
sudo mv /tmp/etcd0.service /etc/systemd/system/etcd0.service
cat > /tmp/etcd1.service <<EOF
[Unit]
Description=etcd
Documentation=https://github.com/coreos/etcd
Conflicts=etcd.service
Conflicts=etcd2.service
[Service]
Type=notify
Restart=always
RestartSec=5s
LimitNOFILE=40000
TimeoutStartSec=0
ExecStart=/usr/local/bin/etcd --name etcd1 \
--data-dir /data/etcd \
--initial-advertise-peer-urls http://172.31.43.114:2380 \
--listen-peer-urls http://172.31.43.114:2380 \
--listen-client-urls http://172.31.43.114:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://172.31.43.114:2379 \
--initial-cluster-token etcd-cluster-pro \
--initial-cluster etcd0=http://172.31.43.166:2380,etcd1=http://172.31.43.114:2380,etcd2=http://172.31.34.237:2380 \
--initial-cluster-state new
[Install]
WantedBy=multi-user.target
EOF
sudo mv /tmp/etcd1.service /etc/systemd/system/etcd1.service
cat > /tmp/etcd2.service <<EOF [Unit] Description=etcd Documentation=https://github.com/coreos/etcd Conflicts=etcd.service [Service] Type=notify Restart=always RestartSec=5s LimitNOFILE=40000 TimeoutStartSec=0 ExecStart=/usr/local/bin/etcd -name etcd2 \ --data-dir /data/etcd \ --initial-advertise-peer-urls http://172.31.34.237:2380 \ --listen-peer-urls http://172.31.34.237:2380 \ --listen-client-urls http://172.31.34.237:2379,http://127.0.0.1:2379 \ --advertise-client-urls http://172.31.34.237:2379 \ --initial-cluster-token etcd-cluster-pro \ --initial-cluster etcd0=http://172.31.43.166:2380,etcd1=http://172.31.43.114:2380,etcd2=http://172.31.34.237:2380 \ --initial-cluster-state new [Install] WantedBy=multi-user.target EOF sudo mv /tmp/etcd2.service /etc/systemd/system/etcd2.service
下面是一些經常使用配置選項的說明:
--name:方便理解的節點名稱,默認爲 default,在集羣中應該保持惟一
--data-dir:服務運行數據保存的路徑,默認爲 ${name}.etcd
--snapshot-count:指定有多少事務(transaction)被提交時,觸發截取快照保存到磁盤
--heartbeat-interval:leader 多久發送一次心跳到 followers。默認值是 100ms
--eletion-timeout:從新投票的超時時間,若是follower在該時間間隔沒有收到心跳包,會觸發從新投票,默認爲 1000 ms
--listen-peer-urls:和同伴通訊的地址,好比 http://ip:2380,若是有多個,使用逗號分隔。須要全部節點都可以訪問,因此不要使用 localhost
--advertise-client-urls:對外公告的該節點客戶端監聽地址,這個值會告訴集羣中其餘節點
--listen-client-urls:對外提供服務的地址:好比 http://ip:2379,http://127.0.0.1:2379,客戶端會鏈接到這裏和etcd交互
--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;不然會致使多個集羣之間的衝突,形成未知的錯誤
全部以--init開頭的配置都是在第一次啓動etcd集羣的時候纔會用到,後續節點的重啓會被忽略,如--initial-cluseter參數。因此當成功初始化了一個etcd集羣之後,就再也不須要這個參數或環境變量了。
若是服務已經運行過就要把修改 --initial-cluster-state 爲existing
啓用服務
sudo systemctl daemon-reload sudo systemctl enable etcd0.service sudo systemctl start etcd0.service sudo systemctl daemon-reload sudo systemctl enable etcd1.service sudo systemctl start etcd1.service sudo systemctl daemon-reload sudo systemctl enable etcd2.service sudo systemctl start etcd2.service
查看 log:
sudo systemctl status etcd0.service -l --no-pager sudo journalctl -u etcd0.service -l --no-pager|less sudo journalctl -f -u etcd0.service sudo systemctl status etcd1.service -l --no-pager sudo journalctl -u etcd1.service -l --no-pager|less sudo journalctl -f -u etcd1service sudo systemctl status etcd2.service -l --no-pager sudo journalctl -u etcd2.service -l --no-pager|less sudo journalctl -f -u etcd2.service
暫停
sudo systemctl stop etcd0.service
sudo systemctl disable etcd0.service
sudo systemctl stop etcd1.service
sudo systemctl disable etcd1.service
sudo systemctl stop etcd2.service
sudo systemctl disable etcd2.service
我使用的etcd的api爲v3版本。在使用命令時須要在前面加上ETCDCTL_API=3
如:查看集羣成員
ETCDCTL_API=3 etcdctl member list
能夠看到有3個節點在線
集羣狀態
ETCDCTL_API=3 etcdctl --endpoints 172.31.43.166:2379,172.31.34.237:2379,172.31.43.114:2379 endpoint status --write-out="table"
使用put和get命令能夠保存和獲得數據.del刪除數據
ETCDCTL_API=3 etcdctl put test1 a ETCDCTL_API=3 etcdctl put test2 b ETCDCTL_API=3 etcdctl put test3 c ETCDCTL_API=3 etcdctl get --prefix test
ETCDCTL_API=3 etcdctl get --from-key ""
watch 會監聽key的變更 有變更時會在輸出。這也正是服務發現須要使用的。
咱們監聽 test鍵,而後對test執行修改和刪除操做
ETCDCTL_API=3 etcdctl watch test
ETCDCTL_API=3 etcdctl put test abcde ETCDCTL_API=3 etcdctl put test aaaa ETCDCTL_API=3 etcdctl del test
etcd能夠爲key設置超時時間,但與redis不一樣,etcd須要先建立lease,而後使用put命令加上參數–lease=<lease ID>
ETCDCTL_API=3 lease grant ttl 建立lease,返回lease ID ttl秒
ETCDCTL_API=3 lease revoke leaseId 刪除lease,並刪除全部關聯的key
ETCDCTL_API=3 lease timetolive leaseId 取得lease的總時間和剩餘時間
ETCDCTL_API=3 lease keep-alive leaseId keep-alive會不間斷的刷新lease時間,從而保證lease不會過時。
使用lock命令後加鎖名稱 作分佈式鎖,若是沒有顯示釋放鎖,其餘地方只能等待。
etcdctl --endpoints=$ENDPOINTS lock mutex1 # 在另外一個終端輸入 etcdctl --endpoints=$ENDPOINTS lock mutex1