这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天
服务注册与发现
微服务服务于分布式系统,是个分散式系统。服务部署跨主机、网段、机房乃至大区。各个服务之间通过RPC(remote procedure call)进行调用。
服务发现
- Register 服务启动时候进行注册
- Query 查询已注册服务信息
- Healthy Check 确认服务状态是否健康
注册模式
服务发现机制需要维护一份可用的服务列表,其中包含服务注册与移除功能,以及健康检查。服务注册模式主要包括两种:
- 自注册模式
自注册,顾名思义,就是上述这些动作,由服务(client)本身来维护。每个服务启动后,需要到统一的服务注册中心进行注册登记,服务正常终止后,也可以到注册中心移除自身的注册记录。在服务执行过程中,通过不断的发送心跳信息,来通知注册中心,本服务运行正常。注册中心只要超过一定的时间没有收到心跳消息,就可以将这个服务状态判断为异常,进而移除该服务的注册记录。
- 三方注册模式
这个模式与自注册模式相比,区别就是健康检查的动作不是由服务本身(client)来负责,而是由其它第三方服务来确认。有时候服务自身发送心跳信息的方式并不精确,因为可能服务本身已经存在故障,某些接口功能不可用,但仍然可以不断的发送心跳信息,导致注册中心没有发觉该服务已经异常,从而源源不断的将流量打到已经异常的服务上来。
发现模式
服务发现的发现机制主要包括三种
- 服务提供者:服务启动时将服务信息注册到注册中心,服务退出时将注册中心的服务信息删除掉。
- 服务消费者:从服务注册表获取服务提供者的最新网络位置等服务信息,维护与服务提供者之间的通信。
- 注册中心:服务提供者和服务消费者之间的一个桥梁。
注册中心提供管理和查询服务注册信息的API。当服务提供者的实例发生变更时(新增/删除服务),服务注册表更新最新的状态列表,并将其最新列表以适当的方式通知给服务消费者。目前大多数的微服务框架使用Netflix Eureka、Etcd、Consul或Apache Zookeeper等作为注册中心。
发现模式主要有以下两种:
- 客户端发现模式
- 服务端发现模式
客户端模式与服务端模式,两者的本质区别在于,客户端是否保存服务列表信息。
客户端发现模式
在客户端模式下,如果要进行微服务调用,首先要进行的是到服务注册中心获取服务列表,然后再根据调用端本地的负载均衡策略,进行服务调用。
在上图中,client端提供了负载均衡的功能,其首先从注册中心获取服务提供者的列表,然后通过自身负载均衡算法,选择一个最合理的服务提供者进行调用。
- 服务提供者向注册中心进行注册,提交自己的相关信息
- 服务消费者定期从注册中心获取服务提供者列表
- 服务消费者通过自身的负载均衡算法,在服务提供者列表里面选择一个合适的服务提供者,进行访问
服务端发现模式
在服务端模式下,调用方直接向服务注册中心进行请求,服务注册中心通过自身负载均衡策略,对微服务进行调用。这个模式下,调用方不需要在自身节点维护服务发现逻辑以及服务注册信息。
- 服务提供者向注册中心进行服务注册
- 注册中心提供负载均衡功能
- 服务消费者去请求注册中心,由注册中心根据服务提供列表的健康情况,选择合适的服务提供者供消费者调用
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。