apache可通过mod_rewrite提取uid、取末两位作哈希槽(00–99),结合条件路由实现10%灰度分流:00–09走gray组,其余走main组,并透传x-original-uid与x-uid-slot供追踪。

Apache 本身不直接支持按用户 UID 哈希做灰度分流,但可以通过 mod_proxy_balancer 配合 mod_rewrite 和 mod_headers 提取、计算并路由请求,实现稳定、可复现的哈希分组。关键在于:把 UID 提取出来 → 做哈希映射到固定槽位 → 绑定到对应后端分组。
提取 UID 并生成哈希值
需要先从请求中拿到 UID(常见来源:Cookie、Header、Query 参数)。以 Cookie 中 uid=123456 为例:
# 启用必要模块(确保已加载)
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule headers_module modules/mod_headers.so
# 提取 UID 并写入环境变量
RewriteEngine On
RewriteCond %{HTTP_COOKIE} uid=([^;]+) [NC]
RewriteRule ^ - [E=UID:%1]
# 可选:对 UID 做简单哈希(取模 100),存入另一个环境变量
RewriteCond %{ENV:UID} ^(.+)$
RewriteRule ^ - [E=UID_HASH:%1]
SetEnvIf UID_HASH "(.*)" UID_HASH_VAL=$1
# 注意:Apache 不内置哈希函数,需靠外部脚本或用 mod_lua;更常用的是用 mod_rewrite 的正则 + mod_headers 做“伪哈希”(如取 UID 最后两位)
RequestHeader set X-Uid-Hash "expr=%{ENV:UID} ? substr(%{ENV:UID},-2) : '00'"
✅ 实际推荐做法:用
substr(%{ENV:UID},-2)或md5(%{ENV:UID})(需启用mod_lua)生成 0–99 的整数,再通过<if></if>判断分组。
定义蓝绿/灰度后端分组
创建两个独立 balancer,分别代表“主流量组”和“灰度组”:
<proxy balancer:>
BalancerMember http://backend-main-01:8080 route=main01 loadfactor=100
BalancerMember http://backend-main-02:8080 route=main02 loadfactor=100
</proxy><proxy balancer:>
BalancerMember http://backend-gray-01:8080 route=gray01 loadfactor=100
BalancerMember http://backend-gray-02:8080 route=gray02 loadfactor=100
</proxy>
⚠️ 注意:
route=用于会话粘滞(配合JSESSIONID或自定义 cookie),此处非必需,但建议保留便于后续调试。
按 UID 哈希动态路由
利用 mod_rewrite + ProxyPass 条件路由,将哈希值映射为 0–99,灰度比例设为 10%(即 0–9):
# 提取 UID 最后两位作为哈希槽(00–99)
RewriteCond %{HTTP_COOKIE} uid=([0-9]+) [NC]
RewriteCond %1 ^(..)$
RewriteRule ^(.*)$ - [E=UID_SLOT:%1]
# 若 UID 尾号 00–09 → 走灰度组;否则走主组
RewriteCond %{ENV:UID_SLOT} ^0[0-9]$
RewriteRule ^(.*)$ $1 [E=USE_GRAY:1]
# 主路由逻辑:根据环境变量选择 balancer
ProxyPass / balancer://main/ enablereuse=on
ProxyPass / balancer://gray/ enablereuse=on
# 用 RewriteRule + ProxyPassMatch 实现条件代理(Apache 2.4.13+ 支持)
<if>
ProxyPass / balancer://gray/
ProxyPassReverse / balancer://gray/
</if><else>
ProxyPass / balancer://main/
ProxyPassReverse / balancer://main/
</else>
✅ 替代方案(兼容性更好):用
ProxyPassMatch+ 正则匹配路径前缀,或拆成两个虚拟主机 +Include动态加载不同配置,再通过apachectl graceful热切换。
验证与注意事项
- 一致性保障:哈希必须是确定性算法(如取 UID 末两位、MD5 后两位 hex),避免同一 UID 在不同请求中落到不同组。
-
兜底逻辑:未带 UID 的请求默认走主组(加
RewriteCond %{ENV:UID} ^$分流)。 -
Header 透传:确保后端能收到原始 UID 和哈希值,方便日志追踪:
RequestHeader set X-Original-UID "%{ENV:UID}e" env=UID RequestHeader set X-Uid-Slot "%{ENV:UID_SLOT}e" env=UID_SLOT -
不依赖 session 粘滞:灰度是按 UID 而非会话,所以建议
lbmethod=byrequests,关闭 sticky(除非业务强依赖)。
不复杂但容易忽略











