(转载)服务发现系统etcd介绍

  • 服务发现系统etcd介绍

最近在折腾服务发现系统,在这之前折腾过一段时间CoreOS,那时候就接触etcd了,不过当时只是把etcd看做一个K/V存储系统来使用的,觉得和redis没什么区别,后来才知道etcd主要也是用于服务发现的。etcd 的灵感来自于 ZooKeeper 和 Doozer,侧重于:
简单:支持 curl 方式的用户 API (HTTP+JSON)
安全:可选 SSL 客户端证书认证
快速:单实例可达每秒 1000 次写操作
可靠:使用 Raft 实现分布式
etcd是用Go语言编写的,使用raft一致性算法来管理高可用日志。etcdctl是一个简单的命令行工具,使用起来就和curl一样。etcd已经托管在github上了,我们下载一个稳定版的(0.4.6),不要下载0.5.0版本,0.5.0是基于开发版的,在折腾kubernetes的时候直接下载的0.5.0,可被坑惨了。部署环境还是三台ubuntu14.04机器,都是部署在/opt/etcd目录下
192.168.1.100  Docker-1  server
192.168.1.101  Docker-2  client
192.168.1.102  Docker-3  client
我们先在Docker-1上练练手,首先安装etcd,etcd用Go语言编写,安装时需要go环境,我这三台机器运行Docker,go环境都已经部署ok了,所以直接编译即可
cd /opt/etcd
./build
执行完上述命令后,会在源码目录发现生成了一个bin目录,里面有两个文件bench、etcd。先在我们来启动etcd
./bin/etcd



etcd启动后,会监听在4001端口,用来和client进行通讯,而监听的7001端口则是服务端和服务端之间进行通讯的端口。下面我们来设置一个key
#set
curl http://127.0.0.1:4001/v2/keys/guol -XPUT -d value='test etcd'
#get
curl http://127.0.0.1:4001/v2/keys/guol



操作起来很简单,现在我们已经启动了一个单节点的etcd服务,并且初步尝试了etcd的api,下面我们看看一些具体的内容。
etcd api
etcd的api系统是一个空间层次分明的系统,key space是由目录和密钥构成的。我们先启动一个etcd系统,并查看该etcd的版本
#start
./bin/etcd -data-dir /tmp/etcd/ -name Docker-1
#get version
curl  http://127.0.0.1:4001/version
在启动etcd时,多了两个参数,-data-dir指定etcd系统存储etcd配置、日志和快照的目录,-name该节点在集群中的名称。
接下来,我们设置第一对K/V,key=message1,value='hello world'
curl -s http://127.0.0.1:4001/v2/keys/message1 -XPUT -d value='hello world'



我们看看返回的对象都包含了哪些值:action,action反映当前请求的模式(get/set/delete),因为当前的请求是通过HTTP的PUT方法修改节点的值,所以action是set。node对象中有四个元素:node.key,HTTP请求设置的key名称,etcd使用类似文件系统的结构来表示K/V对,所以所有的key前面都以'/'开头。node.value,设置的key的值。node.createdIndex,一个唯一的索引,在每次etcd变更时一个单调递增的整数,这个特性可以反映出etcd系统已经创建了多少个key,你可以看到索引的值是8,那是因为之前我已经插入了几对K/V值了,在etcd有变更后,也有一些内部命令在幕后做一些变更,例如增加或者同步servers。node.modifiedIndex,和node.createdIndex很像,该属性也是一个索引,set、delete、update、create、compareAndSwap、compareAndDelete等动作都会引起value值的改变,get、watch动作不会引起已经存储的值的改变,因此这两个特性不会改变node.modifiedIndex的值。
获取一个key的值,我们获取key(message1)的值
curl -s http://127.0.0.1:4001/v2/keys/message1

你也可以用HTTP的PUT方法改变一个key的值,我们改变message1的value为'hello etcd'
curl -s http://127.0.0.1:4001/v2/keys/message1 -XPUT -d value='hello etcd'



这次我们看到返回值中多了一个prevNode属性,prevNode属性根据名称一看就知道是返回的该key在改变前的值,prevNode的格式和node一样,你也会看到index都会递增。
我们也可以用HTTP的DELETE方法删除一个key,我们删除key(message1)
curl -s http://127.0.0.1:4001/v2/keys/message1 -XDELETE



这时候再查看message1的值会发现已经没有该key了

