内容简介:最近 AutoTrader 在调试一个有些复杂的问题,这一过程得到了 Istio 团队的很多帮助。这个问题现在已经基本得到了解决,这一过程中采取的一些措施可能对其他用户有所启发,因此有了本文。我们注意到有些请求在第一次尝试的时候会失败,Istio 会自动进行重试,然后就成功了。在 Jaeger 中观察可以看到:第一个请求是 503 状态,
最近 AutoTrader 在调试一个有些复杂的问题,这一过程得到了 Istio 团队的很多帮助。这个问题现在已经基本得到了解决,这一过程中采取的一些措施可能对其他用户有所启发,因此有了本文。
问题
我们注意到有些请求在第一次尝试的时候会失败,Istio 会自动进行重试,然后就成功了。在 Jaeger 中观察可以看到:第一个请求是 503 状态, response_flags
为 UC
。
如果你在关注或者正在使用 Istio,你可能会看到很多千奇百怪的 503。目前 503 的主要问题就是,它太模糊了。
看看这个简单的例子:
基本上,应用 2 的 Envoy 和应用通信过程中的任何问题都会被包裹成 503,发送回上游,然后上游就会进行重试。
不管怎样,有了 Istio,重试并不是世界末日。Istio 检测到故障后进行重试,然后给上游返回了成功信息。然而值得注意的是,故障总会发生,我们应该面向故障进行应用的构建。我们的应用跨越多个 AZ,出现这种奇怪的问题,会有很多可能的错误源头。
我们观察到,大概 0.012% 的请求发生了这种问题。我们的应用是一种微服务架构,这一种故障和 5 个应用相关,这样会看到 0.08% 的聚合请求失败率,(稳定的故障率)表明,这并非是偶然情况。
当你开始考虑这一故障时,会注意到 Sidecar 模型增加了应用通信过程的复杂度,这就是网格的代价之一。
回忆一下没有服务网格的世界, consumer-gateway
管理一个通往 sauron-seo-app
的连接池。然而有了服务网格,我们其实有了三个各行其是的连接池,各有各的配置:
-
consumer-gateway
到source-envoy
:Java 代码。 -
source envoy
到destination envoy
: DestinationRule 。 -
destination envoy
到sauron-seo-app
:在 Envoy 中进行配置,Istio 对其配置并无掌控。
这中间有很多出问题的机会,要查找根本原因,也有很大的排查范围。因此我们对真实场景中这一问题的应对方法进行回顾。
指标
Istio
Istio 搜集了很多的指标,能帮我们凸显问题。Istio 提供的这种水平的可观测性很有趣,能能够凸显你之前发现的问题。这很直白,所以打开 Prometheus 并输入:
sort_desc(sum(changes(istio_requests_total{response_flags="UC", response_code="503", reporter="destination"}[24h])) by (source_app, destination_app, reporter) >0)
这段指标的含义是:最近 24 小时内,状态为 503 并且被标记为 UC(上游连接问题),使用 source_app
、 destination_app
以及 reporter
进行汇总。
注意:上图中, reporter=source
就是来自于源 Envoy,而 reporter=destination
就是目标 Envoy。
所以看看我得出的结果, {destination_app="sauron-seo-app",reporter="destination",source_app="consumer-gateway"} 58
,这代表过去 24 小时里,从 consumer-gateway
到 sauron-seo-app
的请求中有 58 个出了问题,得到了 503UC
的结果,这一情况是由 sauron-seo-app
的 Envoy 汇报而来。
我们知道了,我们在目标一端发生了问题,这也跟前面的跟踪过程中得到的结论是一致的:源服务尝试了一个不同的目标并获得成功。我们来检查一下 Envoy 发生了什么事。
Envoy
我们要做的下一件事就是启用一些指标,帮助我们对 Envoy 进行排查。缺省情况下 istio-proxy
只提供一些核心的 Envoy 指标。我们需要更多信息。在 Deployment
里加入下列注解:
sidecar.istio.io/statsInclusionPrefixes: cluster.outbound,listener,cluster,cluster_manager,listener_manager,http_mixer_filter,tcp_mixer_filter,server,cluster.xds-grpc
注意:这个指标的数据量较大,缺省是关闭的。我只会在进行排错的时候才启用这些指标,并且在完成工作后就会关闭它们。
完成这一操作后,就会看到一些新指标,例如 envoy_cluster_upstream_cx_destroy_local_with_active_rq
和 envoy_cluster_upstream_cx_destroy_remote_with_active_rq
。这些指标来自 Envoy 的视角,因此它的本地和远程是这样的:
envoy_cluster_upstream_cx_destroy_local_with_active_rq
本地销毁的产生一个以上活动请求的链接数量。
听起来很恐怖吧?没人希望活动请求被杀掉,我们的目标 Envoy 说,有大量的远程销毁,而我们的源 Envoy 有大量的本地销毁。
这看起来云山雾罩,所以我觉得最简单的排查方法就是把他们列在一起。这样就会看到 local
指标在源 Envoy 中出现,而目标 Envoy 中报告了 remote
指标:
上图说明 sauron-seo-app
的 Envoy 和应用之间的连接关闭了。看起来是 sauron-seo-app
关闭了(远程关闭)。然后 consumer-gateway
Envoy 也随即关闭了连接。这就能够解释 consumer-gateway
在 HTTP 1.1 连接中(Envoy 之间的通信)收到的 5xx
响应了。这个连接无法继续发送数据,除了关闭,别无他法(本地关闭)。
注意:这不是 http2.0 的情景,看起来 Istio 1.2 会有能力把 Envoy 之间的连接池切换为 http2.0。
这样我们就决定,要进一步对 sauron-seo-app
进行观察。
istio-proxy debug 日志
istio-proxy
能够在运行时修改日志级别,对排除这类问题很有帮助。所以我们把这些日志设置为 debug
级别:
kubectl exec -n sauron-seo-app sauron-seo-app-7667b9b7dc-jd3vg -c istio-proxy -- curl -XPOST -s -o /dev/null http://localhost:15000/logging?level=debug
看看是否能有所斩获。
修改日志级别后,可以用 tail
来查看一下日志(可能有非常多的输出)。会看到 503 的相关内容:
[2019-05-30 08:24:09.206][34][debug][router] [external/envoy/source/common/router/router.cc:644] [C77][S184434754633764276] upstream reset: reset reason connection termination [2019-05-30 08:24:09.206][34][debug][filter] [src/envoy/http/mixer/filter.cc:133] Called Mixer::Filter : encodeHeaders 2 [2019-05-30 08:24:09.206][34][debug][http] [external/envoy/source/common/http/conn_manager_impl.cc:1305] [C77][S184434754633764276] encoding headers via codec (end_stream=false): ':status', '503' 'content-length', '95' 'content-type', 'text/plain' 'date', 'Thu, 30 May 2019 08:24:08 GMT' 'server', 'istio-envoy' [2019-05-30 08:24:09.208][34][debug][connection] [external/envoy/source/common/network/connection_impl.cc:502] [C77] remote close [2019-05-30 08:24:09.208][34][debug][connection] [external/envoy/source/common/network/connection_impl.cc:183] [C77] closing socket: 0
这里我们看到了 503 出现在连接 [C77]
上。如果我们后退一下,会看到 [C77]
连接上还有一段: upstream reset: reset reason connection termination
。 istio-proxy 告诉我们,上游复位了 77 号连接(这里的上游指的就是应用程序)。这进一步证实了,Envoy 认为 sauron-seo-app
关闭了连接。
抓包
目前为止,我们用了很多的 Istio 和 Envoy 提供的功能,我们大概知道,很可能是目标应用断掉了连接。是时候开始抓包来进一步研究了。
为了在 Kubernetes 上完成这个工作。我们使用了一个叫做 ksniff,我得说,这个 工具 太棒了。因为我们运行的是非特权容器,因此无法在应用中进行 tcpdump
。ksniff 可以:
- 检查你的目标应用运行在哪个节点上。
- 部署一个和这个节点有亲和的 Pod,绑定到 Host network。
- 从特权应用对流量进行 TCP Dump,并把流量发送回你笔记本上的 Wireshark。
TCP Dump 很吵,所以我们会做一下过滤:
- 我们关注的是 TCP 连接相关的事件,所以只需要看
SYN
、FIN
和RST
。 -
我们要观察的是本地 Envoy 和应用之间的流量,我们只想关注
localhost
,所以-i lo
就可以只查看 loopback 适配器了。kubectl sniff $pod -p -n $namespace -c istio-proxy -f ‘tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) != 0’ -i lo
我们很快就能看到 RST
,表明的确是我们的应用关闭了连接。
这就很清楚了,Envoy 应该能够处理上游的关闭连接。然而在极少数情况(0.003%)下,我们发现 Envoy 尝试向被应用关闭的连接中发送数据。Istio 团队还在尝试理解这种情况发生的原因(似乎是在服务端发送 RST
和 Envoy 复用连接池中的连接的过程中发生的争用),并能够更好的处理这种场景(1.1.8 之后)。
Istio 成员发现,在连接开始( SYN
)和复位( RST
)之间,总有五秒左右的间隔。
我们的服务器是 nodejs,Google 搜索发现了 Nodejs 文档中的一段内容:
以毫秒为单位的超时时间,缺省值 5000(5秒):服务器在处理完最后一个响应之后,等待新数据进入的时间,如果超过这一时间都未进行活动,就会销毁该 Socket。
由上述文档看来,虽然 Envoy 为应用创建了连接池,但是应用会在发呆 5 秒钟之后销毁 Socket。这个超时太短了。
TCP Socket 超时
我们做了一番挖掘,我们发现不止在 Nodejs 中有这种情况,Python 应用、Java/Tomecat 都有这种问题。缺省设置如下:
- nodejs:5 秒
- python:10 秒
- tomcat:20 秒
所以 Socket 超时越短, RST
就会越多,也就会有越多的 503 问题。
Istio 团队正在积极的寻求改进方法,我们发现可以简单的设置一个更高的 Socket 超时时间来解决这一问题。
Nodejs
const server = app.listen(port, '0.0.0.0', () => { logger.info(`App is now running on http://localhost:${port}`)}) server.keepAliveTimeout = 1000 * (60 * 6) // 6 minutes
Python
global_config = { 'server.socket_timeout': 6 * 60, } cherrypy.config.update(global_config)
Java-Spring
server: connect-timeout: 360000
下图就是我们修复问题的结果:
我知道 Istio 团队正在努力改进这方面的 UX 问题,尽可能高效的处理这类场景,让 Istio 为更多用户提供开箱可用的高性能表现。所以我很相信他会越来越好。
感谢 Chris McKean 和 Istio 社区的朋友们,他们在没有经历这种问题的情况下,依然提供了无私的帮助。希望这个排查过程能够对读者的工作有所助益。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Data Structures and Algorithms
Alfred V. Aho、Jeffrey D. Ullman、John E. Hopcroft / Addison Wesley / 1983-1-11 / USD 74.20
The authors' treatment of data structures in Data Structures and Algorithms is unified by an informal notion of "abstract data types," allowing readers to compare different implementations of the same......一起来看看 《Data Structures and Algorithms》 这本书的介绍吧!
XML、JSON 在线转换
在线XML、JSON转换工具
UNIX 时间戳转换
UNIX 时间戳转换