服务发现-从原理到实现 (5)

在服务提供者列表发生变化时,能得到通知

其中第一点可以通过

zoo_get_children(handle, path, 1, children);

来获取列表,那么如何在服务提供者列表发生变化时得到通知呢? 这就用到了zookeeper中的watcher机制。

watcher目的是在 znode 以某种方式发生变化时得到通知。watcher仅被触发一次。 如果您想要重复通知,您将需要重新注册观察者。 读取操作(例如exists、get_children、get_data)可能会创建监视。

okeeper中的watcher机制,不在本文的讨论范围内,有兴趣的读者,可以去查阅相关书籍或者资料。

下面,我们对使用zookeeper作为注册中心,服务提供者和消费者需要做的操作进行下简单的总结:

服务提供者

在服务启动的时候,使用zookeeper的客户端,创建一个临时(Ephemeral)节点

服务消费者

通过zoo_get_children获取子节点

注册watcher回调,在path下发生变化时候,会直接调用该回调函数,在回调函数内重新获取子节点,并重新注册回调

etcd

服务发现-从原理到实现

Etcd是基于Go语言实现的一个KV结构的存储系统,支持服务注册与发现的功能,官方将其定义为一个可信赖的分布式键值存储服务,主要用于共享配置和服务发现。其特点如下:

:安装配置简单,而且提供了 HTTP API 进行交互,使用也很简单 键值对存储:

据存储在分层组织的目录中,如同在标准文件系统中

变更:监测特定的键或目录以进行更改,并对值的更改做出反应

:根据官方提供的 benchmark 数据,单实例支持每秒 2k+ 读操作

:采用 Raft 算法,实现分布式系统数据的可用性和一致性

服务注册

每一个服务器启动之后,会向Etcd发起注册请求,同时将自己的基本信息发送给 etcd 服务器。服务器的信息是通过KV键值进行存储。key 是用户真实的 key, value 是对应所有的版本信息。keyIndex 保存 key 的所有版本信息,每删除一次都会生成一个 generation,每个 generation 保存了这个生命周期内从创建到删除中间的所有版本号。

更新数据时,会开启写事务。

会根据当前版本的key,rev在 keyindex 中查找是否有当前 key 版本的记录。主要获取 created 与 ver 的信息。

生成新的 KeyValue 信息。

更新 keyindex 记录。

健康检查

在注册时,会初始化一个心跳周期 ttl 与租约周期 lease。服务器需要在心跳周期之内向 etcd 发送数据包,表示自己能够正常工作。如果在规定的心跳周期内,etcd 没有收到心跳包,则表示该服务器异常,etcd 会将该服务器对应的信息进行删除。如果心跳包正常,但是服务器的租约周期结束,则需要重新申请新的租约,如果不申请,则 etcd 会删除对应租约的所有信息。

在 etcd 中,并不是在磁盘中删除对应的 keyValue 信息,而是对其进行标记删除。

首先在 delete 中会生成一个 ibytes,对其追加标记,表示这个 revision 是 delete。

生成一个 KeyValue,该 KeyValue 只包含Key的信息。

同时修改 Tombstone 标志位,结束当前生命周期,生成一个新的 generation,更新 kvindex。

再次需要做个说明,因为笔者是从事c++开发的,现在线上业务用的zookeeper来作为注册中心实现服务发现功能。上半年的时候,也曾想转到etcd上,但是etcd对c++并不友好,笔者用了将近两周时间各种调研,编译,发现竟然不能将其编译成为一个静态库...

需要特别说明的是,用的是etcd官网推荐的c++客户端etcd-cpp-apiv3

纵使etcd功能再强大,不能支持c++,算是一个不小的遗憾。对于笔者来说,算是个损失吧,希望后续能够支持。

下面是etcd c++ client 不支持静态库,作者以及其他使用者的反馈,以此作为本章节的结束。

etcd官网指定的c++client

etcd官网指定的c++client

作者回复

作者回复

使用者反馈

使用者反馈

5结语

微服务架构模式下,服务实例动态配置,因此服务消费者需要动态了解到服务提供者的变化,所以必须使用服务发现机制。

服务发现的关键部分是注册中心。注册中心提供注册和查询功能。目前业界开源的有Netflix Eureka、Etcd、Consul或Apache Zookeeper,大家可以根据自己的需求进行选择。

服务发现主要有两种发现模式:客户端发现和服务端发现。客户端发现模式要求客户端负责查询注册中心,获取服务提供者的列表信息,使用负载均衡算法选择一个合适的服务提供者,发送请求。服务端发现模式,客户端每次都请求注册中心,由注册中心内部选择一个合适的服务提供者,并将请求转发至该服务提供者,需要注意的是 当一个请求过来的时候,注册中心内部获取服务提供者列表和使用负载均衡算法。

这个世界没有完美的架构和模式,不同的场景都有适合的解决方案。我们在调研决策的时候,一定要根据实际情况去权衡对比,选择最适合当前阶段的方案,然后通过渐进迭代的方式不断完善优化方案。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwwdsd.html