你也可以在etcd系统中给key设置一个过期时间,只需要在设置key时加上一个ttl参数即可
curl -s http://127.0.0.1:4001/v2/keys/message2 -XPUT -d value='hello etcd' -d ttl=5



看到设置的message2的生存期只有5s,过期后会自动删除。在node的输出中多了一个expiration属性,该属性提示多久后key会过期并被删除。ttl属性显示key的ttl值。后面多余的输出是使用以下命令测试的:
curl -s http://127.0.0.1:4001/v2/keys/message2 -XPUT -d value='hello etcd' -d ttl=5|jq .;echo 'sleep....';sleep 6;curl -s http://127.0.0.1:4001/v2/keys/message2 |jq .
我们也可以监视key的变更,在key有改变后,我们会收到相关通知。在调用HTTP请求时,提供wait=true参数,即可监控一个key。
#窗口1
curl -s http://127.0.0.1:4001/v2/keys/message2 -XPUT -d value='hello etcd 1'
curl -s http://127.0.0.1:4001/v2/keys/message2?wait=true
新开一个终端,执行以下命令
curl -s http://127.0.0.1:4001/v2/keys/message2 -XPUT -d value='hello etcd 2'
再看看窗口1有什么变化


自动的创建顺序key,在一个目录中使用POST方法,你可以创建一些key,使key的名字看起来是顺序的,执行以下测试命令:
curl -s http://127.0.0.1:4001/v2/keys/message3 -XPOST -d value='hello etcd 1'
curl -s http://127.0.0.1:4001/v2/keys/message4 -XPUT -d value='hello etcd 1'
curl -s http://127.0.0.1:4001/v2/keys/message5 -XPUT -d value='hello etcd 1'
curl -s http://127.0.0.1:4001/v2/keys/message3 -XPOST -d value='hello etcd 2' | jq .



可以看到我们已经针对message3这个key使用了POST方法,在插入两个新key之后,再次更新message3的value,发现messages3在etcd中的key已经变了(key/index),下面我们看看message3这个key中到底存储什么信息,为了使输出的key是顺序的,我们加了sorted参数
curl -s 'http://127.0.0.1:4001/v2/keys/message3?recursive=true&sorted=true'

可以看到存有message3的历史值记录,在某些情况下,需要自动创建key的目录,但在某些情况下,你希望创建或者删除一个目录。创建一个目录就像创建key一样简单,但是你不能提供一个value,而是要增加一个参数dir=true
curl -s http://127.0.0.1:4001/v2/keys/message7 -XPUT -d dir=true



看到没有value属性,而是多了一个dir属性。有创建目录的需求,就有删除目录的需求,我们现在删除刚刚创建的message7目录,和删除key的方法一样,也是使用HTTP的DELETE方法,只不过要再添加一个dir=true参数
curl -s 'http://127.0.0.1:4001/v2/keys/message7?dir=true' -XDELETE



如果director里面已经包含keys了,则必须增加recursive=true参数
curl -s 'http://127.0.0.1:4001/v2/keys/message7?recursive=true' -XDELETE
在etcd系统中,我们可以存储两种类型的东西:keys和directors。keys存储的是单个字符值,directors存储的是一组keys或者存储其他directors。下面我们创建一个key(message_key),在创建该key之前,我们先看看etcd系统已经存在哪些key了,要查看整个系统的key,只要增加recursive=true参数即可。
curl -s http://127.0.0.1:4001/v2/keys/?recursive=true



因为我已经清空etcd系统了,现在创建key:message_key
curl -s http://127.0.0.1:4001/v2/keys/message_key -XPUT -d value='this is a key'



创建directory:message_directory
curl -s http://127.0.0.1:4001/v2/keys/message_directory -XPUT -d dir=true



现在我们看看整个etcd系统中有多少key
curl -s http://127.0.0.1:4001/v2/keys/?recursive=true



可以看到整个etcd中只有一个key和一个directory,现在我们在message_directory目录下面创建一个key(message_key)
curl -s http://127.0.0.1:4001/v2/keys/message_directory/message_key -XPUT -d value='this is a key in directory'



我们现在看看etcd系统都有哪些key了
curl -s http://127.0.0.1:4001/v2/keys/?recursive=true

可以看到整个etcd中有一个key和一个directory,而directory中又包含了一个key。
如何创建一个隐藏的节点(隐藏key/隐藏directory),我们创建一个隐藏key时使用'_'作为key的前缀即可,当你发送HTTP GET请求时,隐藏key并不会被显示出来
curl -s http://127.0.0.1:4001/v2/keys/_message -XPUT -d value='a hidden key'



