有奖:语音产品征文挑战赛火热进行中> HOT

431 状态码:Request Header Fields Too Large

现象

istio 中 http 请求,envoy 返回 431 异常状态码:
HTTP/1.1 431 Request Header Fields Too Large

原因分析

此状态码说明 http 请求 header 大小超限了,默认限制为60KiB,由 HttpConnectionManager 配置的 max_request_headers_kb 字段决定,最大可调整到96KiB:




解决方案

可以通过 EnvoyFilter 调整 max_request_headers_kb 字段来提升 header 大小限制。
EnvoyFilter 示例(istio 1.6 验证通过):
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: max-header
namespace: istio-system
spec:
configPatches:
- applyTo: NETWORK_FILTER
match:
context: ANY
listener:
filterChain:
filter:
name: "envoy.http_connection_manager"
patch:
operation: MERGE
value:
typed_config:
"@type": "type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager"
max_request_headers_kb: 96
高版本兼容上面的 v2 配置,但建议用 v3 的 配置 (istio 1.8 验证通过):
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: max-header
namespace: istio-system
spec:
configPatches:
- applyTo: NETWORK_FILTER
match:
context: ANY
listener:
filterChain:
filter:
name: "envoy.http_connection_manager"
patch:
operation: MERGE
value:
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
max_request_headers_kb: 96
若 header 大小超过 96 KiB,这种情况本身也很不正常,建议将这部分数据放到 body。

426 状态码:Upgrade Required

现象

Istio 使用 Envoy 作为数据面转发 HTTP 请求,而 Envoy 默认要求使用 HTTP/1.1 或 HTTP/2,当客户端使用 HTTP/1.0 时就会返回 426 Upgrade Required。

常见的 nginx 场景

如果用 nginx 进行 proxy_pass 反向代理,默认会用 HTTP/1.0,您可以显示指定 proxy_http_version 为 1.1:
upstream http_backend {
server 127.0.0.1:8080;

keepalive 16;
}

server {
...

location /http/ {
proxy_pass http://http_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
...
}
}

压测场景

ab 压测时会发送 HTTP/1.0 的请求,Envoy 固定返回 426 Upgrade Required,根本不会进行转发,所以压测的结果也不会准确。可以换成其它压测工具,如 wrk

解决方案:让 istio 支持 HTTP/1.0

有些 SDK 或框架可能会使用 HTTP/1.0 协议,例如使用 HTTP/1.0 去资源中心/配置中心拉取配置信息,在不想改动代码的情况下让服务跑在 istio 上,也可以修改 istiod 配置,加上 PILOT_HTTP10: 1 的环境变量来启用 HTTP/1.0,这个在 TCM 中已产品化,可以在网格基本信息页面的高级设置中开启:




访问 StatefulSet Pod IP 返回 404

现象

在 istio 中业务容器访问同集群一 Pod IP 返回 404,在 istio-proxy 中访问却正常。

原因

Pod 属于 StatefulSet,使用 headless service,在 istio 中对 headless service 的支持跟普通 service 不太一样,如果 pod 用的普通 service,对应的 listener 有兜底的 passthrough,即转发到报文对应的真实目的IP+Port,但 headless service 的就没有,我们理解是因为 headless service 没有 vip,它的路由是确定的,只指向后端固定的 pod,如果路由匹配不上就肯定出了问题,如果也用 passthrough 兜底路由,只会掩盖问题,所以就没有为 headless service 创建 passthrough 兜底路由。同样的业务,上了 istio 才会有这个问题,也算是 istio 的设计或实现问题。

示例场景

使用了自己的服务发现,业务直接使用 Pod IP 调用 StatefulSet 的 Pod IP。

解决方案

使用网格一般不要直接访问 Pod IP,应该访问 service。如果实在有场景需要,同集群访问 statefulset pod ip 时带上 host,可以匹配上 headless service 路由,避免匹配不到发生 404。