又是新的一年了,距离上一次写文章已经过了2个多月了,作为新年的第一篇文章,对最近使用SLB的心得进行总结,作为以后备注,也可以让各位读者少走一点坑。

SLB使用的是阿里云的服务,服务A有多个实例部署在不同服务器上的docker容器中。对外通过SLB进行负载,调用方只需要通过访问SLB就可以将请求均匀的分布到不同服务器的A服务中。

阿里云同时还提供接口的方式操作SLB,可以动态的上下线服务,官方文档:https://help.aliyun.com/document_detail/27566.html?spm=5176.10609282.905295.38.6b0d3801v5OcOg 这里主要使用到了AddBackendServers和RemoveBackendServers对SLB进行操作,在应用发布前,调用RemoveBackendServers将此服务器从SLB中摘除,等待发布完成后,调用AddBackendServers将服务挂载到SLB,这样就可以实现滚动发布了。(接口调用都已经集成到Jenkins上了,只需要在Jenkins上点击发布就好)。

这种方式使用了几天后,在我们的ELK监控上就发现了问题,在每次下线服务后,调用方就会报出好几个超时错误SocketTimeoutException,而且通过监控可以看出在每次下线服务器后都会报出同样的错误。

经过一番调查后发现,直接摘除后端服务的话,会导致当前已经连上的请求直接被中断,所以客户端就会接连报出超时错误。

问题找到了,就非常好解决了。在AddBackendServers接口中发现可以设置权值,于是将发布流程优化成:

  1. 将需要发布的服务器的权值设置为0(防止新的流量进入)
  2. 等待一段时间(SLB设置的超时时间)+2s,(确保之前的请求都完成了)
  3. 将此服务器从SLB上摘除
  4. 进行服务发布
  5. 将服务器挂载到SLB上
  6. 设置权值

通过以上步骤优化后,就再也没有出现过之前的错误了,完美的实现了滚动发布。

在调查的过程中,还看到了官方的最佳实践:https://helpcdn.aliyun.com/document_detail/57399.html 官方使用的是通过心跳监测机制,将SLB自动剔除。但是这种通过文件的方式在目前容器化的服务中是行不通的,而且也复杂了,可以优化成:

  1. 提供自定义的health接口
  2. 下线前将通过接口调用的方式,通知health接口返回500的错误
  3. 等待SLB心跳多次检测后发现服务不可用,将此服务器标记为异常,且不在转发流量
  4. 发布服务
  5. 等待SLB自动完成心跳检测

总结

以上两种方式都能实现SLB的滚动发布,可以根据实际情况进行选择,各有优缺点,总结如下:

接口方式 health方式
优点 方便控制,可以动态设置权重 除了设置health接口不可用外,无需其他操作
缺点 需要实时注意SLB的超时时间,需要调用SLB的接口 依赖SLB的自动监测机制,跟SLB配置相关大,时间不可控