本文目录导读:

- 方案一:基于 Nginx 的 URI/Header/Cookie 分流(最推荐)
- 方案二:基于网关(APISIX/Kong)的分流
- 方案三:基于 PHP-FPM 多实例 + 项目目录隔离
- 方案四:基于 Docker/K8s 的 Service Mesh
- 方案五:基于 DNS 的简单分流(不推荐)
- 总结建议
针对 PHP 项目多版本并存的分流需求,核心目标通常是灰度发布、A/B测试或平滑升级,实现方案主要分为三大类:网关层分流、负载均衡层分流和应用层/容器层分流。
以下是几种经过生产验证的成熟方案,按推荐程度排序:
基于 Nginx 的 URI/Header/Cookie 分流(最推荐)
这是最灵活、性能最高的方案,不依赖业务代码,直接在入口层完成分发。
适用场景:
- 灰度发布(让部分用户先体验新版)
- A/B 测试(根据 User-Agent、Cookie 等特征分流)
基本配置示例(Nginx):
upstream old_php {
server 127.0.0.1:9000; # 老版本 PHP-FPM
}
upstream new_php {
server 127.0.0.1:9001; # 新版本 PHP-FPM
}
server {
listen 80;
server_name example.com;
location / {
# 条件1:根据 Cookie 分流(如灰度用户标记)
if ($http_cookie ~* "version=new") {
set $php_backend "new_php";
}
# 条件2:根据 IP 分流(测试人员)
if ($remote_addr ~* "192.168.1.100") {
set $php_backend "new_php";
}
# 默认走老版本
if ($php_backend = "") {
set $php_backend "old_php";
}
# 动态传递到对应版本的 PHP-FPM
fastcgi_pass $php_backend;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
}
}
高级用法(权重分流):
split_clients "${remote_addr}${http_user_agent}" $version_tag {
10% "new"; # 10% 流量走新版
* "old"; # 其余走旧版
}
location / {
if ($version_tag = "new") {
fastcgi_pass 127.0.0.1:9001;
}
fastcgi_pass 127.0.0.1:9000;
}
优点:对应用透明,性能损耗极小。
缺点:需要 Nginx 重启或 reload。
基于网关(APISIX/Kong)的分流
适用于微服务架构,或需要动态调整分流规则而不重启服务的场景。
以 Apache APISIX 为例:
可以通过 traffic-split 插件实现。
# 路由配置
- uri: /api/v1/*
upstream_id: old-upstream-id
plugins:
traffic-split:
rules:
- weighted_upstreams:
- upstream:
name: new-version-upstream
nodes:
"127.0.0.1:9001": 1
weight: 10 # 10% 流量
- # 剩下的 90% 自动走默认 upstream
优点:可动态调整比例(无需重启)、支持请求重放、支持金丝雀发布。
缺点:需要引入额外组件,运维复杂度稍高。
基于 PHP-FPM 多实例 + 项目目录隔离
适用于同一个代码库但需运行不同版本 PHP(如 PHP 7.4 和 PHP 8.2)。
步骤:
- 启动两个 PHP-FPM 实例(监听不同端口)。
# 启动 PHP 7.4 /usr/sbin/php-fpm7.4 --fpm-config /etc/php/7.4/fpm/php-fpm.conf -p /var/run/php7.4/ # 启动 PHP 8.2 /usr/sbin/php-fpm8.2 --fpm-config /etc/php/8.2/fpm/php-fpm.conf -p /var/run/php8.2/
-
项目目录独立:
/var/www/old_project/→ 指向 PHP 7.4 版本代码/var/www/new_project/→ 指向 PHP 8.2 版本代码(或同一代码但不同分支)
-
Nginx 配置(按域名/路径分发):
server {
listen 80;
server_name old.example.com;
root /var/www/old_project;
fastcgi_pass 127.0.0.1:9000;
}
server {
listen 80;
server_name new.example.com;
root /var/www/new_project;
fastcgi_pass 127.0.0.1:9001;
}
基于 Docker/K8s 的 Service Mesh
适合容器化、Kubernetes 环境,利用 Istio 或 Linkerd 进行精细流量治理。
核心思路(K8s + Istio):
- 部署两个
Deployment:php-v1(旧版)、php-v2(新版) - 通过
VirtualService定义权重路由:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: php-service
spec:
hosts:
- php-service
http:
- match:
- headers:
x-version:
exact: v2
route:
- destination:
host: php-service
subset: v2
- route:
- destination:
host: php-service
subset: v1
weight: 90
- destination:
host: php-service
subset: v2
weight: 10
优点:完全声明式、天然支持弹性伸缩、可观测性强。
缺点:需要完整 K8s 基础设施,投入较大。
基于 DNS 的简单分流(不推荐)
做法:配置不同二级域名指向不同服务器参数。
v1.app.com → 192.168.1.10 (旧版)
v2.app.com → 192.168.1.11 (新版)
适用:极简单的环境隔离(开发/测试/生产互不干扰)。
缺点:无法实现细粒度灰度,切换需要 DNS 生效时间。
总结建议
| 场景 | 推荐方案 |
|---|---|
| 单机/低并发 | Nginx Cookie/IP 分流 + 多 PHP-FPM 进程 |
| 中大型微服务 | APISIX / Kong 网关分流 |
| 容器化/K8s 环境 | Istio + VirtualService 权重路由 |
| 只想测试新版本 | 单独域名 + Nginx proxy_pass 到不同后端 |
| 极简管理 | 通过 supervisor 管理多个 PHP-FPM + 软链接切换目录(不推荐生产) |
注意事项:
- Session 共享:多版本分流时注意 Session 存储(建议使用 Redis),否则用户在不同版本间切换会丢失登录状态。
- 数据库兼容:旧版代码可能不支持新版数据库字段变更,建议先做只读灰度。
- 监控:务必监控两个版本对应的 PHP-FPM 进程的
max_children和慢日志。
如果你能提供更多细节(如项目架构、是否容器化、并发量级),我可以给出更精确的配置示例。