微服务注册中心与分布式协议

Eureka工作原理及心跳机制

  • 服务启动后向Eureka注册,Eureka Server会将注册信息向其他Eureka Server进行同步,当服务消费者要调用服务提供者,则向服务注册中心获取服务提供者地址,然后会将服务提供者地址缓存在本地,下次再调用时,则直接从本地缓存中取,完成一次调用。
  • 当服务注册中心Eureka Server检测到服务提供者因为宕机,网络原因不可用时,则在服务注册中心将该服务置为DOWN状态,并把当前服务提供者状态向订阅者发布,订阅过的服务消费者更新本地缓存。
  • 服务提供者在启动后,周期性(默认30s)向Eureka Server发送心跳,以证明当前服务是可用状态。Eureka Server在一定的时间(默认90s)未收到客户端的心跳,则认为服务宕机,注销该实例。

自我保护机制

  • 默认情况下,如果Eureka Server在一定的时间没有接收到某个服务的心跳,会注销该实例。但在微服务架构下服务之间通常都是跨进程调用,网络通信往往会面临着各种问题,比如微服务状态正常,网络分区故障等。
  • 固定时间内大量实例被注销,可能会严重威胁整个微服务架构的可用性,为了解决这个问题,Eureka 开发了自我保护机制:
    • Eureka Server在运行期间会去统计心跳失败比例在15分钟之内是否低于85%,如果低于85%,Eureka Server则会进入自我保护机制。Eureka Server会将当前的实例注册信息保护起来,同时提示一个警告,一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据。也就是不再注销任何微服务。
    1. Eureka 不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
    2. Eureka仍然能接受新服务的注册和查询请求,但是注册的新服务不会被同步到其它节点上。
    3. 当网络稳定后,当前实例注册信息会被同步到其它节点上。

Zookeeper工作原理及心跳机制

简单的说,zookeeper=文件系统+通知机制

文件系统

zookeeper维护一个类似文件系统的数据结构;每个子目录项都被称作znode,和文件系统一样,我们能够自由的增加,删除znode,且znode可以存储数据。

  • 持久化目录节点:客户端与zk断开连接后,该节点依旧存在;
  • 持久化顺序目录节点:客户端与zk断开连接后,该节点依旧存在,只是zk给该节点名称进行顺序编号;
  • 临时目录节点:客户端与zk断开连接后,该节点被删除;
  • 临时顺序目录节点:客户端与zk断开连接后,该节点被删除,只是zk给该节点名称进行顺序编号;

通知机制(watch)

  • 客户端可以在每个znode上设置一个watch,如果被watch的znode节点有变更,那么该watch就会被触发,这个watch所属客户端将接收到一个通知包,告知节点已经发生变化,把相应的事件通知给设置watch的client端
  • 一次触发:watch只会触发一次

zookeeper的角色

  • leader:负责进行投票的发起和决议,更新系统状态
  • follower:用户接收客户端请求并向客户端返回结果,在选举过程中参与投票
  • observer:可以接收客户端连接,将写请求转发给leader,observer不参与投票过程,只同步leader的状态,observer的目的是为了扩展系统。

服务注册

在zk中,进行服务注册,实际上就是在zk中创建了一个znode节点,该节点存储了该服务的ip,端口,调用方式(协议,序列化方式)等。该节点承担着最重要的职责,它由服务提供者创建,以供服务消费者获取节点中的信息,从而定位到服务提供者真正网络拓扑位置以及如何调用:

  1. 服务提供者启动时,会将其服务名称,ip地址注册到zk
  2. 服务消费者在第一次调用服务时,会通过注册中心找到相应的服务的IP地址列表,并缓存到本地,以供后续使用。当消费者调用服务时,不会再去请求注册中心,而是直接通过负载均衡算法从IP列表中取一个服务提供者的uri调用服务。
  3. zk提供了心跳检测功能,它会定时向各个服务提供者发送一个请求(长连接)如果长期没有响应,那么zk就认为该服务提供者已经挂了,并将其剔除。
  4. 服务消费者会去监听相应的路径(注册的服务实例),一旦数据有任何变化(增加或者减少)。zk会通知服务消费方,消费者会重新拉取服务列表。

