ThinkPHP6 实现1万并发限流需Nginx+PHP中间件+Redis原子脚本+系统资源四层协同,单靠控制器incr或throttle配置必然失效;Nginx层用limit_conn_zone双区限流,PHP层须自定义Redis Lua原子限流中间件。

ThinkPHP6 实现 1 万并发限流,不能只靠单一层级的配置,必须是「Nginx + PHP 中间件 + Redis 原子脚本 + 系统资源」四层协同。单独在控制器里写 $redis->incr() 或只配 throttle:100,1,面对真实万级并发会完全失效——计数错乱、IP 识别失真、缓存锁竞争、连接耗尽都会立刻暴露。
一、Nginx 层:先拦住 TCP 连接洪峰
这是第一道防线,防止恶意扫描或短连接风暴直接打穿 PHP 进程。不依赖 PHP,纯 Nginx 内存计数,毫秒级响应。
- 在
/etc/nginx/nginx.conf的http{}块中定义两个独立限流区:
limit_conn_zone $server_name zone=allsrv:10m;
- 在站点
server{}块内启用双层控制(示例):
limit_conn allsrv 10000; # 全局最多 1 万并发连接
limit_conn_status 429;
limit_conn_log_level warn;
- 对高敏感路径(如
/api/admin)加路由级限制:
limit_conn perip 5;
limit_conn allsrv 500;
}
注意:$binary_remote_addr 比 $remote_addr 节省内存 60% 以上,10m 区域能存约 16 万个 IP 计数器。
二、PHP 中间件层:按接口+IP 维度精准限流
内置 throttle 中间件在万级并发下不可靠:file 缓存锁死、key 冲突、IP 获取错误。必须自定义中间件,用 Redis Lua 保证原子性。
立即学习“PHP免费学习笔记(深入)”;
- 创建
app/middleware/ApiRateLimit.php:
namespace app\middleware;
use think\Request;
use think\Response;
use think\facade\Cache;
class ApiRateLimit
{
public function handle(Request $request, \Closure $next): Response
{
$ip = $request->header('X-Real-IP', $request->ip());
$route = $request->rule() ?: $request->path();
$key = 'rate:api:' . md5($route) . ':' . $ip;
$max = 100; // 每分钟 100 次
$ttl = 60;
$lua = "local current = redis.call('incr', KEYS[1]) if current == 1 then redis.call('expire', KEYS[1], ARGV[1]) end if current > tonumber(ARGV[2]) then return 0 else return current end";
$redis = Cache::store('redis')->getHandler();
$count = $redis->eval($lua, [$key], 1, $ttl, $max);
if ($count === 0) {
return json(['code' => 429, 'msg' => 'Too Many Requests'], 429)
->header('Retry-After', '60');
}
return $next($request);
}
}
- 在
app/route/app.php中绑定到 API 分组:
Route::get('users', 'Api/UserController@index');
})->middleware(\app\middleware\ApiRateLimit::class);
关键点:Lua 脚本一次性完成 INCR + EXPIRE + 判断,彻底避免竞态;key 含 route 和 IP,杜绝共享计数;使用 X-Real-IP(需 Nginx 配置透传)而非 X-Forwarded-For 防伪造。
三、Redis 与系统层:支撑万级稳定运行
没有底层保障,再好的逻辑也会在压测中崩塌。
-
Redis 配置:确保
config/cache.php中默认驱动为redis,且连接池健康。禁用file驱动——它在并发下因文件锁导致计数偏差超 40%。 -
Nginx worker 调优:在
nginx.conf中设worker_processes auto;和worker_connections 10240;,并确认系统ulimit -n≥ 10240 × worker 数量。 -
PHP-FPM 适配:
pm.max_children至少设为 200(对应 1 万并发 ÷ 平均每进程处理 50 连接),pm.start_servers设为 50,避免动态伸缩延迟。 -
可信代理配置:在
config/app.php中设置'trusted_proxies' => ['127.0.0.1'],确保框架正确解析X-Real-IP。
四、验证与观测要点
不验证的配置等于没配。
- 用
ab -c 500 -n 5000 http://your.app/api/users测试,观察 Nginx error.log 是否出现大量limit_connwarn 日志; - 用
redis-cli keys "rate:api:*"查看 key 分布是否合理,数量是否随 IP 和路由增长; - 检查响应头是否含
Retry-After: 60和状态码429; - 在 ThinkPHP 日志中搜索
ApiRateLimit,确认中间件执行无异常; - 监控 Redis
INFO commandstats中cmdstat_eval的调用量和耗时,超 5ms 需优化 Lua 或升级 Redis 版本。
真正扛住 1 万并发,靠的不是某个“神奇参数”,而是每一层都守住自己的边界:Nginx 拦连接、中间件控请求、Redis 保原子、系统给足资源。漏掉任何一环,流量都会从缝隙里冲垮服务。



















