本文介绍服务网格中常见的503报错场景及解决方案。
偶发503
场景一:使用自定义监控指标功能进行个性化配置,每当配置变更时,日志监控发现少量请求出现503
问题原因
自定义指标功能的逻辑是通过生成一个对应的EnvoyFiter来进行istio.stats
的配置更新。该配置在Envoy Listener级别生效,即通过LDS同步生效。Envoy在应用Listener级别的配置时,需要断开已有连接。对应的在途请求因为连接被Reset或Close导致出现503。
解决方案
上游Server主动Close连接时,您看到的503并非上游Server发送,而是客户端Sidecar因为上游连接主动断开,由本地返回的响应。
Istio默认的重试配置中未包含“上游Server主动Close连接”的情况。EnvoyProxy的重试条件中,Reset符合这种情况对应的触发条件。因此,您需要为对应服务的路由配置retry Policy。在VirtualService下的retry Policy配置包含Reset的触发条件。
配置示例如下。该配置仅针对Ratings服务生效。
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: ratings-route
spec:
hosts:
- ratings.prod.svc.cluster.local
http:
- route:
- destination:
host: ratings.prod.svc.cluster.local
subset: v1
retries:
attempts: 2
retryOn: connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes,reset,503
相关FAQ
为什么Istio默认的重试机制未生效?
Istio默认重试发生的条件如下。默认会重试2次。该场景未在重试条件内,因此未生效。
"retry_policy": {
"retry_on": "connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes",
"num_retries": 2,
"retry_host_predicate": [
{
"name": "envoy.retry_host_predicates.previous_hosts"
}
],
"host_selection_retry_max_attempts": "5",
"retriable_status_codes": [
503
]
}
connect-failure:连接失败。
refused-stream:当HTTP2 Stream流返回
REFUSED_STREAM
错误码。unavailable:当gRPC请求返回
unavailable
错误码。cancelled:当gRPC请求返回
cancelled
错误码。retriable-status-codes:当请求返回的
status_code
和retriable_status_codes
配置下定义的错误码匹配。
关于最新版本的EnvoyProxy完整的重试条件,请参见以下文档。
HTTP已有的重试条件配置(包含HTTP2和HTTP3):Router
gRPC独有的重试条件配置:x-envoy-retry-grpc-on
场景二:偶发503,没有规律,在此过程中并未发生配置变更
503偶尔出现,但是在流量密集时,会持续出现。通常出现在Sidecar的Inbound侧。
问题原因
Envoy的空闲连接保持时间和应用不匹配。Envoy空闲连接时间默认为1小时。
Envoy空闲连接时间过长,应用相对较短:
应用已经结束空闲连接,但是Envoy认为没有结束。此时如果有新的连接,就会报503UC。
Envoy空闲连接时间过短,应用相对较长:
这种情况不会导致503。Envoy认为之前的连接已经被关闭,因此会直接新建一个连接。
解决方案
方案一:在DestinationRule中配置idleTimeout
造成该问题的原因就是idleTimeout不匹配,因此在DestinationRule中配置idleTimeout属于比较根本的解决办法。
如果配置了idelTimeout,在Outbound和Inbound两侧都会生效,即Outbound和Inbound的Sidecar都会存在idleTimeout的配置。如果客户端没有Sidecar,idleTimeout也会生效,并能够有效减少503。
配置建议:此配置与业务相关,太短会导致连接数过高。建议您配置为略短于业务应用真正的idleTimeout时间。
方案二:在VirtualService中配置重试
重试会重建连接,可以解决此问题。具体操作,请参见场景一的解决方案。
该操作为非幂等的请求,重试存在较大的风险,请谨慎操作。
场景三:Sidecar生命周期相关
问题原因
Sidecar和业务容器生命周期导致,常发生于Pod重启。
解决方案
具体操作,请参见Sidecar生命周期。
必定503
场景一:应用监听localhost
问题原因
当集群中的应用监听localhost网络地址时,如果localhost是本地地址,会导致集群中的其他Pod无法对其进行正常访问。
解决方案
您可以通过对外暴露应用服务解决此问题。具体操作,请参见如何使集群中监听localhost的应用被其他Pod访问。
场景二:启用Sidecar后,健康检查总是失败,报错503
问题原因
在服务网格开启mTLS后,kubelet向Pod发送的健康检查请求被Sidecar拦截,而kubelet没有对应的TLS证书,导致健康检查失败。
解决方案
您可以通过配置端口健康检查流量免于经过Sidecar代理解决此问题。具体操作,请参见为什么注入Sidecar后,健康检查总失败或者无效。