开局一张图,内容全靠编

背景介绍

随着微服务架构的提出和发展,服务实例的数量和网络地址都是动态变化的,这对系统运维提出了巨大的挑战。因此,动态的服务注册与发现就显得尤为重要。

解决方案

在一个分布式系统中,服务注册与发现组件主要解决两个问题:服务注册和服务发现。

  • 服务注册:服务实例将自身服务信息注册到注册中心。这部分服务信息包括服务所在主机IP和提供服务的Port,以及暴露服务自身状态以及访问协议等信息。
  • 服务发现:服务实例请求注册中心获取所依赖服务信息。服务实例通过注册中心,获取到注册到其中的服务实例的信息,通过这些信息去请求它们提供的服务。

除此之外,服务注册与发现需要关注监控服务实例运行状态、负载均衡等问题。

  • 监控:微服务应用中,服务处于动态变化的情况,需要一定机制处理无效的服务实例。一般来讲,服务实例与注册中心在注册后通过心跳的方式维系联系,一旦心跳缺少,对应的服务实例会被注册中心剔除。
  • 负载均衡:同一服务可能同时存在多个实例,需要正确处理对该服务的负载均衡。

CAP原则

CAP原则,指的是在一个分布式系统中,Consistency(一致性)、Availability(可用性)、Partition Tolerance(分区容错性),不能同时成立。

  • 一致性:它要求在同一时刻点,分布式系统中的所有数据备份都处于同一状态。
  • 可用性:在系统集群的一部分节点宕机后,系统依然能够响应用户的请求。
  • 分区容错性:在网络区间通信出现失败,系统能够容忍。

一般来讲,基于网络的不稳定性,分布容错是不可避免的,所以我们默认CAP中的P总是成立的。

一致性的强制数据统一要求,必然会导致在更新数据时部分节点处于被锁定状态,此时不可对外提供服务,影响了服务的可用性,反之亦然。因此一致性和可用性不能同时满足。

常见的框架中 Eureka 满足了其中的AP,ConsulZookeeper 满足了其中的CP。

Consul

Consul是由HashiCorp基于Go语言开发的支持多数据中心分布式高可用的服务发布和注册服务软件,采用Raft算法保证服务的一致性,且支持健康检查。

Consul采用主从模式的设计,使得集群的数量可以大规模扩展,集群间通过RPC的方式调用(HTTP和DNS)。它的结构图如下所示:

  • Client:作为一个代理(非微服务实例),它将转发所有的RPC请求到Server中。作为相对无状态的服务,它不持有任何注册信息。
  • Server:作为一个具备扩展功能的代理,它将响应RPC查询、参与Raft选举、维护集群状态和转发查询给Leader等。
  • Leader-Server:一个数据中心的所有Server都作为Raft节点集合的一部分。其中Leader将负责所有的查询和事务(如服务注册),同时这些事务也会被复制到所有其他的节点。
  • Data Center:数据中心作为一个私有的,低延迟和高带宽的一个网络环境。每个数据中心会存在Consul集群,一般建议Server是3-5台(考虑到Raft算法在可用性和性能上取舍),而Leader只能唯一,Client的数量没有限制,可以轻松扩展。

Raft算法

Raft算法将Server分为三种类型:Leader、Follower和Candidate。Leader处理所有的查询和事务,并向Follower同步事务。Follower会将所有的RPC查询和事务转发给Leader处理,它仅从Leader接受事务的同步。数据的一致性以Leader中的数据为准实现。

在节点初始启动时,节点的Raft状态机将处于Follower状态等待来来自Leader节点的心跳。如果在一定时间周期内没有收到Leader节点的心跳,节点将发起选举。

Follower节点选举时会将自己的状态切换为Candidate,然后向集群中其它Follower节点发送请求,询问其是否选举自己成为Leader。当收到来自集群中过半数节点的接受投票后,节点即成为Leader,开始接收Client的事务处理和查询并向其它的Follower节点同步事务。Leader节点会定时向Follower发送心跳来保持其地位。

Gossip协议

Gossip协议是为了解决分布式环境下监控和事件通知的瓶颈。Gossip协议中的每个Agent会利用Gossip协议互相检查在线状态,分担了服务器节点的心跳压力,通过Gossip广播的方式发送消息。

所有的Agent都运行着Gossip协议。服务器节点和普通Agent都会加入这个Gossip集群,收发Gossip消息。每隔一段时间,每个节点都会随机选择几个节点发送Gossip消息,其他节点会再次随机选择其他几个节点接力发送消息。这样一段时间过后,整个集群都能收到这条消息。

基于Raft算法,Consul提供强一致性的注册中心服务,但是由于Leader节点承担了所有的处理工作,势必加大了注册和发现的代价,降低了服务的可用性。通过Gossip协议,Consul可以很好地监控Consul集群的运行,同时可以方便通知各类事件,如Leader选择发生、Server地址变更等。

consul使用

  • 启动 consul server (这里启动了三台服务器)

    # 在 10.201.102.198 上启动服务
    consul agent -server -bootstrap-expect 3 -data-dir /tmp/consul -node=s1 -bind=10.201.102.198 -config-dir=/etc/consul.d/ -client 0.0.0.0 -ui
    # 在 10.201.102.199 上启动服务
    consul agent -server -bootstrap-expect 3 -data-dir /tmp/consul -node=s1 -bind=10.201.102.199 -config-dir=/etc/consul.d/ -client 0.0.0.0 -ui
    # 在 10.201.102.200 上启动服务
    consul agent -server -bootstrap-expect 3 -data-dir /tmp/consul -node=s1 -bind=10.201.102.200 -config-dir=/etc/consul.d/ -client 0.0.0.0 -ui
    
  • 启动 consul client

    # 在 10.201.102.248 上启动客户端
    consul agent -data-dir /tmp/consul -node=c1 -bind=10.201.102.248 -config-dir=/etc/consul.d/ -join 10.201.102.198
    
  • 查看 consul 成员

    consul members
    
    Node  Address              Status  Type    Build  Protocol  DC
    c1    10.201.102.248:8301  alive   client  x.x.x  2         dc1
    s1    10.201.102.198:8301  alive   server  x.x.x  2         dc1
    s2    10.201.102.199:8301  alive   server  x.x.x  2         dc1
    s3    10.201.102.200:8301  alive   server  x.x.x  2         dc1
    

consul-node

参考文献