zookeeper选举

  • 第一阶段:数据恢复阶段
    • 每台zk服务器在启动的时候,都会从本地的数据目录中找到自己所拥有的最大事务id
  • 第二阶段:选举阶段
    • 每一个zk的服务器都会推荐自己当leader并且提交选举协议
    1. 自己所拥有的最大事务id:Zxid
    2. 自己的选举id:myid
    3. 逻辑时钟值,作用是确保每一台zk服务器都会处于同一轮选举中
    4. 当前状态:(Looking)->选举中;(Follower)->追随者;(leader)->领导者;(observer)->观察者
  • pk原则
  1. 在选举的时候会先比较两个节点的最大事务id即Zxid,Zxid越大,则说明事务越新,Zxid较大的会胜出。
  2. 如果Zxid一致,则比较选举id,选举id较大的胜出。
  3. 满足过半性:即超过一半的节点才能成为leader
  • 过半性
  1. 过半选举:即只有一个节点胜过一半的节点之后才能成为leader;
  2. 过半服务:即只有zk集群中超过一半的节点存活才能对外提供服务;
  3. 过半操作:即只有zk集群中超过一半的节点同意才会提交请求。
  • zab协议
    • zab协议是为分布式协调服务zk专门设计的一种支持崩溃恢复的原子广播协议。
    1. 崩溃恢复:当整个集群启动过程中,获取当leader服务器出现网络中断,崩溃退出或者重启等异常后,zab协议进入崩溃恢复模式,选举产生新的leader;当选举完成,且集群中有过半机器完成了状态同步之后,zab协议就会退出崩溃恢复模式,进入消息广播模式,此时如果有一台遵守zab协议的服务器加入集群,因为此时集群中已经存在一个leader服务器在广播消息,那么该新加入的服务器自动进入恢复模式,找到leader服务器,进行数据同步。同步完成后,将作为follower一起参与到消息广播流程中。
    2. 消息广播:在zk集群中,数据副本的传递策略就是采用消息广播模式,
      1. 客户端发送一个写操作请求;
      2. leader服务器会将客户端的请求转化为事务proposal提案,同时为每个proposal分配一个全局的zxid;
      3. leader服务器将会为每一个follower服务器分配一个单独的队列,将需要广播的proposal依次放到队列中去,根据fifo策略进行消息发送。
      4. follower接收到proposal后,会首先将其以事务日志的方式写入本地磁盘中,写入成功后向leader反馈一个ack响应。
      5. leader在接收到超过半数的follower的ack后,认为消息发送成功,可以发送commit消息。
      6. leader向所有的follower发送commit消息,同时自身也会完成事务提交,follower接收到commit消息以后,将上一条事务提交。

Nacos的工作原理及心跳机制

  • 服务提供者通过nacos server内部的open api进行服务注册,nacos server内部有一个service服务的概念,里面有多个instance实例的概念,同时对不同的service服务可以划到不同的namespace命名空间下去。
  • 注册的时候就是在注册表里维护好每个服务的每个实例的服务器地址,包括ip地址和端口号。
  • 一旦注册成功后,服务就会跟nacos server进行定时的心跳,保持心跳是很关键的,nacos server会定时检查服务各个实例的心跳,如果一定时间没心跳,则认为这个服务实例宕机了,从注册表里移除。
  • 服务调用者会从nacos server通过open api查询要调用的服务实例列表,并且nacos客户端会启动一个定时任务,每隔10s就重新拉取一次服务实例列表,这样如果调用的服务有上线或者下线,就很快感知到了。
  • 还可以对要调用的服务进行监听,如果有异常变动会由nacos反向通知他。

负载均衡

  • 一般来说,负载均衡并不算是传统注册中心的功能,服务发现的完整流程应该是先从注册中心获取到服务的实例列表,然后再根据自身的需求,来选择其中的部分实例或者按照一定的流量分配机制来访问不同的服务提供者。
  • ribbon采用两步负载均衡,第一步先过滤掉不会采用的服务提供者列表,第二步是在过滤后的服务提供者实例里,实施负载均衡策略。
  1. RoundRobinRule:轮询
  2. RandomRule:随机
  3. AvailabilityFilteringRule:会先过滤掉由于多次访问故障而处于断路器状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务按照轮训策略进行访问
  4. WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应时间越快的权重越高被选中的概率越大,刚启动时如果统计信息不足,则使用RoundRobinRule策略额,等待信息采集足够,切换到WeightedResponseTimeRule
  5. RetryRule:先按照RoundRobinRule策略获取服务,如果获取服务失败则在指定时间内重试。
  6. BestAvailiableRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
  7. ZoneAvoidanceRule:复合判断Server所在区域的性能和Server的可用性选择服务器

nacos在1.0.0正式支持AP(distro协议)和CP(raft协议)两种一致性协议存在。

Ratf协议

  • raft算法是通过一切以领导者为准的方式,实现一系列值的共识和各节点日志的一致
  • raft算法支持领导者,跟随者和候选人3种状态
  1. 跟随者(Follower):就相当于普通群众,默默地接收和处理来自领导者的消息,当等待领导者心跳信息超时的时候,就主动站出来,推荐自己当候选人。
  2. 候选人(Candidate):候选人将向其他节点发送请求投票RPC消息,通知其他节点来投票,如果赢得了大多数选票,就晋升当领导者。
  3. 领导者(leader):处理写请求,管理日志复制,不断发送心跳信息,告知其他节点自己还活着。

