apache 本身不原生支持 websocket 代理,需依赖 mod_proxy_wstunnel 模块实现反向代理;高负载下“内存泄漏”多为连接未释放、缓冲区失当或 mpm 模型不匹配所致,应禁用缓冲、启用 event mpm、限制进程生命周期、透传 upgrade 头并配合后端心跳与 close 帧确保连接及时回收。
apache 本身并不原生支持 websocket 代理(不像 nginx 或 haproxy),若你在用 apache 做 websocket 流量转发,实际通常是借助 mod_proxy_wstunnel 模块实现的反向代理。而高负载下出现的“内存泄漏”,多数并非真正意义上的 c 级别内存泄露,而是连接未及时释放、缓冲区配置失当、或模块在长连接场景下资源复用不足导致的内存持续增长、无法回收——这在 apache 的 prefork 或 worker mpm 下尤为明显。
以下是针对 Apache + mod_proxy_wstunnel 架构下解决高负载内存问题的实用路径:
关键配置收紧:禁用缓冲、限制生命周期
Apache 默认对代理连接启用缓冲和超时宽松策略,这对短连接友好,但会加剧 WebSocket 场景下的内存驻留:
-
关闭代理缓冲:
ProxyRequests Off ProxyPreserveHost On ProxyTimeout 60 # 禁用所有缓冲行为(关键!) SetEnv nokeepalive 1 SetEnv downgrade-1.0 1 SetEnv force-response-1.0 1
-
强制使用 HTTP/1.1 并透传升级头(否则握手失败,连接反复重试):
ProxyPass /ws/ ws://backend:3000/ws/ ProxyPassReverse /ws/ ws://backend:3000/ws/ # 必须显式设置,否则 upgrade 被丢弃 RewriteEngine On RewriteCond %{HTTP:Upgrade} =websocket [NC] RewriteRule /ws/(.*) ws://backend:3000/ws/$1 [P,L] # 或在 ProxyPass 后补充: ProxySet keepalive=Off
MPM 模式与进程管理必须匹配长连接特性
Apache 的 prefork(多进程)模型在 WebSocket 场景下极易因每个连接独占一个子进程而导致内存爆炸;worker/event 模型更合适,但仍需调优:
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
- 推荐启用
eventMPM(Apache 2.4+):# httpd.conf 中确认加载 LoadModule mpm_event_module modules/mod_mpm_event.so
- 严格限制单个子进程寿命与连接数:
<ifmodule mpm_event_module> StartServers 4 MinSpareThreads 25 MaxSpareThreads 75 ThreadsPerChild 100 # 每进程最多处理 100 个并发连接(含 WS) MaxRequestWorkers 400 # 总并发上限,避免 OOM MaxConnectionsPerChild 1000 # 连接数达限时回收进程,防内存累积 </ifmodule>
关闭非必要模块与日志,减少运行时开销
高频 WebSocket 流量下,每条请求触发的模块链路越短,内存抖动越小:
- 禁用
mod_deflate(压缩在 WebSocket 层由业务控制,Apache 压缩会缓存上下文) - 关闭访问日志:
CustomLog /dev/null common ErrorLog /dev/null LogLevel warn
- 移除未使用的模块(如
mod_php,mod_perl),仅保留mod_proxy,mod_proxy_wstunnel,mod_rewrite,mod_headers
后端健康联动:避免僵尸连接堆积
Apache 不主动探测后端 WebSocket 服务是否存活,若后端崩溃或网络中断,Apache 可能长期维持半开连接:
- 配置
ProxyBadHeader Ignore防止因后端响应异常头导致连接卡住 - 加入简单健康检查路由(如
/health),配合外部巡检脚本重启异常 Apache 实例 - 后端务必实现标准心跳(ping/pong),并在断连时主动发送
Close帧——Apache 依赖此帧触发连接清理
监控与兜底:定位真实瓶颈点
内存上涨不等于泄漏,先确认是哪个层级吃掉内存:
- 用
pmap -x $(pgrep apache2 | head -1)查看单个 worker 内存分布,重点关注anon区域是否随连接数线性增长 - 若
httpd进程 RSS 持续上升且MaxConnectionsPerChild未生效,说明连接未正常关闭 → 检查后端是否漏发Close或客户端未正确处理onclose - 使用
mod_status(启用ExtendedStatus On)观察S列状态:大量W(Sending Reply)或K(Keepalive)表示连接滞留,而非泄漏
不复杂但容易忽略










