Webman能支撑在线点餐系统,但需规避同步阻塞:订单创建须异步写库、库存扣减用Redis分布式锁、WebSocket推送需消息入队+分组广播、Redis应按缓存/会话/锁拆分实例、Worker进程数须据内存RSS精准计算。

Webman 能撑住在线点餐系统,但直接照搬传统 MVC 写法会在线上崩得很快——订单创建卡顿、菜单加载延迟、多人同时下单时数据库连接池打满,根本不是“并发不够”,而是同步阻塞和路由/IO层没做针对性收敛。
WebSocket 订单状态推送别用 webman_socket_send() 直推
点餐系统里“下单成功→实时推状态给用户/厨房屏”这个环节,如果在 websocket_dispatch 回调里对所有相关连接挨个调 webman_socket_send(),连接数一过 200 就开始抖动。尤其厨房大屏常驻 TCP 连接质量差,单次 send 可能卡 80ms+,整个事件循环被拖住。
- 必须把消息入队后异步批量发送:用
RingBuffer或 Redis List 存待发消息,另起一个Worker进程消费并调webman_socket_send() - 只推给目标连接:订单归属厨房 ID → 哈希到某组 WebSocket 连接池(如
redis:keys kitchen:123:*),不遍历全量webman_get_all_sockets() - 状态变更消息体要精简:只传
order_id、status、updated_at,前端自己拉详情,避免消息体膨胀
config/redis.php 配多实例,别让缓存和会话抢同一连接
点餐系统里菜单、用户会话、订单锁、库存扣减都依赖 Redis,但默认只配了 default 实例,所有 \support\Container::get('redis') 拿的都是同一个连接池,高峰期会互相阻塞。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 至少拆三套:一个专用于缓存(
cache),一个管 session(session),一个做分布式锁(lock) - 库存扣减必须走
lock实例 +SETNX+EXPIRE组合,不能用INCR简单判断——否则超卖 - 菜单数据用
cache实例,键格式统一为menu:list:restaurant_456,设置SETEX300 秒,更新时主动DEL
订单写入必须异步,别在控制器里 INSERT INTO orders
用户点击“提交订单”后,若控制器里直接执行 PDO 插入 + 库存扣减 + 发送通知,三个操作串行阻塞,QPS 瞬间掉一半。Webman 常驻内存模型会让这种阻塞暴露无遗。
- 订单主表插入走
AsyncMysql或协程 MySQL 客户端(如swoole_mysql),确保不卡事件循环 - 库存扣减和通知发 Kafka/RabbitMQ,由独立消费者进程处理;若用 Redis Stream,确保每个消费者组只负责一类动作(如
consumer-group:inventory) - 返回给前端的只是
order_id和status: pending,后续状态变更走 WebSocket 推送,不要等 DB 写完再返回
$worker->count 别按 CPU 核数拍脑袋设
点餐系统是典型的 IO 密集型:查菜单、扣库存、写订单、发通知,大部分时间在等 Redis/MySQL 响应。设成 CPU 核数 × 2 往往导致内存溢出,而设太高又让每个 Worker 进程 RSS 超过 60MB,触发 OOM killer。
- 实测单 Worker RSS:启动后运行 5 分钟,执行
ps aux --sort=-%mem | grep webman | head -5取平均值 - 安全公式:最大
count≈ (服务器总内存 MB × 0.8) ÷ 单 Worker RSS(MB),例如 8GB 内存、实测 RSS 52MB → 最多设 123,取整 120 - 务必在
start.php里设:$worker->count = 120;,而不是 config/server.php —— 后者不生效
真正卡点不在框架选型,而在“哪里该同步、哪里必须异步”的边界意识。比如用户登录态校验可以同步,但订单生成后的短信通知绝对不能同步;菜单渲染可走本地 OPcache,但库存变更必须强一致读 Redis。这些决策比调参更影响上线后的稳定性。


















