一明刷、什么是ETCD
etcd是CoreOS團(tuán)隊(duì)于2013年6月發(fā)起的開源項(xiàng)目,它的目標(biāo)是構(gòu)建一個(gè)高可用的分布式鍵值(key-value)數(shù)據(jù)庫魁兼。etcd內(nèi)部采用raft協(xié)議作為一致性算法何恶,etcd基于Go語言實(shí)現(xiàn),號(hào)稱云原生分布式存儲(chǔ)的基石
官網(wǎng)地址:https://etcd.io/
/etc 是linux 操作系統(tǒng)的配置存儲(chǔ)目錄哼拔, d distributed分布式縮寫引有,簡單理解為分布式配置數(shù)據(jù)庫
CAP原理
也叫CAP原則,指的是在一個(gè)分布式系統(tǒng)中管挟,Consistency(一致性)轿曙、 Availability(可用性)、Partition tolerance(分區(qū)容錯(cuò)性)僻孝,最多只能同時(shí)三個(gè)特性中的兩個(gè)导帝,三者不可兼得。
CAP原理的提出主要是針對(duì)分布式場景穿铆,所以P是必須具備的您单。
分布式鍵值存儲(chǔ)系統(tǒng)對(duì)比
etcd | zookeeper | consul | NewSQL | |
---|---|---|---|---|
CAP | CP | CP | CP | CP |
開發(fā)語言 | go | java | go | C/C++ |
線性讀 | Y | N | N | 有時(shí)候 |
多版本并發(fā)控制 | Y | N | N | 有時(shí)候 |
事務(wù) | 數(shù)據(jù)內(nèi)容比較、讀或?qū)?/td> | 版本檢查荞雏,寫 | 數(shù)據(jù)內(nèi)容比較虐秦、鎖平酿、讀或?qū)?/td> | SQL式事務(wù) |
用戶權(quán)限 | RBAC | 訪問控制列表 | 訪問控制列表 | 每個(gè)數(shù)據(jù)庫的權(quán)限和每個(gè)表的授權(quán) |
數(shù)據(jù)更新通知 | 歷史和當(dāng)前健范圍 | 當(dāng)前鍵和目錄 | 當(dāng)前鍵(支持前綴) | 觸發(fā)器(有時(shí)候) |
http/json api | Y | N | Y | 很少 |
最大數(shù)據(jù)庫大小 | 幾GB | 幾百M(fèi)B到幾GB | 幾百M(fèi)B以上 | 幾TB |
最小線性讀時(shí)延 | 網(wǎng)絡(luò)RTT | 不支持線性讀 | 網(wǎng)絡(luò)RTT+fsync | 取決于系統(tǒng)和網(wǎng)絡(luò)時(shí)鐘 |
其實(shí)eureka專注于服務(wù)發(fā)現(xiàn),嚴(yán)格來說不算是分布式鍵值存儲(chǔ)系統(tǒng)
NewSQL 分布式關(guān)系型數(shù)據(jù)庫悦陋,主流有g(shù)oogle公司的Cloud Spanner蜈彼,CockroachDB(與PostgreSQL兼容的開源分布式SQL數(shù)據(jù)庫,由熟悉Google Cloud Spanner的前谷歌員工開發(fā))俺驶,ClustrixDB(現(xiàn)歸MariaDB所有幸逆,這個(gè)橫向擴(kuò)展的集群關(guān)系HTAP(混合事務(wù)/分析處理)數(shù)據(jù)庫采用無共享架構(gòu)設(shè)計(jì)。ClustrixDB主要與MySQL和MariaDB兼容)
總的來說暮现,每種系統(tǒng)都有其優(yōu)勢还绘,etcd的優(yōu)勢在于配置信息共享和方便運(yùn)維,etcd設(shè)計(jì)理念是設(shè)計(jì)成大規(guī)模分布式系統(tǒng)的通用底座栖袋,因此在云原生領(lǐng)域得到廣泛使用拍顷;Zookeeper優(yōu)勢在于穩(wěn)定性在大數(shù)據(jù)領(lǐng)域應(yīng)用很廣;Consul的優(yōu)勢在于服務(wù)發(fā)現(xiàn)塘幅。
二昔案、 實(shí)現(xiàn)原理
1.架構(gòu)圖
2.架構(gòu)解析
從 etcd 的架構(gòu)圖中我們可以看到,etcd 主要分為四個(gè)部分电媳。
- HTTP Server:用于處理用戶發(fā)送的 API 請(qǐng)求以及其集群節(jié)點(diǎn)之間數(shù)據(jù)通信爱沟。
- Store:涉及KV存儲(chǔ),WAL文件(預(yù)寫式日志)匆背,Snapshot管理等,用于處理 etcd 支持的各類功能的事務(wù)身冀,包括數(shù)據(jù)索引钝尸、節(jié)點(diǎn)狀態(tài)變更、監(jiān)控與反饋搂根、事件處理與執(zhí)行等珍促,是 etcd 對(duì)用戶提供的大多數(shù) API 功能的具體實(shí)現(xiàn)。
- Raft: etcd 的核心剩愧,是Raft 強(qiáng)一致性算法的具體實(shí)現(xiàn)猪叙。
- 復(fù)制狀態(tài)機(jī):抽象模塊的模塊,狀態(tài)機(jī)的數(shù)據(jù)維護(hù)在內(nèi)存中仁卷,定期持久化到磁盤穴翩,每次寫請(qǐng)求會(huì)持久化到WAL文件,并根據(jù)寫請(qǐng)求的內(nèi)容修改狀態(tài)機(jī)數(shù)據(jù)
3.數(shù)據(jù)讀寫過程
- 讀冉趸:由于集群所有節(jié)點(diǎn)數(shù)據(jù)都是強(qiáng)一致性的芒帕,讀取可以隨機(jī)讀取,leader和follow 都可以讀取
- 寫入:如果請(qǐng)求發(fā)到follow會(huì)轉(zhuǎn)發(fā)給leader丰介,由leader寫入背蟆,然后分發(fā)給follower
4.如何選舉
- 集群開始的時(shí)候鉴分,所有節(jié)點(diǎn)的角色都是Follower
- 當(dāng)節(jié)點(diǎn)在指定的時(shí)間沒有收到Leader 或者 Candidate的有效消息時(shí)會(huì)發(fā)起選舉投票,指定時(shí)間是選舉超時(shí)時(shí)間带膀,是一個(gè)隨機(jī)的值(防止多節(jié)點(diǎn)同時(shí)發(fā)起選舉志珍,Leader無法被選出),心跳時(shí)間比這個(gè)時(shí)間短
- 投票過程:
1. Follower 遞增Term
2. 自身狀態(tài)變成Candidate
3. 投票給自己
4.向集群其它節(jié)點(diǎn)發(fā)起投票請(qǐng)求(Request Vote)
當(dāng)超過集群一半節(jié)點(diǎn)都同意垛叨,狀態(tài)變成Leader伦糯,立即向集群所有其它節(jié)點(diǎn)發(fā)送心跳
當(dāng)發(fā)現(xiàn)其它Leader 節(jié)點(diǎn)并且Term不小于自己的term ,狀態(tài)變成Follow点额,否則丟棄消息
數(shù)據(jù)通道
Stream類型通道: 主要用于傳輸數(shù)據(jù)量較小的信息舔株,例如心跳、日志追加消息还棱,節(jié)點(diǎn)之間維護(hù)長連接
Pipeline 類型通道: 主要用于處理數(shù)據(jù)量大的信息载慈,比如snapshot,采用短連接珍手,與心跳等消息區(qū)分處理办铡,保證集群穩(wěn)定
三、 應(yīng)用場景
etcd的定位是通用的一致性key/value的存儲(chǔ)琳要,典型的應(yīng)用場景包括分布式數(shù)據(jù)庫寡具、服務(wù)注冊(cè)與發(fā)現(xiàn)、負(fù)載均衡稚补、分布式鎖童叠、分布式隊(duì)列、消息發(fā)布與訂閱课幕、分布式通知與協(xié)調(diào)厦坛、集群監(jiān)控與leader競選
四、 發(fā)展里程碑
etcd目前最新的是3.x版本乍惊,有3個(gè)重要里程碑版本杜秸,分別是etcd 0.4,etcd 2.0 和etcd 3.0润绎; etcd 0.4是對(duì)外發(fā)布的第一個(gè)穩(wěn)定版本撬碟,etcd2.0與etcd3.0版本差別比較,具體如下:
- v3版本采用gRPC+protobuf 取代 v2版本的Http+json的通訊方式莉撇,同時(shí)保留v2版本的方式呢蛤,提高整體吞吐率,降低時(shí)延
- v3采用磁盤數(shù)據(jù)庫代替v2 key-value內(nèi)存數(shù)據(jù)庫
- v3引入多版本的鍵空間(MVCC),支持訪問歷史版本key
- v3引入事務(wù)概念棍郎,etcd服務(wù)的多個(gè)請(qǐng)求合并成一個(gè)操作
- v3摒棄v2的key-value的層級(jí)和目錄顾稀,采用扁平的二進(jìn)制鍵空間
- v3更輕量級(jí)的基于租約(Lease)的key自動(dòng)過期機(jī)制,取代基于TTL的key過期機(jī)制
- v3 watch機(jī)制重新設(shè)計(jì)坝撑,采用基于http2的server push静秆,對(duì)事件進(jìn)行多路復(fù)用優(yōu)化
v2采用的是http長連接的事件驅(qū)動(dòng)機(jī)制
etcd v3 版本依然保留etcd v2的協(xié)議和api粮揉,同時(shí)提供一套v3的API,也就是說,兩個(gè)版本共享一套raft協(xié)議代碼的抚笔,在于api不同扶认,存儲(chǔ)不同,數(shù)據(jù)相互隔離殊橙,采用v2版本API 只能用v2版本的API辐宾,v3版本只能用v3 版本的API
五、 常用操作
1. 安裝部署
1) 單機(jī)部署
可以使用二進(jìn)制或源碼下載安裝膨蛮,但是需要自己寫配置文件叠纹,推薦使用yum安裝方式
hostnamectl set-hostname etcd-1
wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -ivh epel-release-latest-7.noarch.rpm
# yum 倉庫中的etcd版本為3.3.11,如果需要最新版本的etcd可以進(jìn)行二進(jìn)制安裝
yum -y install etcd #安裝
systemctl enable etcd
systemctl start etcd #啟動(dòng)
默認(rèn)配置文件vim /etc/etcd/etcd.conf
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_CLIENT_URLS="http://localhost:2379"
#ETCD_LISTEN_CLIENT_URLS="http://localhost:2379,http://xx.xx.xx.xx:2379" #如果需要其它機(jī)器訪問需要添加機(jī)器ip的url
ETCD_NAME="default"
ETCD_ADVERTISE_CLIENT_URLS="http://localhost:2379"
2) 集群部署
集群部署分靜態(tài)配置和服務(wù)發(fā)現(xiàn)敞葛,常用是靜態(tài)配置
靜態(tài)配置
1.三臺(tái)機(jī)器分別安裝etcd誉察,ip分別為172.16.0.1;172.16.0.2惹谐;172.16.0.3持偏;
yum install etcd -y
2.修改vim /etc/etcd/etcd.conf
#[Member]
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_CLIENT_URLS="http://172.16.0.1:2379" #對(duì)外提供服務(wù)地址
ETCD_LISTEN_PEER_URLS="http://172.16.0.1:2380" #監(jiān)聽的地址
ETCD_NAME="etcd1" # 節(jié)點(diǎn)名稱
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://172.16.0.1:2380" #該節(jié)點(diǎn)同伴監(jiān)聽地址,這個(gè)值會(huì)告訴集群中其他節(jié)點(diǎn)
ETCD_ADVERTISE_CLIENT_URLS="http://172.16.0.1:2379" #對(duì)外公告的該節(jié)點(diǎn)客戶端監(jiān)聽地址氨肌,同步給集群其它節(jié)點(diǎn)
ETCD_INITIAL_CLUSTER="etcd1=http://172.16.0.1:2380,etcd2=http://172.16.0.2:2380,etcd3=http://172.16.0.3:2380" # 集群中所有節(jié)點(diǎn)的信息
ETCD_INITIAL_CLUSTER_TOKEN="etcd-token" #每個(gè)集群唯一
ETCD_INITIAL_CLUSTER_STATE="new" #新建集群值為 new鸿秆;已經(jīng)存在的集群值為 existing
另外兩個(gè)機(jī)器配置記得替換IP 172.16.0.1 和etcd1 節(jié)點(diǎn)名稱
3.分別啟動(dòng)etcd服務(wù)
systemctl start etcd # 第一個(gè)節(jié)點(diǎn)啟動(dòng)會(huì)阻塞等待第二個(gè)節(jié)點(diǎn)啟動(dòng)
2. 訪問安全
etcd 默認(rèn)是沒有開啟訪問控制的,訪問安全包括用戶的認(rèn)證和授權(quán)怎囚,傳輸安全是指使用SSL/TLS來加密信道创南,本身證書也可以來做認(rèn)證
1) 基于身份驗(yàn)證的訪問控制
采用基于角色訪問控制(RBAC)
etcdctl user add root #首開添加root賬戶灾梦,才能開始認(rèn)證
etcdctl auth enable #開啟認(rèn)證 治笨,默認(rèn)有root角色夕土,擁有所有權(quán)限,授予root用戶
etcdctl role add test --user=root:pwd # 添加角色
etcdctl role grant-permission --from-key test read "" --user=root:pwd #角色授予所有key讀權(quán)限(read井誉,write,readwrite)
etcdctl user grant-role test test # 用戶test授予test角色
2) 基于證書的訪問控制開(支持雙向認(rèn)證)
#[Security]
ETCD_CERT_FILE="server.pem" #服務(wù)端證書
ETCD_KEY_FILE="server-key.pem" #
ETCD_CLIENT_CERT_AUTH="true" #是否開啟客戶端端證書認(rèn)證
ETCD_TRUSTED_CA_FILE="ca.pem" #客戶端服務(wù)器TLS授信的CA證書路徑整胃,
ETCD_AUTO_TLS="true" # 客戶端TLS是否使用自動(dòng)生成的證書
ETCD_PEER_CERT_FILE="peer.pem" #節(jié)點(diǎn)通訊采用的客戶端證書
ETCD_PEER_KEY_FILE="peer-key.pem"
ETCD_PEER_CLIENT_CERT_AUTH="true" #是否啟用peer客戶端證書認(rèn)證
ETCD_PEER_TRUSTED_CA_FILE="ca.pem" 服務(wù)端TLS授信的CA證書路徑
ETCD_PEER_AUTO_TLS="true" #是否使用自動(dòng)生成的證書
3颗圣、 常用命令
默認(rèn)安裝自帶etcdctl 命令行客戶端,分兩個(gè)版本ETCDCTL_API=2和ETCDCTL_API=3屁使,兩個(gè)版本不一樣在岂,操作的數(shù)據(jù)也不相容
以export ETCDCTL_API=3 為例
- help 查看所有命令集
etcdctl help
- put 命令
etcdctl put /test1 value1 #設(shè)置test1=value1
etcdctl put /test1 value2 # 存在直接覆蓋
etcdctl put /test1 value3 --lease=1234abc #綁定租賃id,租賃時(shí)間到期自動(dòng)刪除
etcdctl put /test1 value4 --ignore-lease # 使用當(dāng)前key的租賃
etcdctl put /test1 value5 --prev-kv #設(shè)置值蛮寂,并返回上一個(gè)版本的值
- get查看
etcdctl get /test1 #獲取key=/test1的值,返回key和value
etcdctl get "" --from-key #返回比空字符串大的key的鍵值對(duì)蔽午,該例返回所有數(shù)據(jù)
etcdctl get "dir" --prefix --keys-only --limit=5 # 返回"dir" 前綴的鍵最多5個(gè)
etcdctl get /test1 /test4 #獲取[/test1,/test4) 范圍的鍵值對(duì),左閉右開酬蹋,不包括/test4
etcdctl get /test1 --print-value-only #只返回值
etcdctl get /test1 --consistency='l' #獲取key=/test1的鍵值對(duì)及老,consistency 'l' 代表線性讀(執(zhí)行raft)抽莱, 's' 代表串行化讀
etcdctl get /test1 -w json #查看key=/test1的版本數(shù)據(jù),返回?cái)?shù)據(jù)如下:
#cluster_id:請(qǐng)求的etcd集群ID骄恶。
#member_id:請(qǐng)求的etcd節(jié)點(diǎn)ID食铐。
#revision:etcd服務(wù)端當(dāng)前全局?jǐn)?shù)據(jù)版本號(hào)。對(duì)任一key的put或delete操作都會(huì)使#revision自增1僧鲁。revision=1是etcd的保留版本號(hào)虐呻,因此用戶的key版本號(hào)將從2開始。
#raft_term:etcd當(dāng)前raft主節(jié)點(diǎn)任期號(hào)寞秃。
#create_revision:當(dāng)前key創(chuàng)建時(shí)全局?jǐn)?shù)據(jù)版本號(hào)revision的值斟叼。
#mod_revision:當(dāng)前key最后一次修改時(shí)全局?jǐn)?shù)據(jù)版本號(hào)revision的值。
#version:當(dāng)前key的數(shù)據(jù)版本號(hào)春寿。key創(chuàng)建時(shí)version為1朗涩,對(duì)當(dāng)前key進(jìn)行put操作會(huì)使version自增1,將key刪除后堂淡,重新創(chuàng)建馋缅,version又會(huì)從1開始計(jì)數(shù)
- del 命令
etcdctl del /test1 #刪除指定key
etcdctl del /test1 --prev-kv #返回刪除的鍵值對(duì)
etcdctl del /test --from-key # 刪除比/test大的所有key,也支持--prefix 按前綴刪除
- watch命令
etcdctl watch foo -- echo watch event received #watch key=foo 輸出指定文字
etchctl watch foo --rev=2 #從2版本開始watch绢淀,返回中間所有修改的版本
etcdctl watch foo -- sh -c "env | grep ETCD_WATCH_"
# PUT
# foo
# bar
# ETCD_WATCH_REVISION=11
# ETCD_WATCH_KEY="foo"
# ETCD_WATCH_EVENT_TYPE="PUT"
# ETCD_WATCH_VALUE="bar"
- lease 命令(租約)
etcdctl lease grant 10 #創(chuàng)建一個(gè)10s的租約萤悴,返回租約的id,用于綁定key
etcdctl lease revoke 1234abc #刪除id=1234abc 的租約
etcdctl lease timetolive 1234abc #查看id=1234abc 的租約剩余時(shí)間
etcdctl lease timetolive --keys 1234abc #查看id=1234abc 的租約剩余時(shí)間皆的,并顯示關(guān)聯(lián)的key
etcdctl lease keep-alive -- once 1234abc #一次續(xù)約id=1234abc 的租約覆履,并退出,不加--once 命令掛起费薄,到期自動(dòng)續(xù)約
etcdctl lease list #查看所有激活的租期
- member 命令(集群成員管理)
etcdctl member add newMember --peer-urls=https://127.0.0.1:12345
Member ced000fda4d05edf added to cluster 8c4281cc65c7b112
ETCD_NAME="newMember"
ETCD_INITIAL_CLUSTER="newMember=https://127.0.0.1:12345,default=http://10.0.0.30:2380"
ETCD_INITIAL_CLUSTER_STATE="existing"
etcdctl member update 2be1eb8f84b7f63e --peer-urls=https://127.0.0.1:11112
etcdctl member remove 2be1eb8f84b7f63e
etcdctl member list #查看集群列表
- endpoint 查看節(jié)點(diǎn)狀態(tài)
etcdctl endpoint status -w table #查看默認(rèn)節(jié)點(diǎn)狀態(tài)硝全,table格式輸出
etcdctl endpoint --cluster status -w table # 查看集群狀態(tài)
etcdctl endpoint --cluster hashkv -w json #查看集群hashkv
六、 集群故障處理
1. 數(shù)據(jù)備份
etcdctl snapshot save backup.db #數(shù)據(jù)備份到當(dāng)前目錄下backup.db
etcdctl -w table snapshot save backup.db
2. 數(shù)據(jù)恢復(fù)
etcdctl --data-dir=/var/lib/etcd/backup.etcd snapshot restore backup.db #恢復(fù)數(shù)據(jù)到新目錄
#每個(gè)節(jié)點(diǎn)恢復(fù)數(shù)據(jù)楞抡,然后修改配置指定新的數(shù)據(jù)目錄伟众,最后重啟所有節(jié)點(diǎn)
注意數(shù)據(jù)目錄權(quán)限,權(quán)限不夠召廷,提示不是很友好
3. 數(shù)據(jù)遷移
場景1 更換高性能盤
1.停掉etcd服務(wù)
2.高性能盤上創(chuàng)建新的數(shù)據(jù)目錄
3.copy舊數(shù)據(jù)文件到新數(shù)據(jù)目錄中
4.修改配置文件的數(shù)據(jù)目錄為新目錄凳厢,然后重啟服務(wù)
場景2 更換高性能物理機(jī)器,不停服切換
1.新的機(jī)器先安裝好etcd服務(wù)
2.先啟動(dòng)安裝好的一臺(tái)etcd竞慢,單獨(dú)起來先紫,然后查看etcd的member的ID
3.到原有的三臺(tái)etcd集群上,將第二部步中起來的etcd添加到集群(添加節(jié)點(diǎn)需要用到etcd的member ID 和peer-urls地址)
4.將原來三臺(tái)的etcd的ETCD_INITIAL_CLUSTER地址添加進(jìn)來筹煮,將ETCD_INITIAL_CLUSTER_STATE的new改為existing,刪除數(shù)據(jù)目錄遮精,重啟etcd
5.其它兩臺(tái)重復(fù)2-4步驟
6.確保新的三臺(tái)已加入集群且數(shù)據(jù)一致,然后把原有三臺(tái)剔除集群
運(yùn)行時(shí)的重配置都需要經(jīng)過兩個(gè)階段败潦,1.先通知集群新的配置本冲,采用member api 操作准脂,2.啟動(dòng)新的節(jié)點(diǎn),指定正確的initial-cluster眼俊,initial-cluster-state設(shè)置為existing意狠,新節(jié)點(diǎn)啟動(dòng)會(huì)校驗(yàn)initial-cluster與當(dāng)前集群的配置匹配
場景3 直接拿著etcd快照,進(jìn)行etcd集群恢復(fù)
1.獲取快照
2.先將新的三臺(tái)組成集群疮胖,啟動(dòng)起來
3.用etcd快照恢復(fù)到新目錄环戈,在三臺(tái)機(jī)器上都執(zhí)行
4.分別修改目錄配置到新目錄,最后重啟etcd