一、RPC框架设计的核心模块

1、服务发现

2、健康检查

3、路由策略

4、负载均衡

5、异常重试

6、优雅关闭

7、优雅启动

8、熔断限流

9、服务分组

二、服务发现

1、整体架构

RPC服务用途 rpc 服务治理_RPC服务用途

2、技术选型

(1)DNS(不可用)

RPC服务用途 rpc 服务治理_负载均衡_02

  • 如果服务端IP 端口下线了,服务调用者不能及时摘除下线节点。
  • 如果服务端ip,端口 扩容,新上线的服务提供方,调用方不能及时发现。
  • DNS存在缓存时间长的问题

(2)负载均衡设备 (不可用)

RPC服务用途 rpc 服务治理_RPC服务用途_03

  • 搭建负载均衡设备或 TCP/IP 四层代理,需求额外成本;
  • 请求流量都经过负载均衡设备,多经过一次网络传输,会额外浪费些性能;
  • 负载均衡添加节点和摘除节点,一般都要手动添加,当大批量扩容和下线时,会有大量的人工操作和生效延迟;
  • 我们在服务治理的时候,需要更灵活的负载均衡策略,目前的负载均衡设备的算法还满足不了灵活的需求。

(3)zookeeper(可用,但存在性能瓶颈)

RPC服务用途 rpc 服务治理_负载均衡_04

ZooKeeper 集群性能-当服务集群大时,容易出现性能问题。

CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。

在极端情况下保证AP ,实现最终一致性。

(4)消息总线的形式实现服务发现机制

RPC服务用途 rpc 服务治理_RPC服务用途_05

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

 

三、健康检查

RPC 框架里面的一个核心的功能——健康检测,它能帮助我们从连接列表里面过滤掉一些存在问题的节点,避免在发请求的时候选择出有问题的节点而影响业务。

但是在设计健康检测方案的时候,我们不能简单地从 TCP 连接是否健康、心跳是否正常等简单维度考虑,因为健康检测的目的就是要保证“业务无损”,所以在设计方案的时候,我们可以加入业务请求可用率因素,这样能最大化地提升 RPC 接口可用率。

RPC服务用途 rpc 服务治理_负载均衡_06

  • 健康状态:建立连接成功,并且心跳探活也一直成功;
  • 亚健康状态:建立连接成功,但是心跳请求连续失败;
  • 死亡状态:建立连接失败。

也可以通过接口的可用率这个突破口,判定服务节点的健康状况。

可用率的计算方式是某一个时间窗口内接口调用成功次数的百分比(成功次数 / 总调用次数)。当可用率低于某个比例就认为这个节点存在问题,把它挪到亚健康列表,这样既考虑了高低频的调用接口,也兼顾了接口响应时间不同的问题。

 

四、路由策略

RPC服务用途 rpc 服务治理_RPC服务用途_07

ip路由策略==>实现ip选择

参数路由策略==>基于请求入参,服务治理框架的配置端配置路由策略。实现定时化流量分配。

五、负载均衡

当我们的一个服务节点无法支撑现有的访问量时,我们会部署多个节点,组成一个集群,然后通过负载均衡,将请求分发给这个集群下的每个服务节点,从而达到多个服务节点共同分担请求压力的目的。

负载均衡主要分为软负载和硬负载,软负载就是在一台或多台服务器上安装负载均衡的软件,如 LVS、Nginx 等,硬负载就是通过硬件设备来实现的负载均衡,如 F5 服务器等。负载均衡的算法主要有随机法、轮询法、最小连接法等。

RPC服务用途 rpc 服务治理_负载均衡_08

负载均衡算法包括

  • 随机权重
  • Hash
  • 轮询
  • 自适应负载均衡算法

自适应负载均衡算法

