redis+lua是workerman实现高可靠限流的核心方案,因其能保证incr与expire原子执行、避免key堆积,支持ip/uid多维秒级或分钟级限流,并通过标准429状态码反馈,配合网关前置与黑名单等防护形成完整防刷体系。

Workerman 5.2.3 本身不内置限流组件,但可通过 Redis + Lua 脚本或内存计数器快速实现可靠、低开销的限流防刷功能。重点在于原子性、时间切片和维度设计,避免 key 泄漏或精度失准。
用 Redis + Lua 实现秒级/分钟级请求限制
适合防登录爆破、短信发送、优惠券领取等场景。必须用 Lua 脚本保证 INCR 和 EXPIRE 原子执行,否则可能计数成功但没设过期,导致 key 持续堆积。
- 键名推荐格式:
rate:ip:{$_SERVER['REMOTE_ADDR']}:1m(按分钟切片)或rate:uid:{uid}:1s(按用户+秒级) - 脚本示例(Lua):
local key = KEYS[1] local limit = tonumber(ARGV[1]) local current = redis.call('INCR', key) if current == 1 then redis.call('EXPIRE', key, ARGV[2]) end return current - 在
onMessage或业务逻辑中调用:$ok = $redis->eval($luaScript, [$key], [$maxCount, $ttl]);
内存计数器(轻量级、无依赖)
适用于单机部署、QPS 不高、且能接受进程重启后计数清零的场景。注意 PHP 进程间不共享内存,需配合 Worker::$pidFile 和全局变量或 APCu。
- 用
$_SERVER或静态数组暂存连接/IP 计数(仅限单 Worker 进程内) - 示例(IP 维度每分钟最多 30 次):
function getIpKey($ip) { return 'rate_ip_' . $ip . '_' . date('YmdHi'); } $key = getIpKey($_SERVER['REMOTE_ADDR']); $count = $_SERVER[$key] ?? 0; if ($count >= 30) { $connection->send(['code'=>429, 'msg'=>'请求过于频繁']); return; } $_SERVER[$key] = $count + 1; - 缺点:多进程下不一致;无法跨机器;需自行清理旧 key(可用定时器或写入时判断时间戳)
结合网关层做接口级令牌桶(推荐生产使用)
把限流前置到入口,减轻业务层压力。Workerman 可作为网关服务,或与 Nginx、Webman 等配合。
- 用 Redis 存储桶状态,Lua 执行「取令牌」逻辑,支持动态配额(如
uid + route组合 key) - 返回标准 HTTP 状态码:429 Too Many Requests,客户端可据此退避重试,避免误当故障反复刷
- 阈值建议:抢单类接口给峰值 QPS 的 1.5 倍;查询类给 3 倍;优惠券类必须带参数维度(如
coupon_id),否则单 ID 刷爆无感知
配套防护不能少
限流只是防刷的一环,需搭配其他措施才真正有效:
- 限制单 IP 最大并发连接数(
$worker->count = 4+onConnect计数) - 对高频 IP 自动加入黑名单(Redis set + TTL,后续请求直接拦截)
- 校验 WebSocket 或 HTTP 请求中的 token、UA、Referer 等字段,过滤明显异常流量
- 记录日志并对接监控(如慢请求、429 频次突增),触发告警人工介入