etcd系统中也可以存储一些小的配置文件、json文档、xml文档等等。
curl -s http://127.0.0.1:4001/v2/keys/file -XPUT --data-urlencode value@upfile



etcd会跟踪一些集群使用的统计信息,比如带宽、启动时间之类的。
Leader Statistics:leader有查看整个etcd集群视图的能力,而且会跟踪两个有趣的统计信息:到集群中同等机器的延迟和rafr rpc请求失败和成功的数量。
curl -s http://127.0.0.1:4001/v2/stats/leader



Self Statistics:每个节点内部的统计信息
curl -s http://127.0.0.1:4001/v2/stats/self



Store Statistics:存储统计信息包含了在该节点上的所有操作信息
curl -s http://127.0.0.1:4001/v2/stats/store

如何查询集群的配置
curl -s http://192.168.1.100:7001/v2/admin/config



看看整个集群中有多少成员
curl -s http://192.168.1.100:7001/v2/admin/machines



在集群中删除Docker-2节点
curl -s http://192.168.1.100:7001/v2/admin/machines/Docker-2 -XDELETE
再次查看整个集群的成员


etcd节点的配置文件可以有三种设置方法:命令行、环境变量、配置文件,命令行优先级最高,环境变量的又高于配置文件。

下面我们看看etcd的命令都支持哪些命令行参数:
Options:
  --version         显示版本号
  -f -force         强制使用新的配置文件
  -config=<path>    指定配置文件的路径
  -name=<name>      该节点在etcd集群中显示的名称
  -data-dir=<path>  etcd数据的存储路径
  -cors=<origins>   Comma-separated list of CORS origins.
  -v                开启verbose logging.
  -vv               开启very verbose logging.

Cluster Configuration Options:
  -discovery=<url>                Discovery service used to find a peer list.
  -peers-file=<path>              包含节点信息的文件列表
  -peers=<host:port>,<host:port>  逗号分割的节点列表,这些节点应该匹配节点的-peer-addr标记指定的信息

Client Communication Options:
  -addr=<host:port>         客户端进行通讯的公共地址端口
  -bind-addr=<host[:port]>  监听的地址端口,用来进行客户端通讯
  -ca-file=<path>           客户端CA文件路径
  -cert-file=<path>         客户端cert文件路径
  -key-file=<path>          客户端key文件路径

Peer Communication Options:
  -peer-addr=<host:port>  节点间进行通讯的地址端口
  -peer-bind-addr=<host[:port]>  监听的地址端口,节点间来进行通讯
  -peer-ca-file=<path>    节点CA文件路径
  -peer-cert-file=<path>  节点cert文件路径
  -peer-key-file=<path>   节点key文件路径
  -peer-heartbeat-interval=<time> 心跳检测的时间间隔,单位是毫秒
  -peer-election-timeout=<time> 节点选举的超时时间,单位是毫秒

Other Options:
  -max-result-buffer   结果缓冲区的最大值
  -max-retry-attempts  节点尝试重新加入集群的次数
  -retry-interval      Seconds to wait between cluster join retry attempts.
  -snapshot=false      禁止log快照
  -snapshot-count      发布快照前执行的事物次数
  -cluster-active-size 集群中的活跃节点数
  -cluster-remove-delay 多少秒之后再删除集群中的节点
  -cluster-sync-interval 在备模式下,两次同步之间的时间差
配置文件方式,etcd默认从/etc/etcd/etcd.conf读取配置
addr = "127.0.0.1:4001"
bind_addr = "127.0.0.1:4001"
ca_file = ""
cert_file = ""
cors = []
cpu_profile_file = ""
data_dir = "."
discovery = "http://etcd.local:4001/v2/keys/_etcd/registry/examplecluster"
http_read_timeout = 10.0
http_write_timeout = 10.0
key_file = ""
peers = []
peers_file = ""
max_cluster_size = 9
max_result_buffer = 1024
max_retry_attempts = 3
name = "default-name"
snapshot = true
verbose = false
very_verbose = false

[peer]
addr = "127.0.0.1:7001"
bind_addr = "127.0.0.1:7001"
ca_file = ""
cert_file = ""
key_file = ""

[cluster]
active_size = 9
remove_delay = 1800.0
sync_interval = 5.0

posted @ 2015-12-17 16:03  Take-off.Wang  阅读(960)  评论(0编辑  收藏  举报