RPC服务用途 rpc 服务治理_提供方_09

  • 添加服务指标收集器,并将其作为插件,默认有运行时状态指标收集器、请求耗时指标收集器。
  • 运行时状态指标收集器收集服务节点 CPU 核数、CPU 负载以及内存等指标,在服务调用者与服务提供者的心跳数据中获取。
  • 请求耗时指标收集器收集请求耗时数据,如平均耗时、TP99、TP999 等。
  • 可以配置开启哪些指标收集器,并设置这些参考指标的指标权重,再根据指标数据和指标权重来综合打分。
  • 通过服务节点的综合打分与节点的权重,最终计算出节点的最终权重,之后服务调用者会根据随机权重的策略,来选择服务节点。

 

六、异常重试

RPC服务用途 rpc 服务治理_RPC服务用途_10

rpc框架支持重试机制,但业务使用时,需要注意业务的接口是否是幂等接口

  • 业务逻辑必须是幂等的
  • 每次超时时间需要重置(保证重试的成功率)
  • 以及去掉有问题的服务节点后,在剩余节点选择可重试节点
  • 匹配可重试的异常策略
  • 具有重试最大次数限制

 

七、优雅的服务关闭

RPC服务用途 rpc 服务治理_负载均衡_11

目的:在服务停机时,最大程度减少业务影响。

服务启动时,给jvm运行环境,注册一个钩子函数,在jvm进程关闭时,启动钩子函数执行

  • 开启挡板(新流量不接收处理,返回特定异常。服务端基于特定异常,选择其他节点重试请求)
  • 通知调用方服务下线(调用方不进行下线服务节点流量分配,服务端也要保存客户端的列表)
  • 等待处理中的请求结束(服务提供方,通过技术器表现当前服务处理的请求数,要有超时机制,等待时间不能太长(10s))

 

八、优雅的服务启动

那什么叫启动预热呢?简单来说,就是让刚启动的服务提供方应用不承担全部的流量,而是让它被调用的次数随着时间的移动慢慢增加,最终让流量缓和地增加到跟已经运行一段时间后的水平一样。

RPC服务用途 rpc 服务治理_RPC服务用途_12

【1】服务发布时,向注册中心暴露自己服务启动的时间,调用方感知到服务端存在时,动态调整权重,达到服务预热的效果

  • 基于权重的负载均衡,但是这个权重是由服务提供方设置的,属于一个固定状态。
  • 现在我们要让这个权重变成动态的,并且是随着时间的推移慢慢增加到服务提供方设定的固定值,整个过程如上图所示:预热过程图通过这个小逻辑的改动,我们就可以保证当服务提供方运行时长小于预热时间时,对服务提供方进行降权,减少被负载均衡选择的概率,避免让应用在启动之初就处于高负载状态,从而实现服务提供方在启动后有一个预热的过程。
  • 大批量服务重启时,这种策略会失效。但可以采取动态自适应负载机制决策。

【2】服务发布时,延迟暴露自己给注册中心

  • 接口注册到注册中心前,预留一个 Hook 过程,让用户可以实现可扩展的 Hook 逻辑。用户可以在 Hook 里面模拟调用逻辑,从而使 JVM 指令能够预热起来,并且用户也可以在 Hook 里面事先预加载一些资源,只有等所有的资源都加载完成后,最后才把接口注册到注册中心。

RPC服务用途 rpc 服务治理_提供方_13

九、熔断限流

服务端的自我保护(限流机制)

  • 最简单的计数器,还有可以做到平滑限流的滑动窗口
  • 漏斗算法
  • 令牌桶算法

调用端的自我保护(熔断机制)

  • 动态代理是 RPC 调用的第一个关口。在发出请求时先经过熔断器,如果状态是闭合则正常发出请求,如果状态是打开则执行熔断器的失败策略。
  • 熔断器的状态:打开,关闭,探测 三个状态
  • 熔断器基于线程中断机制实现(超过指定时间未得到响应则进行熔断)

十、服务分组

对服务提供方进行分组,达标,实现流量隔离,隔离业务流量。在服务异常时,降低业务影响。

也是路由的一种特殊策略提现

RPC服务用途 rpc 服务治理_负载均衡_14