1. 背景
本文并不介绍服务发现的基本原理。除了一致性算法之外,其他并没有太多高深的算法,网上的资料很容易让大家明白上面是服务发现。
想直接查看结论的同学,请直接跳到文末。
目前,市面上有非常多的服务发现工具,《 Open-Source Service Discovery》一文中列举了如下开源的服务发现工具。
Name | Type | AP or CP | Language | Dependencies | Integration |
Zookeeper | General | CP | Java | JVM | Client Binding |
Doozer | General | CP | Go | | Client Binding |
Etcd | General | Mixed (1) | Go | | Client Binding/HTTP |
SmartStack | Dedicated | AP | Ruby | haproxy/Zookeeper | Sidekick (nerve/synapse) |
Eureka | Dedicated | AP | Java | JVM | Java Client |
NSQ (lookupd) | Dedicated | AP | Go | | Client Binding |
Serf | Dedicated | AP | Go | | Local CLI |
Spotify (DNS) | Dedicated | AP | N/A | Bind | DNS Library |
SkyDNS | Dedicated | Mixed (2) | Go | | HTTP/DNS Library |
(1) If using the consistent parameter, inconsistent reads are possible
(2) If using a caching DNS client in front of SkyDNS, reads could be inconsistent
上面表格中,前三个是通用的,后面都是各大公司自己造的轮子,应用范围并不广,我也就不深入研究了。
此外,这篇文章是 14 年写的,当时它并没有研究 Consul,放到表格中,Consul 则应该是 General、CP、Go、No dependency、Http/DNS Library。
截止到今天,除了容器编排框架 k8s、istio/envoy 自己实现了服务发现机制(他们也兼容第三方的服务发现工具),似乎也没有其他的知名的服务发现框架出现了。
下面我就 zookeeper、etcd、consul 这三款进行下比较。
2. 比较
2.1. Zookeeper
ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. All of these kinds of services are used in some form or another by distributed applications. Each time they are implemented there is a lot of work that goes into fixing the bugs and race conditions that are inevitable. Because of the difficulty of implementing these kinds of services, applications initially usually skimp on them ,which make them brittle in the presence of change and difficult to manage. Even when done correctly, different implementations of these services lead to management complexity when the applications are deployed.
官网这么介绍 zookeeper 的,翻译过来,zookeeper 的功能有:
- 作为配置信息的存储的中心服务器
- 命名服务
- 分布式同步
- 分组服务
能看出,zookeeper 并不只是作为服务发现框架使用的,它非常庞大。
如果只是打算将 zookeeper 作为服务发现工具,就需要用到其配置存储和分布式同步的功能。前者可以理解成具有一致性的 kv 存储,后者提供了 zookeeper 特有的 watcher 注册于异步通知机制,zookeeper 能将节点的状态实时异步通知给 zookeeper 客户端。
2.2. Zookeeper 使用
Zookeeper 的使用流程如下:
- 确保有所选语言的 sdk,理论上 github 上第三方的库有一些,仔细筛选一下应该可以用。
- 调用 zookeeper 接口连接 zookeeper 服务器。
- 注册自身服务
- 通过 watcher 获取监听服务的状态
- 服务提供者需自行保持与 zookeeper 服务器的心跳。
《 [Zookeeper C API 指南]()》写了八篇文章介绍了如何使用 zookeeper 的 c 语言 api。
总得来说,zookeeper 需要胖客户端,每个客户端都需要通过其 sdk 与 zookeeper 服务保活,增加了编写程序的复杂性。此外,还提供 api 实现服务注册与发现逻辑,需要服务的消费者实现服务提供者存活的检测。
2.3. Etcd
Etcd 是一个采用 http 协议的分布式键值对存储系统,因其易用,简单。很多系统都采用或支持 etcd 作为服务发现的一部分,比如 kubernetes。但正事因为其只是一个存储系统,如果想要提供完整的服务发现功能,必须搭配一些第三方的工具。
比如配合 etcd、Registrator、confd 组合,就能搭建一个非常简单而强大的服务发现框架。但这种搭建操作就稍微麻烦了点,尤其是相对 consul 来说。所以 etcd 大部分场景都是被用来做 kv 存储,比如 kubernetes。
2.4. Consul
相较于 etcd、zookeeper,consul 最大的特点就是:它整合了用户服务发现普遍的需求,开箱即用,降低了使用的门槛,并不需要任何第三方的工具。代码实现上也足够简单。
Consul has multiple components, but as a whole, it is a tool for discovering and configuring services in your infrastructure. It provides several key features:
- Service Discovery
- Health Checking
- KV Store
- Multi Datacenter
展开了说,consul 的功能有:
- 通过 DNS 或 HTTP,应用能轻易地找到它们依赖的系统
- 提供了多种健康检查方式:http 返回码 200,内存是否超限,tcp 连接是否成功
- kv 存储,并提供 http api
- 多数据中心,这点是 zookeeper 所不具备的。
2.5. Consul 使用
相比于 zookeeper 的服务发现使用,consul 并不需要专门的 sdk 集成到服务中,因此它不限制任何语言的使用。我们看看 consul 一般是怎么使用的。
- 每台服务器上都要安装一个 consul agent。
- consul agent 支持通过配置文件注册服务,或者在服务中通过 http 接口来注册服务。
- 注册服务后,consul agent 通过指定的健康检查方式,定期检查服务是否存活。
- 如果服务想查询其他服务的存活状态,只需要与本机的 consul agent 发起一次 http 请求或者 dns 请求即可。
简单点说,consul 的使用不依赖任何 sdk,依靠简单的 http 请求就能满足服务发现的所有逻辑。
不过,服务每次都从 consul agent 获取其他服务的存活状态,相比于 zookeeper 的 watcher 机制,实时性稍差一点,需考虑如何尽可能提高实时性,问题不会很大。
3. 总结
名称 | 优点 | 缺点 | 接口 | 一致性算法 |
zookeeper | 1.功能强大,不仅仅只是服务发现 2.提供 watcher 机制能实时获取服务提供者的状态 3.dubbo 等框架支持 | 1.没有健康检查 2.需在服务中集成 sdk,复杂度高 3.不支持多数据中心 | sdk | Paxos |
consul | 1.简单易用,不需要集成 sdk 2.自带健康检查 3.支持多数据中心 4.提供 web 管理界面 | 1.不能实时获取服务信息的变化通知 | http/dns | Raft |
etcd | 1.简单易用,不需要集成 sdk 2.可配置性强 | 1.没有健康检查 2.需配合第三方工具一起完成服务发现 3.不支持多数据中心 | http | Raft |
为了以后支持多数据中心,同时为了快速支持不同的语言比如 nodejs、python 服务,我会选择 consul 作为我们的服务发现框架,但是实时获取服务信息变化通知的问题需尽可能减小。