CoreOS 折腾笔记(三)了解 Etcd

服务发现是微服务化架构中重要的一环,服务的配置信息需要有一种可靠高效的发现机制,保证服务上线时可以及时被使用,服务失效中断时可以及时切走。服务发现工具 Etcd 就是为了这种需求开发的。

什么是 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 使用

工具 etcdctletcd 的控制程序,我们可以通过执行命令查看所有键值:

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 秒内时效。

Etcd 集群管理

除了本身的 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}

其它的系列集群接口,也可以在 官方文档 中查看。

Etcd 配置

如果你有印象在第一篇中,如果你打开 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 的特性非常方便用做服务发现,具体如何操作呢?在谈具体实现之前,我们来介绍一下两种服务注册方法:一种叫做 自注册方法;另外一种叫 第三方注册方法。区别是是否由自身来进行健康检查和提醒。另外,服务发现重要的是,在服务失效时可以及时去除无效服务,这个在 Etcd 的 TTL 功能上就会显得比较重要。我们可以设置一个键值的有效期为 3 秒,并且每秒钟都来刷新授权,如果程序异常退出或者刷新不及时,那么这个服务简直就会失效。通过这种方式就可以有效验证服务是否有效。

具体的代码就不再额外给出了,大家可以自己动手实现一下。另外,其实服务发现还有一个重要的是提供自身工作的地址端口信息,这些可以通过环境变量传递到容器的注册过程中去,这个也是能够让负载均衡或者 WebService 服务器可以识别服务的重要手段。比如 Nginx 可以在根据服务注册信息定期更新自己的配置文件,利用重载保证不间断的服务运行。

Built with Hugo
Theme Stack designed by Jimmy