212

主动健康检查要点(Ribbon 为例)

 4 years ago
source link: https://lotabout.me/2020/Active-Health-Check-With-Ribbon-Example/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

之前的文章 QQA: Nginx 如何做健康检查? 介绍了 Nginx 如何做被动健康检查(passive health check),本文以 Ribbon 为例,介绍主动健康检查(active health check) 有哪些注意点。

典型流程

典型的主动检查需要客户端至少有一个 ping thread,定期检测服务器是否健康,流程如下图:

IFbQreE.png!web
  1. Ping thread 检测到两个服务器都正常工作
  2. 于是客户端会将请求分发到两个服务器上
  3. 此时 Server 2 宕机,发送到该机器的请求处理失败,返回错误
  4. 由于新一轮的检测还没有开始,客户端没有意识到服务器已宕机,依旧将请求分发给 Server 2
  5. 新一轮 Ping 检测到 Server 2 宕机,将其标记为不可用
  6. 于是客户端将所有请求分发到 Server 1
  7. 此时 Server 2 恢复正常,但由于还没有被客户端检测到,不会向它分发请求
  8. 新一轮 Ping 检测到 Server 2 恢复,将其标记为可用
  9. 客户端重新将请求分配给 Server 2

Ribbon 相关实现

要实现上节中的策略,Ribbon 对其中的关键节点做了相应的抽象:

  1. Server 代表服务器, .setAlive(boolean) 方法可标记服务是否健康
  2. IPing.isAlive(Server server) 用于检测服务是否健康。 DummyPing 实现不对服务进行检测, ribbon-httpclient 包中的 PingUrl 实现则会请求指定 URL,根据返回是否符合预期来判断服务是否健康
  3. IPingStrategy 接口定义以什么策略来 ping 多台服务器,默认是顺序 ping,ping 完一台 ping 下一台
  4. IRule 定义如何分发请求,默认是轮流选择(round-robin),会跳过标记为不可用的服务
  5. ILoadBalancer 代表负载均衡,在创建时需要指定上述的各项元素

简单使用示例如下(代码不可直接运行):

IRule rule = new RetryRule(new RoundRobinRule(), maxRetryMills);
IPing ping = new PingUrl(false, healthUrl);
((PingUrl) ping).setPingAppendString(healthExpected.trim());

BaseLoadBalancer loadBalancer = new BaseLoadBalancer(ping, rule);
loadBalancer.addServers(endpoints.stream().map(Server::new).collect(Collectors.toList()));
loadBalancer.setPingInterval(pingIntervalSeconds);

MyLoadBalancerContext context = MyLoadBalancerContext(loadBalancer);

Server server = context.getLoadBalancer().chooseServer(null);
URI newUri = context.reconstructURIWithServer(server, originalUrl);

// do what ever you want with newUri

注意点

其实上述流程还有一些缺陷,需要在具体实现中注意:

  • 在步骤 #3 中,Server 2 宕机导致请求失败时,要如何处理?(是否需要类似被动检查中的故障转移?)
    • 是否要重试?重试是对当前服务还是转发到其它服务?
    • 是否需要将当前服务标记为不可用?防止 #4 时继续向它发送请求?
  • Ping 的时间间隔多少合适?间隔太短则会产生大量检测流量,太大则对服务变化不敏感。

在 Ribbon 中,有 RetryRule 策略,在选择 Server 时,如果发现 server.isAlive = false ,则会等待一段时间,期间如果 server.isAlive 变成 true 则继续请求,否则则返回错误。在 PingUrl 检查机制下,其实只可能等待下次 Ping 成功 isAlive 才可能变成 true,所以重试也没有太多实际用处。但如果 Ping 的方式是类似 eureka 这种注册中心通知的机制,则可以发挥作用。

另外因为 Ribbon 的边界是选择服务器,因此如果是请求结果错误(如连接失败),并不会直接反映到 Ribbon 的 Server 状态。因此如果需要的话,需要自己手工将对应的 server 的 isAlive 设置成 false 来标记为不可用。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK