PHP项目中如何高效使用Workerman?从入门到实战指南
目录导读
- Workerman是什么?为什么选它?
- 环境要求与安装步骤
- 核心概念:进程、连接、事件
- 搭建一个简单的WebSocket聊天室
- 结合Laravel框架实现实时消息推送
- 常见问题与问答
- 性能调优与最佳实践
- Workerman在项目中的落地策略
Workerman是什么?为什么选它?
核心定义
Workerman是一款纯PHP开发的开源高性能异步网络通信框架,它无需扩展、无需nginx/apache,直接基于PHP的socket和事件循环机制,支持TCP、UDP、WebSocket、HTTP等协议。

与传统的PHP-FPM模式对比
| 维度 | PHP-FPM(传统) | Workerman |
|---|---|---|
| 运行模型 | 请求-响应,进程短生命周期 | 常驻内存,事件驱动 |
| 连接管理 | 每个请求新建进程 | 单进程可处理数千并发连接 |
| 实时推送 | 需轮询或依赖第三方 | 原生支持WebSocket/长连接 |
| 性能 | 受限于进程频繁创建销毁 | 内存常驻,毫秒级响应 |
适用场景
- 即时通讯:聊天、客服、直播弹幕
- 物联网(IoT):设备数据采集、指令下发
- 游戏服务端:实时对战、状态同步
- API网关:长连接聚合、负载均衡
- 定时任务:替代crontab的常驻调度器
问答:
问:Workerman是否适合高并发场景?
答:是的,单台机器使用Workerman可支持数万并发TCP连接,同时得益于PHP的select/epoll事件轮询,CPU占用远低于同等数量的PHP-FPM进程,实测某日活百万的IM系统,使用Workerman的WebSocket服务器,单机稳定承载2万在线用户。
环境要求与安装步骤
环境要求
- PHP版本:
>=5.4(推荐4+或x) - 扩展:
posix、pcntl(Linux必需)、sockets(建议开启) - 操作系统:Linux最佳(Windows可开发,生产环境不建议)
安装方式
Composer(推荐)
composer require workerman/workerman
手动下载
- 访问GitHub仓库:[workerman/workerman](已替换域名)
- 解压后引入
Autoloader.php
验证安装
创建test.php:
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
$worker = new Worker('http://0.0.0.0:8080');
$worker->onMessage = function($connection, $data) {
$connection->send('Hello Workerman!');
};
Worker::runAll();
在终端运行:php test.php start,访问http://你的IP:8080应看到响应。
问答:
问:为什么我的Workerman启动后报错require_once找不到文件?
答:检查Composer是否已正确安装依赖,确保vendor/autoload.php存在,若是手动下载,确认Workerman.php文件路径正确,并正确注册了自动加载。
核心概念:进程、连接、事件
进程模型
- Master进程:负责监控子进程,处理信号(如重启、停止)
- Worker进程:实际处理业务逻辑,数量可设置(默认4个)
- Connection对象:代表一个客户端连接,拥有
send、close等方法
事件回调
Workerman通过事件驱动业务,最常用的三个回调:
onConnect:新连接建立时触发(如用户上线)onMessage:收到客户端消息时触发(核心业务入口)onClose:连接断开时触发(如用户下线清理)
示例:带心跳的TCP服务器
$worker = new Worker('tcp://0.0.0.0:5678');
$worker->onConnect = function($conn) {
// 给每个连接设置超时检测(30秒无消息断开)
$conn->maxSendBufferSize = 102400;
echo "新连接: {$conn->id}\n";
};
$worker->onMessage = function($conn, $data) {
if (trim($data) === 'ping') {
$conn->send('pong');
} else {
// 业务逻辑处理
}
};
$worker->onClose = function($conn) {
echo "连接断开: {$conn->id}\n";
};
问答:
问:Workerman的Worker进程数如何设置最佳?
答:一般设置为CPU核心数的2~3倍,例如4核CPU可设置8~12个进程,注意:每个Worker进程独立运行,内存占用会叠加,可在Worker::$count = 4;中调整。
实战一:搭建简单的WebSocket聊天室
完整代码
<?php
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
// 创建WebSocket服务器
$ws_worker = new Worker('websocket://0.0.0.0:2346');
$ws_worker->count = 2; // 2个进程
$ws_worker->name = 'ChatServer';
// 存储所有连接的用户信息
$connections = [];
$ws_worker->onConnect = function($connection) {
echo "用户{$connection->id}连接\n";
};
$ws_worker->onMessage = function($connection, $data) use (&$connections) {
// 首次消息视为用户名注册
if (!isset($connection->username)) {
$connection->username = trim($data);
$connections[$connection->id] = $connection;
// 广播新用户上线
foreach ($connections as $conn) {
$conn->send("系统: {$connection->username} 加入了聊天室");
}
return;
}
// 群发消息
$message = $connection->username . ': ' . $data;
foreach ($connections as $conn) {
$conn->send($message);
}
};
$ws_worker->onClose = function($connection) use (&$connections) {
// 用户离开,广播通知
if (isset($connection->username)) {
unset($connections[$connection->id]);
foreach ($connections as $conn) {
$conn->send("系统: {$connection->username} 离开了聊天室");
}
}
};
Worker::runAll();
运行测试
- 启动:
php chat.php start -d(-d表示守护进程) - 浏览器打开WebSocket测试工具(如
wscat),连接ws://你的IP:2346 - 发送第一条消息作为用户名,之后可自由聊天
问答:
问:为什么客户端连接后,服务器没有收到消息?
答:检查防火墙是否开放了2346端口,WebSocket握手需要HTTP协议升级,确保客户端使用ws://而非wss://(安全连接需额外配置SSL)。
实战二:结合Laravel框架实现实时消息推送
场景描述
用户提交表单后,需要实时通知后台管理员,传统方式需要轮询,使用Workerman可主动推送。
实现架构
- Laravel应用:处理HTTP请求,写入消息到Redis List
- Workerman服务:订阅Redis,当有新数据时推送到已连接的管理端
关键代码
Laravel端(消息入队)
// Controller
public function submitOrder(Request $request) {
// 保存订单逻辑...
Redis::lpush('new_orders', json_encode(['order_id' => 123, 'time' => now()]));
return response()->json(['status' => 'success']);
}
Workerman端(消费队列并推送)
<?php
use Workerman\Worker;
use Workerman\Lib\Timer;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('websocket://0.0.0.0:2347');
$worker->count = 1;
$admin_connections = [];
$worker->onConnect = function($connection) use (&$admin_connections) {
$admin_connections[$connection->id] = $connection;
echo "管理员连接: {$connection->id}\n";
};
$worker->onClose = function($connection) use (&$admin_connections) {
unset($admin_connections[$connection->id]);
};
// 定时器:每秒轮询Redis
Timer::add(1, function() use (&$admin_connections) {
if (empty($admin_connections)) return;
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$order_json = $redis->lPop('new_orders');
if ($order_json) {
foreach ($admin_connections as $conn) {
$conn->send($order_json);
}
}
});
Worker::runAll();
问答:
问:为什么不用Laravel自带的队列直接推送?
答:Laravel队列需配合Supervisor等进程管理器,且无法直接维持WebSocket长连接,Workerman作为独立服务,既处理WebSocket推送,又通过Redis解耦,不阻塞Laravel的HTTP请求处理。
常见问题与问答
问题1:Workerman在Windows下总是报错?
答: Windows不支持pcntl扩展,部分功能受限,建议:
- 开发阶段:使用
php start.php start(不带-d,前台运行) - 生产环境:务必使用Linux
问题2:如何重启Workerman服务?
答:
# 平滑重启(不中断现有连接) php start.php reload # 停止所有进程 php start.php stop # 查看运行状态 php start.php status
问题3:连接数过多导致内存溢出?
答: 设置连接级缓冲区限制:
$connection->maxSendBufferSize = 102400; // 限制发送缓冲区100KB $connection->maxPackageSize = 102400; // 限制单包大小100KB
同时开启Worker::$logFile记录异常日志。
问题4:如何在分布式环境中共享连接状态?
答: 使用Redis或数据库存储用户-连接映射。
- 用户登录时:
Redis::hSet('user_connections', $userId, $connection->id) - 推送时:从Redis获取connection ID,通过通道通信(如Workerman的
Channel组件)
性能调优与最佳实践
核心调优参数
// 在启动文件前设置 Worker::$stdoutFile = '/dev/null'; // 关闭标准输出 Worker::$logFile = '/tmp/workerman.log'; Worker::$maxWorkerBufferSize = 2*1024*1024; // 每个进程最大内存2MB // 设置打开文件数(Linux) // 在终端执行:ulimit -n 65535
安全加固
- 使用
$connection->getRemoteIp()限制来源IP - 对WebSocket消息做长度限制:
if (strlen($data) > 10240) { // 限制10KB $connection->close("消息过长"); } - 启用SSL加密(wss协议):
$context = [ 'ssl' => [ 'local_cert' => '/path/to/cert.pem', 'local_pk' => '/path/to/private.key', ] ]; $worker = new Worker('websocket://0.0.0.0:443', $context); $worker->transport = 'ssl';
日志与监控
- 使用
Worker::$logFile记录报错信息 - 集成Prometheus:在定时任务中统计连接数、消息吞吐量
- 配合
HealthCheck定时器:每5秒检查内存占用,超过阈值自动重启
问答:
问:Workerman运行时CPU占用100%怎么办?
答:通常是死循环或无效循环导致,检查onMessage中是否有while(true)未正确退出,使用Worker::safeSleep(0.1)在定时任务中释放CPU。
Workerman在项目中的落地策略
适合集成的项目阶段
- 新项目:优先使用Workerman作为长连接服务,替代传统的ajax轮询
- 遗留系统:在边缘模块(如聊天、通知)引入,通过Redis/消息队列与主系统解耦
- 物联网项目:Workerman+MQTT协议,实现设备端到服务端的高效通信
不建议使用的场景
- 纯HTTP RESTful API(Nginx/php-fpm更成熟)
- 单页应用的前端路由(应由前端框架处理)
- 仅需要定时任务(使用crontab更轻量)
学习路线建议
- 掌握基础用法:TCP/WebSocket服务器、定时器、多进程
- 研究
GatewayWorker框架(Workerman的增强版,支持分布式) - 深入源码:理解事件循环、进程间通信机制
最后提醒: Workerman是PHP开发者突破“PHP只能做Web”认知的利器,本文中所有代码示例均可直接运行,建议动手搭建一个简单的推送服务,体会常驻内存带来的性能飞跃。