1.1 服务发现架构
在微服务的服务治理中,服务发现占据着非常重要的地位。由于微服务架构中的微服务实例众多,且上下游实例经常会随着服务流量的变化进行扩缩容,因此需要一套服务发现机制来保证上下游服务随时都能调到安全可靠的接口
一个标准的服务发现架构主要由三部分组成,分别是服务注册中心,服务调用者,服务提供者,其相关交互如下图所示
其中服务注册中心为此架构的关键设备,由于下游的服务提供者众多,且处于一个动态变化的过程,因此需要服务调用者去服务注册中心中去进行服务订阅,从而获取一个下游服务的地址及端口,同时,如果下游服务发生变动,服务注册中心也会及时将服务变更信息同步给服务调用者
服务调用者即为客户端,服务提供者即为服务端,因此服务发现也有着两种主要的服务发现方式:客户端发现和服务端发现
客户端发现:此方式是客户端通过查询服务注册中心,获取可用服务的地址,然后进行访问,此方案的优点为架构简单,扩展灵活,方便实现负载均衡功能,缺点为强耦合,有一定开发成本。
服务端发现:此方式不是客户端去主动查询,而是客户端向中间负载均衡设备发送请求,然后由负载均衡设备去向服务注册中心去获取服务地址,此方案对客户端无感知,但是需要维护高可用的负载均衡设备
同时,服务注册也有两种方式,一种是自己注册,一种是第三方注册
自己注册,即服务实例自己主动去注册中心进行注册和注销,该方法的优点是非常简单,不需要任何其他辅助组件,缺点是各个服务和注册中心的耦合度比较高
第三方注册是服务本身不关心注册和注销功能,而是通过其他组件来实现服务注册功能,可以通过如事件订阅等方式来监控服务的状态,如果发现一个新的服务实例运行,就向注册中心注册该服务,如果监控到某一服务停止了,就向注册中心注销该服务。
1.2 常见的服务组件
目前的主流服务发现组件主要有3种,分别是Consul,Zookeeper,Etcd
1.2.1 Zookeeper
Zookeeper是一个常用的分布式组件,在分布式系统中通常被用于配置管理、名字服务,分布式锁等方向。
用Zookeeper来实现服务发现主要是使用Zookeeper的临时节点,通过这些临时节点来实现基本的服务注册功能和基本的健康检查功能,当服务实例启动就会在Zookeeper中注册一个临时节点,同时,如果服务实例发生故障或下线的时候,该临时节点就会被Zookeeper自动删除,如果有其他服务依赖这个服务可以设置监听该服务实例对应的临时节点,当临时节点被删除时,依赖该服务的其他服务会获得通知。依赖Zookeeper自身的高可用及临时节点提供的健康检查和监听机制来实现具备容错能力的服务发现机制。
在 实际开发过程中,通常建议使用Apache Curator来替代Zookeeper原生客户端库,Apache Curator通过封装Zookeeper原生API,提供更高抽象层次API让Zookeeper使用起来更加容易和可靠,而且提供专用于实现服务发现的API。
1.2.2 Etcd
Etcd是一个基于Raft共识算法具备线性强一致性(linearizable)的Key-Value存储系统,可以为每个Key设置TTL(time to live),当TTL过后相应Key会自动过期失效。基于Etcd构建服务发现解决方案将Etcd作为服务注册中心,服务实例注册就是在Etcd中构建一个Key-Value记录,由服务实例自身或代理负责设置并定期更新其关联Key的TTL,如果服务实例故障其对应Key就会在TTL之后过期失效,相当于将该故障服务实例注销,通过定时心跳以达到监控健康状态的效果。而且Etcd提供监听机制,允许为Key设置监听器当该Key发生变化时,监听器能及时获取通知。Etcd自身的高可用特性,基于TTL提供基本的服务健康检查,基于监听机制及时感知服务实例变化,使Etcd成为微服务架构中常用服务发现解决方案。
1.2.3 Consul
Consul是一个成熟的服务发现解决方案。其核心是一个基于Raft共识算法具备线性强一致性的Key-Value存储系统作为服务注册中心,并提供代理(Agent)机制一方面用于协调服务注册,一方面提供服务健康检查。代理(Agent)会在每个运行服务的节点上启动,获取节点地址并将该服务实例注册到服务注册中心。架构上Consul包括两类组件:Server、Agent,服务注册信息保存在Server上,通过Raft共识算法保证多个Server间数据线性强一致,保证服务注册中心高可用;将所有Agent作为集群节点,使用Gossip协议进行组关系管理和故障探测,当有Agent加入(启动)或离开(故障)集群时其他Agent会得到通知,实现服务健康检查和监视功能。
Gossip协议常用于集群组关系管理和故障检测,每个节点都通过一个或多个引导节点加入集群,引导节点有集群中所有节点列表,每个节点都从自己所知节点列表中随机选择一组节点周期性地发送多播消息,最终集群中所有节点都能知道其他节点。这个过程看起来很神奇,实际上Gossip协议能在几秒内将消息传遍有上百节点的集群。Akka、Riak、Cassandra都使用Gossip协议维护集群成员列表和故障探测。