参考链接
https://it.cha138.com/wen5/show-2300898.html
https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-troubleshooting.html#http-502-issues
https://repost.aws/zh-Hans/knowledge-center/elb-alb-troubleshoot-502-errors
https://github.com/kubernetes-sigs/aws-load-balancer-controller/issues/660
https://github.com/kubernetes-sigs/aws-load-balancer-controller/issues/814
https://github.com/kubernetes-sigs/aws-load-balancer-controller/issues/905
背景
每次api服务有更新时,预警监控总是报502 Bad Gateway错误,但由于做市程序几乎每秒都调用api服务下单几十次,如果在有行情波动情况下,做市商无法下单会造成很大损失。
处理方式
起初怀疑是service问题,通过直接访问service方式进行测试,发现重启过程中不会出现任何异常。所以还是怀疑问题出在ingress上
后来发现我们服务alb ingress转发方式是ip,也就是说alb ingress自己维护了pod的ip信息,没有走service
alb.ingress.kubernetes.io/target-type: ip
然后尝试在alb ingress上配置了健康检查配置,以及pod的preStop,但在滚动更新的时候依然会有502异常
alb配置
alb.ingress.kubernetes.io/healthcheck-path: "/healthcheck/"
alb.ingress.kubernetes.io/healthcheck-interval-seconds: "1"
# 缩小延迟注销时间
alb.ingress.kubernetes.io/target-group-attributes: deregistration_delay.timeout_seconds=30
pod配置
lifecycle:
preStop:
exec:
command: ["/bin/sleep", "30"]
通过观察发现在preStop中进行sleep期间pod依然处于Running状态,猜测可能pod处于Running状态时 ingress不会真正取消转发到此pod上。
然后通过观察发现 一旦执行完preStop pod的健康检查会立马生效,pod此时处于Terminating状态时pod的ReadinessProbe探针几乎立即就会失败,貌似服务在收到SIGTERM(kill -15)时会立马处于不能访问状态。
尝试在我的Java程序上延迟关闭(目的是收到SIGTERM信号后,阻塞一下等待ingress真正不会把流量转发到这个服务上)
@Slf4j
@Component
public class ShutdownListener implements ApplicationListener<ContextClosedEvent> {
@Override
public void onApplicationEvent(@NotNull ContextClosedEvent event) {
Uninterruptibles.sleepUninterruptibly(20, TimeUnit.SECONDS);
}
}
需要注意的是等待的时间不能超过terminationGracePeriodSeconds的时间
terminationGracePeriodSeconds 默认30s
改完之后再进行测试,滚动更新过程中不会再出现502异常了
总结
主要思想是确保pod的状态变更有足够的时间传播到ingress,并且貌似pod进入Terminating状态时ingress才会开始处理,pod在执行preStop的时候依然是处于Running状态,执行完毕才会进入Terminating状态。
所以在preStop进行休眠时没有效果的,需要程序收到SIGTERM信号后,再延迟一段时间关闭(好像只能在自己程序里进行处理了)。