背景

某线上生产环境反馈部分业务功能不可用了,通过登录环境排查,发现envoy网关pod全部状态异常,通过重启pod无法拉起。

网关崩溃处理过程

当时第一次重启网关pod无法拉起的情况下,查看了相关网关日志,发现网关日志报健康检查通不过,后来尝试进入网关pod控制器,删除对应服务控制器的探针配置,重启pod,pod可以正常running一会,还是再会挂掉,在查看网关日志,发现网关存在崩溃,崩溃日志只展示部分如下:

 StreamInfoImpl 0x566959139990, protocol_: 1, response_code_: null, response_code_details_: null, attempt_count_: null, health_check_request_: 0, route_name_:     upstream_info_: 
      UpstreamInfoImpl 0x5669748a6600, upstream_connection_id_: null
    OverridableRemoteConnectionInfoSetterStreamInfo 0x566959139990, remoteAddress(): x.x.x.x:62534, directRemoteAddress(): x.x.x.x:62534, localAddress(): x.x.x.x:8080
Http1::ConnectionImpl 0x56695ab9c008, dispatching_: 1, dispatching_slice_already_drained_: 1, reset_stream_called_: 0, handling_upgrade_: 0, deferred_end_stream_headers_: 0, require_strict_1xx_and_204_headers_: 0, send_strict_1xx_and_204_headers_: 1, processing_trailers_: 0, no_chunked_encoding_header_for_304_: 1, buffered_body_.length(): 1300, header_parsing_state_: Done, current_header_field_: , current_header_value_: 
active_request_: 
, request_url_: null, response_encoder_.local_end_stream_: 0
absl::get<RequestHeaderMapPtr>(headers_or_trailers_): null
, current_dispatching_buffer_: nullConnectionImpl 0x56695ab0e000, connecting_: 0, bind_error_: 0, state(): Open, read_buffer_limit_: 1048576
socket_: 
  ListenSocketImpl 0x56695aa7b800, transport_protocol_: raw_buffer
  connection_info_provider_: 
    ConnectionInfoSetterImpl 0x56695ab25eb0, remote_address_: x.x.x.x:62534, direct_remote_address_: x.x.x.x:62534, local_address_: x.x.x.x:8080, server_name_: 
2025-06-13T00:55:23.713609Z	info	ads	ADS: "@" sino-nginx-prod-7cc5c4887d-2l86k.cms-v6-prod-1 terminated
2025-06-13T00:55:23.713676Z	info	ads	ADS: "@" sino-nginx-prod-7cc5c4887d-2l86k.cms-v6-prod-2 terminated
2025-06-13T00:55:23.715081Z	error	failed scraping envoy metrics: error scraping http://localhost:15090/stats/prometheus: Get "http://localhost:15090/stats/prometheus": read tcp [::1]:41584->[::1]:15090: read: connection reset by peer
2025-06-13T00:55:23.715860Z	error	Epoch 0 exited with error: signal: segmentation fault (core dumped)
2025-06-13T00:55:23.715924Z	info	No more active epochs, terminating

当时根据日志,当时创建envoyfilter设置max_request_bytes的大小,进行恢复。

网关崩溃问题分析

1、部署模拟测试场景,根据报错日志进行故障模拟。
根据envoy官方提供的文件上传模拟最大请求字节数案例进行部署测试场景,相关地址如下:

https://github.com/jewertow/istio-playground/tree/master/issues/ext-authz-max-requests-bytes-413-payload-too-large

1.1、官方测试场景:

测试场景一 没有创建envoyfilter,默认request大小10M,buffer大小默认1M,模拟100M大文件上传

测试命令如下(官方提供的命令):

curl -v POST -H “x-ext-authz: allow” -F ‘data=@test.txt’
http://10.10.10.10:3000/file-upload/upload?key=TESTUSER

测试结果如下:
在这里插入图片描述
测试场景二 创建envoyfilter设置request值为12M,模拟100M大文件上传

测试命令如下(官方提供命令):

curl -v POST -H “x-ext-authz: allow” -F ‘data=@test.txt’
http://10.10.10.10:3000/file-upload/upload?key=TESTUSER

测试结果如下:
在这里插入图片描述

如上两个根据官方提供的命令测试均未模拟出故障期间的崩溃问题,在设置limit后只出现了413状态码,已经显示出上传文件过大。

1.2、根据租户侧请求进行模拟请求场景

通过网关崩溃日志发现,存在两处崩溃的日志都有相同的特征

'authorization', ''
'content-type', 'multipart/form-data'
'user-agent', 'okhttp/4.7.2'

崩溃发生在处理分块请求体时:

#1: Envoy::Router::Function::FcpFilter::decodeData() [0xaaaade927e24]
#4: Envoy::Http::Http1::ServerConnectionImpl::onBody()
#5: Envoy::Http::Http1::ConnectionImpl::dispatchBufferedBody()

崩溃可能当空认证头 + okhttp/4.7.2时特定分块大小组合时,根据这两点, 开始准备进行模拟租户侧的请求。

测试场景一、 未创建envoyfilter,模拟请求头包含空的请求头+okhttp/4.7.2

测试命令如下:

curl -v POST -H "authorization: " -H “user-agent:okhttp/4.7.2” -F
‘data=@minio-helm.tar.gz’
http://10.228.38.83:12356/file-upload/upload?key=TESTUSER

测试结果如下,跟当时网关崩溃报错日志吻合:
在这里插入图片描述

测试场景二、 创建envoyfilter,模拟请求头包含空的请求头+okhttp/4.7.2

测试命令如下:

curl -v POST -H "authorization: " -H “user-agent:okhttp/4.7.2” -F ‘data=@minio-helm.tar.gz’ http://10.228.38.83:12356/file-upload/upload?key=TESTUSER

测试结果,会反馈413,如下:

在这里插入图片描述
如上根据模拟租户侧相同的请求,能复现出当时的故障,而创建envoyfilter后就返回413,并没有崩溃。

2、问题总结

在这里插入图片描述
OkHttp使用8KB(8192字节)的缓冲区,当数据块0<size<8192时使用特殊处理进行分块,放入缓冲区,1300字节正好落入到这个危险区间,大量文件上传时,envoy没有对request的大小做任何限制 ( 我们当时认为这个request的默认大小是10M,还在模拟期间产生了疑问,为什么超过10M的文件上传,不会触发envoy的413,看了代码才知道根本没做限制 ) ,触发envoy的缓冲过滤器内存错误如越界访问导致的崩溃,而对网关添加了envoyfilter的request的大小限制,相当于给网关加了一个过载的保护,当上传的文件太大,会触发这个保护机制,拒绝大文件上传,网关不会崩溃掉。

envoy的max_request_bytes部分代码如下:
在这里插入图片描述

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