把Nginx换成Envoy后,我们踩到的7个坑

举报
i-WIFI 发表于 2025/07/26 10:45:48 2025/07/26
【摘要】 背景交代:公司ToB SaaS业务,QPS峰值8k,原架构是Nginx + Lua做流量网关。为了对接Istio、顺手蹭Envoy的observability,我们拍板——“无痛”迁移。结果从立项到全量灰度花了6周,踩坑无数。下面把血泪笔记整理出来,供后来人“无痛”翻坑。 1. 为什么要换?坦白说,最初的理由只有两个:老板在PPT上看到Envoy能“自动熔断”和“分布式tracing”。运维...

背景交代:
公司ToB SaaS业务,QPS峰值8k,原架构是Nginx + Lua做流量网关。为了对接Istio、顺手蹭Envoy的observability,我们拍板——“无痛”迁移。结果从立项到全量灰度花了6周,踩坑无数。下面把血泪笔记整理出来,供后来人“无痛”翻坑。


1. 为什么要换?

坦白说,最初的理由只有两个:

  • 老板在PPT上看到Envoy能“自动熔断”和“分布式tracing”。
  • 运维受够了Nginx reload时5~10秒的502高峰。

技术选型会上,我默默列了张对比表,原以为能劝退,结果老板一句“长期价值”就给过了……

维度 Nginx (1.24) Envoy (1.28) 备注
热更新 reload 5-10s 零中断 运维最爱
熔断/重试配置粒度 location级 路由级 细到header
可观测性 stub_status 原生Prometheus 省一个Exporter
Lua扩展 没有 后面细说
内存占用 ~30 MB ~90 MB 贵了三倍

2. 坑1:Lua脚本没法平迁

Nginx时代我们写了3k行Lua做鉴权、灰度、ABTest。Envoy官方推荐用Lua Filter,但实测发现:

  • Lua版本只支持5.1,连table.pack都没有。
  • 每个worker独立VM,全局缓存要用shared dict,迁移成本爆炸。

最终妥协:把最重的鉴权逻辑拆成Go的External Authorization Server,Envoy只留轻量级灰度逻辑。多了一次RTT,但CPU反而降了5%,因为Go的垃圾回收比LuaJIT的GC压力小。


3. 坑2:metrics名字长到让Grafana崩溃

Envoy默认metrics格式长成这样:

envoy_cluster_upstream_rq_retry{cluster="user-svc",env="prod"} 123

Prometheus一拉就是3w+条。我们用了官方的stats-matcher正则过滤,把.*circuit_breakers.*等不关心的维度全干掉,磁盘瞬间少了70%。过滤前后对比如下:

指标 过滤前 过滤后
活跃metrics数 31,042 4,198
5分钟抓取耗时 4.8s 0.9s
SSD占用/天 2.1GB 680MB

4. 坑3:HTTP/2 并发流控被打爆

上线第二天,用户反馈上传大文件必超时。抓包一看:Envoy默认initial_window_size只有64 KB,文件上传时流控窗口瞬间被耗尽。
解决办法:把initial_window_size调到1 MB,同时把max_concurrent_streams从100提到500(再高客户端hold不住)。
调优后,99线RT从3.2s降到1.1s。


5. 坑4:TLS指纹导致老安卓App握手失败

Nginx用的是OpenSSL 1.1.1,Envoy默认BoringSSL。两者TLS指纹不一致,结果线上统计到Android 7.0以下机型握手失败率2.8%。
临时方案:

  1. 在Listener层加match_typed_filter_chain,降级到TLS 1.2;
  2. 对老UA单独打标,切到“兼容”集群。
    一周后失败率降到0.1%。

6. 坑5:灰度发布忘记关“全局限速”

Envoy的local_rate_limit是全局token桶,上线时直接套用了demo配置:100 rps。结果我们8k QPS一进来直接熔断,整站503两分钟。
复盘:任何灰度发布,先把限流调到10倍QPS再缩回去,别嫌麻烦。


7. 坑6:日志格式不兼容ELK

Nginx日志是经典的$remote_addr - $user [$time_local]格式,而Envoy默认JSON,字段名全是request_idupstream_cluster之类的驼峰。
我们写了个Logstash Ruby filter做字段映射,跑了两天又发现:某些字段值里有未转义的双引号,导致JSON解析失败。
最后干脆放弃,改走Envoy的access_log_formatter自定义成Nginx兼容格式,ELK侧零改动。


8. 坑7:控制面竟比数据面先挂

Envoy依赖Pilot(Istiod)下发xDS。压测时发现:Istiod OOM重启期间,Envoy拿不到新路由,老路由还缓存着,导致切流失败。
解决:

  • 把Istiod内存从2G调到8G(简单粗暴);
  • 给Envoy加--concurrency=4限制线程,减少xDS推送压力;
  • 预热阶段用静态bootstrap兜底,防止完全失联。

总结:一句话看清ROI

项目 数值
迁移周期 6周
人肉投入 3人*6周 ≈ 432工时
P99延迟下降 25%
502错误率下降 从0.8%到0.02%
运维人肉reload次数 ∞ → 0

值不值?老板看完报表说“明年给网关团队加预算”。
我的教训是:别信“无痛”两个字,把预期调到“有痛可救”,才是Envoy的正确打开方式。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。