那天凌晨三点,我被刺耳的电话铃声惊醒。运维同事急促的声音从听筒传来:"生产环境的API全部超时,Kong网关节点CPU飙到100%,客户投诉已经炸锅了!"这个突如其来的故障,开启了我为期两周的Kong网关深度排障之旅。
我们使用的是Kong 2.8.x版本,部署在Docker Swarm集群上。最初的表现是随机API请求卡住不动,Nginx返回504超时。查看日志发现大量upstream timed out错误,但后端服务监控显示一切正常。更诡异的是,重启Kong容器后问题会暂时消失,但几小时后必定复发。
通过docker stats观察发现,故障时Kong容器的CPU使用率确实达到100%。但用top进入容器内部查看,实际进程CPU占用却不到30%。这种矛盾现象立刻让我联想到Docker的网络性能问题。
关键提示:当容器内外部CPU指标差异较大时,首先怀疑网络栈开销
我们对比了三种Docker网络模式的表现:
| 网络模式 | 吞吐量(QPS) | 平均延迟 | CPU占用 |
|---|---|---|---|
| bridge(default) | 1200 | 85ms | 100% |
| host | 9800 | 12ms | 45% |
| macvlan | 9500 | 14ms | 50% |
测试结果令人震惊——默认的bridge模式性能竟比host模式低8倍!这是因为:
最终我们将docker-compose.yml修改为:
yaml复制services:
kong:
network_mode: "host"
environment:
- KONG_PROXY_LISTEN=0.0.0.0:8000
- KONG_ADMIN_LISTEN=0.0.0.0:8001
这个改动立竿见影:
网络问题解决后,我们又发现限流插件(rate-limiting)经常失效。明明配置了每分钟100次请求的限制,但实际测试时超过200次请求仍能正常响应。
通过分析插件配置发现:
bash复制# 错误配置示例
curl -X POST http://localhost:8001/plugins \
--data "name=rate-limiting" \
--data "config.minute=100" \
--data "config.policy=local"
问题出在policy=local——这个策略只在单节点生效。在集群环境下需要使用redis:
bash复制# 正确配置
curl -X POST http://localhost:8001/plugins \
--data "name=rate-limiting" \
--data "config.minute=100" \
--data "config.policy=redis" \
--data "config.redis.host=redis-service" \
--data "config.redis.port=6379"
默认的限流错误信息是英文的:
json复制{"message":"API rate limit exceeded"}
通过自定义插件实现汉化:
/usr/local/share/lua/5.1/kong/plugins/rate-limiting-zh目录lua复制local RateLimiting = require "kong.plugins.rate-limiting.handler"
local RateLimitingHandler = RateLimiting:extend()
function RateLimitingHandler:deny(conf)
return kong.response.exit(429, { message = "请求过于频繁,请稍后再试" })
end
RateLimitingHandler.PRIORITY = 901
RateLimitingHandler.VERSION = "1.0.0"
return RateLimitingHandler
yaml复制plugins:
- name: rate-limiting-zh
稳定运行两周后,Kong节点开始频繁被OOM Killer终止。通过docker logs看到大量内存不足的警告:
code复制kernel: [ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name
kernel: [12345] 0 12345 1683243 153204 332 0 0 kong
我们建立了完整的内存分析方案:
bash复制watch -n 1 "docker stats --no-stream | grep kong"
bash复制docker exec -it kong kong memory
lua复制collectgarbage("count") -- 打印当前Lua内存使用量
最终定位到一个自定义插件的内存泄漏:
lua复制-- 错误代码示例
local cache = {} -- 模块级变量
function _M:access(conf)
cache[conf.key] = some_data -- 不断增长
end
修复方案:
网络模式选择优先级:
资源限制必须设置:
yaml复制deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
memory: 1G
关键nginx配置调整:
nginx复制worker_processes auto;
worker_rlimit_nofile 1000000;
events {
worker_connections 4000;
multi_accept on;
}
http {
lua_shared_dict prometheus_metrics 10m;
lua_socket_pool_size 512;
}
必须监控的核心指标:
| 指标名称 | 报警阈值 | 检查方法 |
|---|---|---|
| 节点内存使用率 | >80%持续5分钟 | kong.node.get_memory_stats() |
| 数据库连接池使用率 | >90% | pg_stat_activity查询 |
| 请求延迟P99 | >500ms | Prometheus指标 |
| 插件执行错误率 | >1% | 日志分析 |
经历这次事件后,我们最终实施了以下架构改进:
网络层:
部署模式:
监控体系:
这套方案上线后,系统已稳定运行6个月无重大故障。最深刻的体会是:网关类基础设施的问题往往具有放大效应,一个小问题可能导致整个系统瘫痪。预防性监控比事后救火重要十倍。