CoreOS 折腾笔记(三)了解 Etcd

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

什么是 Etcd?

Etcd 是一个分布式 KV 数据库,通过将数据分散存储在多台独立的设备上,从而提高数据的可靠性或读写性能。Etcd 是几个比较常见的服务发现应用之一,它支持 TTL 的支持和 HTTP Restful API,同时通过 Raft 一致性算法处理日志复制以保证强一致性。关于 Raft 算法,请参考 这篇文章,这里不多介绍。Etcd 本来就是 CoreOS 团队开发支持的,因此也是原生存在在 CoreOS 系统中。

Etcd 中提供了订阅通知机制,同时提供了一个线上服务

Fleet 等等工具也是基于 Etcd 去发现网络中的节点服务器。在 CoreOS 机器部署之后,系统中一个叫做 ```cloud-init``` 的服务会根据之前的 ```user-data``` 文件去启动 Etcd。Etcd 会更新对应的自己的节点信息,并且获取其它的节点信息。
1
2
3
4
5
6

另外比较常见的服务发现还有 ZooKeeper(应用最广泛)、Consul 等等,如果有兴趣,可以自己在进行研究。

## Etcdctl 使用

工具 ```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

1
2

还可以通过类似 Redis 的 ```get``` 等命令获取具体存储内容:

core@core-01 ~ $ etcdctl get /coreos.com/network/subnets/10.1.64.0-24
{“PublicIP”:”172.17.8.101”}

1
2

区别是 Etcd 是支持目录的:

core@core-01 ~ $ etcdctl mkdir hello
core@core-01 ~ $ etcdctl get hello
/hello: is a directory
core@core-01 ~ $ etcdctl rmdir hello

1
2

刚刚我们介绍时也提到,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]

1
2

TTL 的特性可以在设置状态时进行设定:

etcdctl set /foo “Expiring Soon” –ttl 20

1
2
3
4
5
6

这个 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}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

其它的系列集群接口,也可以在 [官方文档](https://coreos.com/etcd/docs/latest/) 中查看。

## Etcd 配置

如果你有印象在第一篇中,如果你打开 ```user-data``` 文件,你就会发现 Etcd 的踪影:

```yaml
➜ 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 可以在根据服务注册信息定期更新自己的配置文件,利用重载保证不间断的服务运行。