ETCD 简介 + 使用
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工具下载比通过谷歌下载慢,可能是我谷歌FQ的原因。
解压后的文件如下所示:
-
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的配置参数也可以通过命令行参数进行设置,但是命令行优美指定的参数优先级更高,同时存在时会覆盖环境变量对应的值。