etcd簡介
etcd是一個高可用的分布式鍵值(key-value)數據庫。etcd內部采用raft協議作為一致性算法,etcd基於Go語言實現。
etcd是一個服務發現系統,具備以下的特點:
簡單:安裝配置簡單,而且提供了HTTP API進行交互,使用也很簡單
安全:支持SSL證書驗證
快速:根據官方提供的benchmark數據,單實例支持每秒2k+讀操作
可靠:采用raft算法,實現分布式系統數據的可用性和一致性
etcd應用場景
用於服務發現,服務發現(ServiceDiscovery)要解決的是分布式系統中最常見的問題之一,即在同一個分布式集群中的進程或服務如何才能找到對方並建立連接。
要解決服務發現的問題,需要具備下面三種必備屬性。
- 一個強一致性、高可用的服務存儲目錄。
基於Ralf算法的etcd天生就是這樣一個強一致性、高可用的服務存儲目錄。
一種注冊服務和健康服務健康狀況的機制。
- 用戶可以在etcd中注冊服務,並且對注冊的服務配置key TTL,定時保持服務的心跳以達到監控健康狀態的效果。
- 一種查找和連接服務的機制。
通過在etcd指定的主題下注冊的服務業能在對應的主題下查找到。為了確保連接,我們可以在每個服務機器上都部署一個proxy模式的etcd,這樣就可以確保訪問etcd集群的服務都能夠互相連接。
etcd安裝
etcd在生產環境中一般推薦集群方式部署。在這里,主要講講單節點安裝和基本使用。
因為etcd是go語言編寫的,安裝只需要下載對應的二進制文件,並放到合適的路徑就行。
下載軟件包
-
$ wget https: //github.com/coreos/etcd/releases/download/v3.1.5/etcd-v3.1.5-linux-amd64.tar.gz
-
$ tar xzvf etcd -v3.1.5-linux-amd64.tar.gz
-
$ mv etcd -v3.1.5-linux-amd64 /opt/etcd
這里可以嘗試直接打開https://github.com/coreos/etcd/releases/download/v3.1.5/etcd-v3.1.5-linux-amd64.tar.gz 進行下載,經測試利用git工具下載比通過谷歌下載慢,可能是我谷歌翻牆的原因。
解壓后的文件如下所示:
-
root @rice:/opt/etcd# ls
-
Documentation etcd etcdctl README-etcdctl.md README.md READMEv2-etcdctl.md
其中etcd是server端,etcdctl是客戶端,操作之后會生成一個default.etcd,主要用來存儲etct數據。
啟動一個單節點的etcd服務,只需要運行etcd命令就行。不過有可能會出現以下問題:
-
root @rice:/opt/etcd# ./etcd
-
bash: ./etcd: 權限不夠
這個時候需要提高文件的權限,采用如下方法:
root@rice:/opt/etcd# chmod 777 etcd
再次啟動etcd,成功后可以看見以下提示:
-
root@rice:/opt/etcd # ./etcd
-
2017-08-02 10:41:26.241044 I | etcdmain: etcd Version: 3.1.5
-
2017-08-02 10:41:26.241150 I | etcdmain: Git SHA: 20490ca
-
2017-08-02 10:41:26.241170 I | etcdmain: Go Version: go1.7.5
-
2017-08-02 10:41:26.241187 I | etcdmain: Go OS/Arch: linux/amd64
-
2017-08-02 10:41:26.241205 I | etcdmain: setting maximum number of CPUs to 4, total number of available CPUs is 4
-
2017-08-02 10:41:26.241230 W | etcdmain: no data-dir provided, using default data-dir ./default.etcd
-
2017-08-02 10:41:26.241730 I | embed: listening for peers on http://localhost:2380
-
2017-08-02 10:41:26.241883 I | embed: listening for client requests on localhost:2379
-
2017-08-02 10:41:26.246016 I | etcdserver: name = default
-
2017-08-02 10:41:26.246058 I | etcdserver: data dir = default.etcd
-
2017-08-02 10:41:26.246078 I | etcdserver: member dir = default.etcd/member
-
2017-08-02 10:41:26.246095 I | etcdserver: heartbeat = 100ms
-
2017-08-02 10:41:26.246110 I | etcdserver: election = 1000ms
-
2017-08-02 10:41:26.246127 I | etcdserver: snapshot count = 10000
-
2017-08-02 10:41:26.246153 I | etcdserver: advertise client URLs = http://localhost:2379
-
2017-08-02 10:41:26.246173 I | etcdserver: initial advertise peer URLs = http://localhost:2380
-
2017-08-02 10:41:26.246201 I | etcdserver: initial cluster = default=http://localhost:2380
-
2017-08-02 10:41:26.252215 I | etcdserver: starting member 8e9e05c52164694d in cluster cdf818194e3a8c32
-
2017-08-02 10:41:26.252400 I | raft: 8e9e05c52164694d became follower at term 0
-
2017-08-02 10:41:26.252455 I | raft: newRaft 8e9e05c52164694d [peers: [], term: 0, commit: 0, applied: 0, lastindex: 0, lastterm: 0]
-
2017-08-02 10:41:26.252492 I | raft: 8e9e05c52164694d became follower at term 1
-
2017-08-02 10:41:26.268040 I | etcdserver: starting server... [version: 3.1.5, cluster version: to_be_decided]
-
2017-08-02 10:41:26.268837 I | etcdserver/membership: added member 8e9e05c52164694d [http://localhost:2380] to cluster cdf818194e3a8c32
-
2017-08-02 10:41:26.553047 I | raft: 8e9e05c52164694d is starting a new election at term 1
-
2017-08-02 10:41:26.553127 I | raft: 8e9e05c52164694d became candidate at term 2
-
2017-08-02 10:41:26.553144 I | raft: 8e9e05c52164694d received MsgVoteResp from 8e9e05c52164694d at term 2
-
2017-08-02 10:41:26.553159 I | raft: 8e9e05c52164694d became leader at term 2
-
2017-08-02 10:41:26.553170 I | raft: raft.node: 8e9e05c52164694d elected leader 8e9e05c52164694d at term 2
-
2017-08-02 10:41:26.553336 I | etcdserver: setting up the initial cluster version to 3.1
-
2017-08-02 10:41:26.555447 N | etcdserver/membership: set the initial cluster version to 3.1
-
2017-08-02 10:41:26.555481 I | etcdserver/api: enabled capabilities for version 3.1
-
2017-08-02 10:41:26.555506 I | embed: ready to serve client requests
-
2017-08-02 10:41:26.555636 I | etcdserver: published {Name:default ClientURLs:[http://localhost:2379]} to cluster cdf818194e3a8c32
-
2017-08-02 10:41:26.555852 N | embed: serving insecure client requests on 127.0.0.1:2379, this is strongly discouraged!
從上面的輸出中,我們可以看到很多信息。以下是幾個比較重要的信息:
2017-08-02 10:41:26.246016 I | etcdserver: name = default
name表示節點名稱,默認為default。
2017-08-02 10:41:26.246058 I | etcdserver: data dir = default.etcd
data-dir 保存日志和快照的目錄,默認為當前工作目錄default.etcd/目錄下。
2017-08-02 10:41:26.246201 I | etcdserver: initial cluster = default=http://localhost:2380
在http://localhost:2380和集群中其他節點通信。
2017-08-02 10:41:26.246153 I | etcdserver: advertise client URLs = http://localhost:2379
在http://localhost:2379提供HTTP API服務,供客戶端交互。
2017-08-02 10:41:26.246095 I | etcdserver: heartbeat = 100ms
heartbeat為100ms,該參數的作用是leader多久發送一次心跳到followers,默認值是100ms。
2017-08-02 10:41:26.246110 I | etcdserver: election = 1000ms
election為1000ms,該參數的作用是重新投票的超時時間,如果follow在該時間間隔沒有收到心跳包,會觸發重新投票,默認為1000ms。
2017-08-02 10:41:26.246127 I | etcdserver: snapshot count = 10000
snapshot count為10000,該參數的作用是指定有多少事務被提交時,觸發截取快照保存到磁盤。
集群和每個節點都會生成一個uuid。
啟動的時候會運行raft,選舉出leader。
采用這種方式啟動的etcd只是一個程序,如果啟動etcd的窗口被關閉的話則etcd便會被關閉
,所以如果要長期使用的話最好是為etcd開啟一個服務,此處便不提供開啟服務的方法,如果有需要讀者可以自行百度。
打開另一個窗口輸入:
root@rice:/opt/etcd# ./etcd -version
- 1
可以看到etcd等的版本信息
-
etcd Version: 3.1.5
-
Git SHA: 20490ca
-
Go Version: go1.7.5
-
Go OS/Arch: linux/amd64
那么etcd如何使用呢?
etcd廠商為我們提供提供了一個命令行客戶端—etcdctl,供用戶直接跟etcd服務打交道,而無需基於 HTTP API方式。可以方便我們在對服務進行測試或者手動修改數據庫內容。
etcdctl支持的命令大體上分為數據庫操作和非數據庫操作兩類。
可以使用 ./etcdctl -h 查看etcdctl的用法:
-
root@rice:/opt/etcd # ./etcdctl -h 查看etcdctl的用法:
-
NAME:
-
etcdctl - A simple command line client for etcd.
-
-
USAGE:
-
etcdctl [ global options] command [command options] [arguments...]
-
-
VERSION:
-
3.1.5
-
-
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
-
-
GLOBAL OPTIONS:
-
--debug output cURL commands which can be used to reproduce the request
-
--no-sync don't synchronize cluster information before sending request
-
--output simple, -o simple output response in the given format (simple, `extended` or `json`) (default: "simple")
-
--discovery-srv value, -D value domain name to query for SRV records describing cluster endpoints
-
--insecure-discovery accept insecure SRV records describing cluster endpoints
-
--peers value, -C value DEPRECATED - "--endpoints" should be used instead
-
--endpoint value DEPRECATED - "--endpoints" should be used instead
-
--endpoints value a comma-delimited list of machine addresses in the cluster (default: "http://127.0.0.1:2379,http://127.0.0.1:4001")
-
--cert-file value identify HTTPS client using this SSL certificate file
-
--key-file value identify HTTPS client using this SSL key file
-
--ca-file value verify certificates of HTTPS-enabled servers using this CA bundle
-
--username value, -u value provide username[:password] and prompt if password is not supplied.
-
--timeout value connection timeout per request (default: 2s)
-
--total-timeout value timeout for the command execution (except watch) (default: 5s)
-
--help, -h show help
-
--version, -v print the version
數據庫操作圍繞對鍵值和目錄的CRUD完整生命周期的管理。
etcd在鍵的組織上采用了層次化的空間結構(類似於文件系統中目錄的概念),用戶指定的鍵可以為單獨的名字,如:testkey,此時實際上放在根目錄/下面,也可以為指定目錄結構,如/cluster1/node2/testkey,則將創建相應的目錄結構。
set
指定某個鍵的值。
-ttl ‘0’ 該鍵值的超時時間(單位為秒),不配置(默認為0)則永不超時
–swap-with-value value 若該鍵現在的值是value,則進行設置操作
–swap-with-index ‘0’ 若該鍵現在的索引值是指定索引,則進行設置操作get
獲取指定鍵的值
例如:
-
root@rice:/opt/etcd# ./etcdctl set --ttl '5' key "Hello world"
-
Hello world
-
root@rice:/opt/etcd# ./etcdctl get key
-
Hello world
-
root@rice:/opt/etcd# ./etcdctl get key
-
Error: 100: Key not found (/key) [14]
-
第一個get是5秒內的操作,第二get是5秒后的操作,此刻key的值已經消失了。
update
對指定鍵進行修改
–ttl ‘0’ 超時時間(單位為秒),不配置(默認為 0)則永不超時。
-
root @rice:/opt/etcd# ./etcdctl update key "Hello world2"
-
Hello world2
-
root @rice:/opt/etcd# ./etcdctl get key
-
Hello world2
rm
刪除某個鍵值。
–dir 如果鍵是個空目錄或者鍵值對則刪除
–recursive 刪除目錄和所有子鍵
–with-value 檢查現有的值是否匹配
–with-index ‘0’檢查現有的index是否匹配
例如
-
root@rice:/opt/etcd # ./etcdctl rm key
-
PrevNode.Value: Hello world2
-
root@rice:/opt/etcd # ./etcdctl get key
-
Error: 100: Key not found (/key) [17]
mk
如果給定的鍵不存在,則創建一個新的鍵值。
–ttl ‘0’ 超時時間(單位為秒),不配置(默認為 0)。則永不超時
例如:
-
root @rice:/opt/etcd# ./etcdctl mk /test/key "Hello world"
-
Hello world
當鍵存在的時候,執行該命令會報錯,例如:
-
root @rice:/opt/etcd#./etcdctl mk /testdir/testkey "Hello world"
-
Error: 105: Key already exists (/testdir/testkey) [8]
mkdir
–ttl ‘0’ 超時時間(單位為秒),不配置(默認為0)則永不超時。
如果給定的鍵目錄不存在,則創建一個新的鍵目錄。
例如:
root@rice:/opt/etcd#./etcdctl mkdir dir2
- 1
當鍵目錄存在的時候,執行該命令會報錯,例如:
-
root @rice:/opt/etcd#./etcdctl mkdir dir2
-
Error: 105: Key already exists (/dir2) [9]
setdir
創建一個鍵目錄。如果目錄不存在就創建,如果目錄存在更新目錄TTL。
–ttl ‘0’ 超時時間(單位為秒),不配置(默認為0)則永不超時。
例如:
root@rice:/opt/etcd#./etcdctl setdir dir3
- 1
updatedir
更新一個已經存在的目錄。
–ttl ‘0’ 超時時間(單位為秒),不配置(默認為0)則永不超時。
例如:
root@rice:/opt/etcd#./etcdctl updatedir dir2
- 1
rmdir
刪除一個空目錄,或者鍵值對。
例如:
-
root @rice:/opt/etcd#./etcdctl setdir dir2
-
root @rice:/opt/etcd#./etcdctl rmdir dir2
若目錄不空會報錯,例如:
-
root @rice:/opt/etcd#./etcdctl set /dir/key hi
-
hi
-
root @rice:/opt/etcd#./etcdctl rmdir /dir
-
Error: 108: Directory not empty (/dir) [17]
ls
列出目錄(默認為根目錄)下的鍵或者子目錄,默認不顯示子目錄中內容。
–sort 將輸出結果排序
–recursive 如果目錄下有子目錄,則遞歸輸出其中的內容
-p 對於輸出為目錄,在最后添加/進行區分
例如:
-
root @rice:/opt/etcd#./etcdctl ls
-
/dir
-
/dir2
-
/dir
例如:
-
root @rice:/opt/etcd#./etcdctl ls dir
-
/dir/key
非數據庫操作,非數據庫操作包括:備份、監測、節點管理等
backup
備份etcd的數據。
–data-dir etcd的數據目錄
–backup-dir 備份到指定路徑
例如:
root@rice:/opt/etcd#./etcdctl backup --data-dir default.etcd --backup-dir /xx/xx
- 1
watch
監測一個鍵值的變化,一旦鍵值發生更新,就會輸出最新的值並退出。
–forever 一直監測直到用戶按CTRL+C退出
–after-index ‘0’ 在指定index之前一直監測
–recursive 返回所有的鍵值和子鍵值
例如:用戶更新key鍵值為test。
-
root @rice:/opt/etcd#./etcdctl set key "Hello world"
-
Hello world
-
root @rice:/opt/etcd#./etcdctl watch key
如圖,窗口一直在監控
當我開啟另一窗口,更新key的值后:
之前的監控界面便打印出test,然后退出,如圖:
exec-watch
監測一個鍵值的變化,一旦鍵值發生更新,就執行給定命令。
–after-index ‘0’ 在指定 index 之前一直監測
–recursive 返回所有的鍵值和子鍵值
例如:采用exec-watch設置如果key值被更新則啟動ls命令:
root@rice:/opt/etcd# ./etcdctl exec-watch key -- sh -c 'ls'
- 1
當我在另一個窗口update key的值之后,監控的窗口打印出以下數據,且監控不會退出:
-
root@rice:/opt/etcd # ./etcdctl exec-watch key -- sh -c 'ls'
-
default .etcd etcd README-etcdctl.md READMEv2-etcdctl.md
-
Documentation etcdctl README .md
-
default .etcd etcd README-etcdctl.md READMEv2-etcdctl.md
-
Documentation etcdctl README .md
有興趣的可以試試,哈哈哈!
root@rice:/opt/etcd# ./etcdctl exec-watch key -- sh -c './etcdctl update key '5''
- 1
member
list 列出etcd實例
add 添加etcd實例
remove 刪除etcd實例
查看集群中存在的節點,例如:
-
root @rice:/opt/etcd# ./etcdctl member list
-
8e9e05c52164694d: name=default peerURLs=http://localhost:2380 clientURLs=http://localhost:2379 isLeader=true
刪除集群中存在的節點,例如:
-
root @rice:/opt/etcd# ./etcdctl member remove 8e9e05c52164694d
-
Removed member 8e9e05c52164694d from cluster
向集群中新加節點,例如:
-
root @rice:/opt/etcd# ./etcdctl member add etcd3 http://192.168.1.100:2380
-
Added member named etcd3 with ID 8e9e05c52164694d to cluster
針對以上配置參數做些解釋:
-
ETCD_NAME :ETCD的節點名,在集群中應該保持唯一,可以使用 hostname。
-
ETCD_DATA_DIR:ETCD的數據存儲目錄,服務運行數據保存的路徑,默認為 ${name}.etcd。
-
ETCD_SNAPSHOT_COUNTER:多少次的事務提交將觸發一次快照,指定有多少事務(transaction)被提交時,觸發截取快照保存到磁盤。
-
ETCD_HEARTBEAT_INTERVAL:ETCD節點之間心跳傳輸的間隔,單位毫秒,leader 多久發送一次心跳到 followers。默認值是 100ms。
-
ETCD_ELECTION_TIMEOUT:該節點參與選舉的最大超時時間,單位毫秒,重新投票的超時時間,如果 follow 在該時間間隔沒有收到心跳包,會觸發重新投票,默認為 1000 ms。
-
ETCD_LISTEN_PEER_URLS:該節點與其他節點通信時所監聽的地址列表,多個地址使用逗號隔開,其格式可以划分為scheme://IP:PORT,這里的scheme可以是http、https。和同伴通信的地址,比如 http://ip:2380 ,如果有多個,使用逗號分隔。需要所有節點都能夠訪問,所以不要使用 localhost。
-
ETCD_LISTEN_CLIENT_URLS:該節點與客戶端通信時監聽的地址列表,對外提供服務的地址:比如 http://ip:2379,http://127.0.0.1:2379 ,客戶端會連接到這里和 etcd 交互
-
ETCD_INITIAL_ADVERTISE_PEER_URLS:該成員節點在整個集群中的通信地址列表,這個地址用來傳輸集群數據的地址。因此這個地址必須是可以連接集群中所有的成員的。該節點同伴監聽地址,這個值會告訴集群中其他節點。
-
ETCD_INITIAL_CLUSTER:配置集群內部所有成員地址,其格式為:ETCD_NAME=ETCD_INITIAL_ADVERTISE_PEER_URLS,如果有多個使用逗號隔開,集群中所有節點的信息,格式為 node1=http://ip1:2380 ,node2=http://ip2:2380 ,…。注意:這里的 node1 是節點的 –name 指定的名字;后面的 ip1:2380 是 –initial-advertise-peer-urls 指定的值
-
ETCD_ADVERTISE_CLIENT_URLS:廣播給集群中其他成員自己的客戶端地址列表
-
ETCD_INITIAL_CLUSTER_STATE:新建集群的時候,這個值為new;假如已經存在的集群,這個值為 existing。
-
ETCD_INITIAL_CLUSTER_TOKEN:初始化集群token,創建集群的token,這個值每個集群保持唯一。這樣的話,如果你要重新創建集群,即使配置和之前一樣,也會再次生成新的集群和節點 uuid;否則會導致多個集群之間的沖突,造成未知的錯誤。
注意:所有ETCD_MY_FLAG的配置參數也可以通過命令行參數進行設置,但是命令行優美指定的參數優先級更高,同時存在時會覆蓋環境變量對應的值。