istio 503处理

istio上线一段时间后发现部分高并发的业务会频繁告警503,于是开始排查:

业务架构:

 

 在我们的环境中istio只拦截inbound的流量,不拦截outbound的流量

 

 1.查看apisix 端的envoy日志发现日志中有大量response_code:503 ,response_flags: UC

 2.查看业务容器的envoy 日志并未发现503日志,由此猜测是apisix 到业务容器中间链路发生503,请求未到达业务容器

 3.在业务容器中tcpdump抓包,发现业务端口大量业务返回的 reset包,waht?业务主动断开了连接?

 

 于是让业务梳理了业务场景,检查了相关代码逻辑,确定是否有主动关闭tcp连接的操作,业务给出了否定答案,确定没有相关逻辑,gogle了相关问题,发现有很多人遇到了类似的问题,按照网上的方法设置了一下参数:

1.istio 增加503 retry

2.禁用业务容器envoy的keepalive

3.设置envoy连接池空闲缓存时间(让envoy主动断开空闲连接,而不是让业务容器断开envoy的长链接)

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: xthk-live-api-pub-vs
  namespace: prod-main
spec:
  hosts:
    - xthk-live-api-pub
  http:
    - match:
        - port: 80
      retries:
        attempts: 3
        perTryTimeout: 2s
        retryOn: 'gateway-error,connect-failure,refused-stream,503'
      route:
        - destination:
            host: xthk-live-api-pub
            port:
              number: 80
            subset: v1
    - match:
        - port: 443
      route:
        - destination:
            host: xthk-live-api-pub
            port:
              number: 443
            subset: v1
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: xthk-live-api-pub-dr
  namespace: prod-main
spec:
  host: xthk-live-api-pub
  subsets:
    - labels:
        version: v1
      name: v1
  trafficPolicy:
    connectionPool:
      http:
        idleTimeout: 1s
        maxRequestsPerConnection: 1
    tls:
      mode: ISTIO_MUTUAL

经过一段时间的操作,发现然并卵,错误依旧

再次仔细查看envoy日志,发现了异常

 

 upstream_cluster为PassthroughCluster,调用k8s集群内的服务,为什么upstream_cluster不是服务名称的cluster呢?(当cluster为PassthroughCluster,证明istio没有通过k8s发现该服务,这样的话就不会走istio的路由,而是通过k8s的svc转发,就会多走一层kube-proxy转发)

为了排查 upstream_cluster为PassthroughCluster的问题,将apisix envoy的日志设置为debug,有两种设置方式:

1.直接在进入envoy 调用envoy接口配置,这种方式实时生效,且不重启envoy,envoy重启后失效 curl -X POST localhost:15000/logging?level=debug

2.设置pod annoations: sidecar.istio.io/logLevel: debug,这种方式pod会重建,但是重启后debug模式依旧生效

查看envoy 日志:

 

 通过日志我们发现authority 为一个外网域名,即istio向后转发时使用的host 是一个外网域名而不是集群内的service name,而istio中的VirtualService以及DestinationRule都是靠其中的host字段来匹配的,所以导致istio向pod转发流量时走的istio的passthroughCluster,而不是对应集群内服务(Outbound Cluster),所以没有走istio的路由直接转发给pod(istio的转发是不经过kube-proxy),而是走了k8s 的service ip,通过kube-proxy转发到pod,这中间相当于就多了一层转发,那为什么会造成这个原因呢,看了apisix的配置,发现了问题

 

 apisix 向后转发时可以配置转发到后端时主机名的保持,有三种方式:

1.保持与客户端请求一致的主机名:他的意思是客户端请求的是什么域名,转发到k8s pod时 host 就是客户端请求的域名,如:客户端请求的是 www.baidu.com,这时候转发到集群时,hostName 就是 www.baidul.com,就会导致本次访问的host 与istio vs以及dr规则匹配不到,就会当成不是集群内的服务,会走passthroughCluster,不会走istio的路由,而是通过k8s的kube-proxy最终转发到pod

2.使用目标节点列表中的主机名或IP,这个选项的意思是无论客户端通过什么域名来请求,apisix转发到k8s集群时都是用我们自己配置的主机名,如上游主机我们配置的是k8s的svc name,这时转发到后端时就会使用k8s的svc name而不是客户端访问的域名

3.自定义Host请求头:这个的意思和第二个选项类似,只不过我们可以自定义向后携带的hostName

我把apisix修改成了上述第二个选项使用目标节点列表中的主机名或IP,再次查看apisix 的envoy日志:

 

 这时发现upstream_cluster变成了对一个k8s服务的outbond,说明istio已经识别了目标服务为k8s集群内的服务,这时候就会走istio自己的路由,不走kube-proxy.

一天后查看对应业务的访问日志

 

 

查看了一天的日志,发现503消失

相关参考链接:

https://blog.csdn.net/luo15242208310/article/details/96480095

https://zhuanlan.zhihu.com/p/412262801

https://jishuin.proginn.com/p/763bfbd310c3

posted on 2022-01-21 14:17  it_man_xiangge  阅读(1581)  评论(0编辑  收藏  举报

导航

所有文章均为个人学习笔记,并未有任何教学的意思,大神勿喷