webman适合做抽奖系统因其支持长连接、多进程和异步io,能精准控制连接状态、对接redis队列与websocket推送,并通过redis原子操作保障库存扣减与幂等性,配合限流、防刷及异步落库等机制应对高并发。

为什么 Webman 适合做抽奖系统
Webman 是基于 Workerman 的轻量级 PHP 框架,天生支持长连接、多进程和异步 IO,对高并发抽奖场景比传统 FPM 架构更可控。它不依赖 Apache/Nginx 的请求生命周期,能直接管理连接状态(比如防刷、排队、实时中奖通知),也更容易对接 Redis 队列或 WebSocket 推送。
- 抽奖核心逻辑(如概率计算、库存扣减)必须放在原子操作里,
Redis::eval或Redis::hIncrBy是首选,不能靠 PHP 层加锁 - Webman 的
onMessage回调是单进程内串行执行的,同一连接不会并发触发,但不同用户连接之间完全并行——这意味着全局共享资源(如奖池余量)必须用外部存储协调 - 别在
onWorkerStart里初始化耗时连接(如 MySQL),容易卡住进程启动;改用连接池或延迟初始化
如何防止重复提交和机器人刷奖
抽奖接口被高频重放或自动化脚本调用,是上线当天最常爆的点。Webman 本身不带限流中间件,得自己搭。
- 对每个
$connection->id记录最近一次抽奖时间戳,用Redis::setex('rate_limit:'.$conn_id, 3, 1)实现 3 秒内仅允许一次请求 - 用户维度限流要结合登录态:如果用了 JWT,从
$request->header('authorization')解出 uid,再用Redis::incr('user:uid:123:count')+expire控制日频次 - 前端按钮点击后立刻置灰 + 后端校验
$_POST['ts']和$_POST['sign'](用 uid + ts + secret 算 HMAC),防抓包重放 - 不要只依赖前端 disable 按钮——网络抖动或刷新会导致重复发包,服务端必须做幂等:用
Redis::set('lottery:log:'.$uid.':'.$ts, 1, ['nx', 'ex' => 60])拦第一道
抽奖结果怎么做到秒级实时通知
中奖后不能只返回 JSON,还得推送给前端页面(尤其是大屏或直播间弹幕),否则体验断层。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- Webman 原生支持 WebSocket,把中奖连接保留在
$connections全局数组里,中奖后直接$connection->send(json_encode([...])) - 但要注意:如果用户中途断连,
$connection可能已失效,发送前先if ($connection->isEstablished()) - 大规模推送别用单进程广播,改走 Redis Pub/Sub:
Redis::publish('lottery:result', json_encode($data)),另起一个 Webman 进程订阅该 channel 并分发到各连接 - 如果用 Swoole 协程风格写法(Webman 1.x 默认不启用),记得所有 Redis 操作都得用
Redis::setOption(Redis::OPT_READ_TIMEOUT, 0.1),避免阻塞整个协程调度
数据库写放大和事务陷阱
很多人把中奖记录、奖品扣减、用户积分更新全塞进一个 MySQL INSERT ... ON DUPLICATE KEY UPDATE,看似原子,实际在高并发下会严重锁表。
- 奖池库存必须用 Redis 扣减:
Redis::decr('prize:1001:stock'),返回值 ≤ 0 就直接拒绝,不进 DB - 中奖记录写入用消息队列异步落库,Webman 内直接
Redis::lPush('queue:lottery_log', json_encode($log)),再由独立消费者进程处理 - MySQL 表结构要避开自增主键热点:用
id CHAR(19)(雪花 ID)代替INT AUTO_INCREMENT,写入分散到不同页 - 别在事务里查 Redis 再写 MySQL——网络延迟不可控,事务持有时间拉长,容易触发死锁或超时
Webman 的优势不在语法糖,而在你能精确控制每个连接的生命期和每个请求的资源边界。真正难的不是“怎么写抽奖”,而是“怎么让十万用户同时点下去时不崩、不错、不慢”。这些细节没压测过,上线就暴露。










