服务发现是微服务化架构中重要的一环,服务的配置信息需要有一种可靠高效的发现机制,保证服务上线时可以及时被使用,服务失效中断时可以及时切走。服务发现工具Etcd就是为了这种需求开发的。
Etcd是一个分布式KV数据库,通过将数据分散存储在多台独立的设备上,从而提高数据的可靠性或读写性能。Etcd是几个比较常见的服务发现应用之一,它支持TTL的支持和HTTP Restful API,同时通过Raft一致性算法处理日志复制以保证强一致性。关于Raft算法,请参考 这篇文章 ,这里不多介绍。Etcd本来就是CoreOS团队开发支持的,因此也是原生存在在CoreOS系统中。
Etcd中提供了订阅通知机制,同时提供了一个线上服务 https://discovery.etcd.io/
,这个服务可以用于发现集群中的机器。比如Fleet等等工具也是基于Etcd去发现网络中的节点服务器。在CoreOS机器部署之后,系统中一个叫做 cloud-init
的服务会根据之前的 user-data
文件去启动Etcd。Etcd会更新对应的自己的节点信息,并且获取其它的节点信息。
另外比较常见的服务发现还有ZooKeeper(应用最广泛)、Consul等等,如果有兴趣,可以自己在进行研究。
工具 etcdctl
是 etcd
的控制程序,我们可以通过执行命令查看所有键值:
core@core-01 ~ $ etcdctl ls / --recursive /coreos.com /coreos.com/network /coreos.com/network/config /coreos.com/network/subnets /coreos.com/network/subnets/10.1.64.0-24 /coreos.com/network/subnets/10.1.48.0-24 /coreos.com/network/subnets/10.1.10.0-24 /coreos.com/updateengine /coreos.com/updateengine/rebootlock /coreos.com/updateengine/rebootlock/semaphore
还可以通过类似Redis的 get
等命令获取具体存储内容:
core@core-01 ~ $ etcdctl get /coreos.com/network/subnets/10.1.64.0-24 {"PublicIP":"172.17.8.101"}
区别是Etcd是支持目录的:
core@core-01 ~ $ etcdctl mkdir hello core@core-01 ~ $ etcdctl get hello /hello: is a directory core@core-01 ~ $ etcdctl rmdir hello
刚刚我们介绍时也提到,Etcd支持HTTP方式调用,比如:
core@core-01 ~ $ curl -L -X PUT http://127.0.0.1:2379/v2/keys/message -d value="Hello" {"action":"set","node":{"key":"/message","value":"Hello","modifiedIndex":10318,"createdIndex":10318},"prevNode":{"key":"/message","value":"Hello","modifiedIndex":10300,"createdIndex":10300}} core@core-01 ~ $ etcdctl get /message Hello core@core-01 ~ $ curl -L -X DELETE http://127.0.0.1:2379/v2/keys/message {"action":"delete","node":{"key":"/message","modifiedIndex":10462,"createdIndex":10318},"prevNode":{"key":"/message","value":"Hello","modifiedIndex":10318,"createdIndex":10318}} core@core-01 ~ $ etcdctl get /message Error: 100: Key not found (/message) [10467]
TTL的特性可以在设置状态时进行设定:
etcdctl set /foo "Expiring Soon" --ttl 20
这个KV对就会在20秒内时效。
除了本身的KV数据库特性外,作为集群服务发现工具时,也可以通过restful api方式发现当前集群信息:
core@core-01 ~ $ curl -L http://127.0.0.1:4001/v2/stats/leader {"leader":"efb737dfdc9ee528","followers":{"6219cfe16536320":{"latency":{"current":0.003561,"average":0.0031178274017212987,"standardDeviation":0.018016615756979302,"minimum":9e-06,"maximum":1.338917},"counts":{"fail":0,"success":51588}},"a8cc28a8e121c40d":{"latency":{"current":0.002212,"average":0.002837358092138387,"standardDeviation":0.015615452604769925,"minimum":1.7e-05,"maximum":1.48721},"counts":{"fail":0,"success":51618}},"e44ee28dd4e590ac":{"latency":{"current":0.001838,"average":0.006247004906804689,"standardDeviation":0.4458222893241591,"minimum":9e-06,"maximum":105.637627},"counts":{"fail":32,"success":58694}}}} core@core-01 ~ $ curl -L http://127.0.0.1:4001/v2/stats/self {"name":"c99fef8aac9b4a3e9d3a44f58b0739a6","id":"efb737dfdc9ee528","state":"StateLeader","startTime":"2016-05-28T09:44:01.416629553Z","leaderInfo":{"leader":"efb737dfdc9ee528","uptime":"1h59m14.023315023s","startTime":"2016-05-28T09:44:44.495996231Z"},"recvAppendRequestCnt":0,"sendAppendRequestCnt":162816,"sendPkgRate":20.004570208101516,"sendBandwidthRate":1953.7463493742348}
其它的系列集群接口,也可以在 官方文档 中查看。
如果你有印象在第一篇中,如果你打开 user-data
文件,你就会发现Etcd的踪影:
➜ coreos-vagrant git:(master) cat user-data #cloud-config --- coreos: etcd2: advertise-client-urls: http://$public_ipv4:2379 initial-advertise-peer-urls: http://$private_ipv4:2380 listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001 listen-peer-urls: http://$private_ipv4:2380,http://$private_ipv4:7001 discovery: https://discovery.etcd.io/xxxxxxxxxxxx fleet: public-ip: "$public_ipv4" flannel: interface: "$public_ipv4" ....
我们这里使用了线上服务 https://discovery.etcd.io/
发现集群中的机器,这个服务同样也可以使用本地内系统。
之前提到,Etcd的特性非常方便用做服务发现,具体如何操作呢?在谈具体实现之前,我们来介绍一下两种服务注册方法:一种叫做 自注册方法 ;另外一种叫 第三方注册方法 。区别是是否由自身来进行健康检查和提醒。另外,服务发现重要的是,在服务失效时可以及时去除无效服务,这个在Etcd的TTL功能上就会显得比较重要。我们可以设置一个键值的有效期为3秒,并且每秒钟都来刷新授权,如果程序异常退出或者刷新不及时,那么这个服务简直就会失效。通过这种方式就可以有效验证服务是否有效。
具体的代码就不再额外给出了,大家可以自己动手实现一下。另外,其实服务发现还有一个重要的是提供自身工作的地址端口信息,这些可以通过环境变量传递到容器的注册过程中去,这个也是能够让负载均衡或者WebService服务器可以识别服务的重要手段。比如Nginx可以在根据服务注册信息定期更新自己的配置文件,利用重载保证不间断的服务运行。