Apache的mod_rewrite本身不支持动态负载分配,但可通过RewriteMap调用外部脚本(如Python)实现轮询、随机等策略,并结合RewriteRule与[P]标志代理转发。

Apache 的 mod_rewrite 本身不直接支持“动态负载分配”这类服务端调度逻辑,但可通过 RewriteMap 调用外部脚本(如 Bash、Python 或 PHP),由脚本实现自定义的分发策略(例如轮询、随机、加权、健康检查后路由等),再将结果返回给 rewrite 引擎完成跳转或重写。关键在于 RewriteMap 的外部程序模式(prg:)与脚本的可靠交互。
启用 mod_rewrite 并配置外部 RewriteMap 支持
确保 Apache 已加载必要模块并允许外部映射:
- 确认
mod_rewrite和mod_env(可选,用于传递环境变量)已启用:a2enmod rewrite(Debian/Ubuntu)或在httpd.conf中取消注释LoadModule rewrite_module modules/mod_rewrite.so - 在主配置(如
/etc/apache2/apache2.conf或虚拟主机块)中启用RewriteEngine on,并声明外部映射:RewriteMap backend "prg:/usr/local/bin/balance.sh"
注意:prg:类型要求 Apache 以子进程方式持续运行该脚本,脚本必须保持 stdin/stdout 打开且能循环读写 - 确保 Apache 用户(如
www-data)对脚本有执行权限:chmod +x /usr/local/bin/balance.sh && chown root:www-data /usr/local/bin/balance.sh
编写可交互的负载分配脚本
脚本需满足:持续运行、按行读取输入(每行一个 key)、按行输出对应值(如后端地址)、不退出、处理异常输入。以下为 Python 示例(保存为 /usr/local/bin/balance.py):
#!/usr/bin/env python3 import sys import random <h1>模拟后端列表(实际可读配置文件、DB 或 API)</h1><p>BACKENDS = ["<a href="https://www.php.cn/link/4fbe9e8a0ace3a44f0a9e1d7fe41da02">https://www.php.cn/link/4fbe9e8a0ace3a44f0a9e1d7fe41da02</a>", "<a href="https://www.php.cn/link/6cf8ae4c2312ba4a0103e20d0ace1ea3">https://www.php.cn/link/6cf8ae4c2312ba4a0103e20d0ace1ea3</a>", "<a href="https://www.php.cn/link/f0b2257261d359354fc5fef47e80e110">https://www.php.cn/link/f0b2257261d359354fc5fef47e80e110</a>"]</p><h1>简单轮询(维护计数器需用文件或 Redis,此处仅示意随机)</h1><p>for line in sys.stdin: line = line.strip() if not line: continue</p><h1>可根据 line(如请求路径、Host、IP hash)做不同策略</h1><pre class="brush:php;toolbar:false;">target = random.choice(BACKENDS) print(target) sys.stdout.flush() # 必须刷新,否则 Apache 会卡住
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
然后在 Apache 配置中改用:RewriteMap backend "prg:/usr/bin/python3 /usr/local/bin/balance.py"
在 RewriteRule 中调用并实现动态路由
利用 ${backend:key} 语法触发脚本,并结合条件和重定向完成负载分配:
- 基础跳转示例(所有
/api/请求分发到动态后端):RewriteCond %{REQUEST_URI} ^/api/RewriteRule ^/api/(.*) ${backend:api}\/$1 [P,L]
其中[P]表示代理转发(需同时启用mod_proxy),key可固定为api,也可用%{REMOTE_ADDR}或%{HTTP_USER_AGENT}做哈希分发 - 若需基于路径前缀区分策略,脚本内可解析输入 key:
Apache 发送user/123→ 脚本返回http://node-a/user→ 规则匹配后重写 - 务必设置超时和错误兜底,例如:
RewriteCond ${backend:%{REQUEST_URI}|NOTFOUND} !NOTFOUNDRewriteRule ^/(.*) ${backend:%{REQUEST_URI}}/$1 [P,L]RewriteRule ^/(.*) http://fallback.example.com/$1 [R=302,L]
注意事项与调试建议
外部脚本模式易出错,部署前需验证稳定性:
-
prg:映射脚本崩溃会导致整个 RewriteMap 失效,Apache 日志中会出现pipe to ... failed错误;建议脚本加入 try/catch 和日志记录 - Apache 启动时即启动脚本进程,重启 Apache 才能重载脚本;修改脚本后需重启服务
- 开启重写日志辅助排查:
LogLevel alert rewrite:trace3(Apache 2.4+),查看error.log中 map 调用过程 - 生产环境慎用
prg:,高并发下脚本 I/O 可能成瓶颈;更稳妥方案是使用txt:(查静态映射表)配合定时更新,或改用专门的反向代理(如 Nginx、HAProxy)承担负载逻辑