raft实现了随机超时时间的特性,也就是说,每个节点等待领导者节点心跳信息的超时时间的间隔是随机的。等待超时时间最小的节点会最先因为没有等到领导者的心跳信息,发生超时,而这个时候,节点A就增加自己的任期编号,并推荐自己为候选人,先给自己投票,然后向其他节点发送请求投票RPC消息,请它们选举自己为领导者。如果其他节点接收到候选人A的请求投票RPC消息,在编号为1的这届任期内,还没有进行过投票,那么它就将选票投给该节点,并增加自己的任期编号。如果候选人在选举超时时间内获得了大多数选票,那么它就将会成为本届任期内新的领导者。

节点间通讯

  • 请求投票RPC:由候选人在选举期间发起,通知各节点进行投票;
  • 日志复制RPC:是由领导者发起,用来复制日志和提供心跳消息。

任期

  1. 跟随者在等待领导者心跳消息超时后,推举自己为候选人时,会增加自己的任期号。
  • 如果一个服务器节点,发现自己的任期编号比其他节点小,那么它会将自己的编号更新至较大的编号。

选举规则

  • 领导者周期性地向所有跟随者发送心跳消息,通知大家我是领导者,阻止跟随者发起新的选举。
  • 如果在指定时间内,跟随者没有接收到来自领导者的消息,那么它就认为当前没有领导,推荐自己为候选人,发起选举。
  • 在一次选举中,赢得大多数选票的候选人,将晋升为领导者。
  • 在一个任期内,领导者一直都会是领导者,直到它自身出现问题,或者因为网络延迟,其他节点发起一轮新的选举。
  • 在一次选举中,每一个服务器节点最多会对一个任期编号投出一张选票,并且按照先来先投的原则进行投票。
  • 当任期编号相同时,日志完整性高的跟随者,拒绝投票给日志完整性低的候选人。

日志复制

  • 接收到客户端请求后,领导者基于客户端请求中的指令,创建一个新日志项,并附加到本地日志中。
  • 领导者通过日志复制rpc,将新的日志项复制到其他的服务器
  • 当领导者将日志项,成功复制到大多数的服务器上的时候,领导者会将这条日志项提交到它的状态机中。
  • 领导者将执行的结果返回给客户端。
  • 当跟随者接收到心跳信息,或者新的日志复制rpc消息后,如果跟随者发现领导者已经提交了某项日志项,而它还没提交,那么跟随者就将这条日志项提交到本地的状态机中。
  • 对于领导者跟随者日志项不一致的情况,领导者通过强制跟随者直接复制自己的日志项,处理不一致日志。

成员变更

  1. 成员变更的问题,主要在于进行成员变更时,可能同时存在新旧配置的两个大多数,导致集群中出现两个领导者,破坏了raft领导者的唯一性原则。
  2. 单节点变更则是利用一次变更一个节点,不会出现同时存在两个大多数的特性。实现成员变更。

Distro协议

  • 客户端以服务为纬度向服务端注册,注册后每隔一段时间向服务端发送一次心跳,心跳需要带上注册服务的全部信息,在客户端看来,服务端节点对等,所以请求的节点是随机的
  • 客户端请求失败则换一个节点继续发送请求
  • 服务端节点都存储所有数据,但每个节点都只负责其中的一部分服务,在接收到客户端的写请求后,服务端节点会判断是否为自己负责,如果是则处理,否则交由负责的节点处理
  • 每个服务端节点主动发送健康检查到其他节点,响应的节点则被该节点视为健康节点
  • 服务端在接收到客户端心跳后,如果该服务不存在,则当作注册请求来处理
  • 服务端如果长时间未接收到客户端心跳,则下线该服务
  • 负责的节点在接收到服务注册,服务心跳等请求后将数据写入后即返回,后台异步同步数据至其他节点
  • 节点在收到读请求后直接读本地,无论数据是否最新版本。

基于事件总线的AP模型

注册数据可以全量缓存在每个注册中心内存中,通过消息总线来同步数据。当有一个注册中心节点接收到服务节点注册时,会产生一个消息推送给消息总线,再通过消息总线通知给其他注册中心节点更新数据并进行服务下发,从而达到注册中心间数据最终一致性。

  • 当有服务上线,注册中心节点收到注册请求,服务列表数据发生变化,会生成一个消息,推送给消息总线,每个消息都有整体递增的版本。
  • 消息总线会主动推送消息到各个注册中心节点,同时注册中心节点也会定时拉取消息。对于获取到消息的在消息回放模块里面回放,只接受大于本地版本号的消息,小于本地版本号的消息直接丢弃,从而实现最终一致性。
  • 消费者订阅可以从注册中心内存拿到指定接口的全部服务实例,并缓存到消费者的内存里面。
  • 采用推拉模式,消费者可以及时地拿到服务实例增量变化情况,并和内存中的缓存数据进行合并。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值