🗒️spring boot网关的流量流向
2023-5-19
| 2023-5-20
0  |  0 分钟
type
status
date
slug
summary
tags
category
icon
password

写在前面

在遇到这个问题之前,我以为即使是spring boot网关,也会走k8s默认的service实现负载均衡(网关pod→微服务clusterIP→微服务pod)。现实打脸,又上了一课。
  • 故障背景:kube-proxy是ipvs模式,spring+k8s的组合框架,只spring boot网关使用nodeport暴露,其他微服务都是clusterip,网关里写上所有的路由规则
  • 故障现象:某项目一个微服务的部分副本CPU100%,但是pod内存正常(容器日志显示heap内存oom),pod一直僵死,未自动重启。刚开始涉及到微服务的部分很卡顿,但是后面居然无影响了。检查eureka,发现CPU超限的几个pod全部下线了。难道下线了就无影响了?因为我知道这个项目根本未配置存活探针,理论上ipvs还是会把流量负载到死掉的pod上啊?为什么现象不符合这个设定?
为了验证猜想,ipvsadm -Ln -c|egrep $clusterip 查不到任何该微服务的记录,说明流量并未通过svc的clusterip来进行dnat。最后只能检查conntrack连接跟踪表,可以查到pod ip的记录(废话,查不到就见鬼了)。前面几个现象说明流量从外网到微服务pod时未经过clusterip。
kubectl -n $ns get svc 微服务名 //得到clusterip ipvsadm -Ln -c|egrep $clusterip //过滤该微服务的ipvs转发记录 #检查conntrack连接跟踪表 egrep $clusterip /proc/net/nf_conntrack //可以查到pod ip 的记录
💡
免责声明:非java开发,下面的叙述来自互联网和自己的理解

spring boot网关的负载均衡

notion image
如上图,通过eureka服务发现,网关甚至可以直接拿到微服务的pod ip做LB,跳过了service。当然,网关也可以利用k8s自身的service。区别主要在于spring.cloud.gateway.discovery,但是我现在不能确定配置了service网关的流量流向,个人认为既然都没用到eureka服务发现组件,那理论上会直接使用service实现负载均衡,more
spring: cloud: gateway: # 设置与服务注册发现组件结合,这样可以采用服务名的路由策略 discovery: locator: enabled: true
当然,路由uri: lb://user-serviceuri: http://user-service 也是明显的区别,前者lb:说明用的是spring自身的loadblance。
前面的故障背景用到了spring.cloud.gateway.discovery ,故pod从eureka下线后,网关不再转发流量到僵死的pod。
进一步猜想,由于网关是nodeport暴露端口,故外部流量请求的流量流向大致是
client ->公网接入层 ->内网SLB ->|prerouting ->ipvs ->postrouting| ->网关pod(网关LB算法) -> 微服务pod
上面的流向反推,如果网关pod到微服务pod之间经过service,有点画蛇添足的感觉,因为网关pod已经拿到了所有的pod ip(对于service来说是endpoints),没有必要通过service再来一次负载均衡。

参考

 
技术
  • k8s
  • 网络
  • 运维方法论运维的价值
    目录