为 RPC 端口和 Websocket 端口配置独立的 Worker 进程
在标准的 Swoole 中,子服务器端口(listen 产生的 Swoole\Server\Port)只能单独设置网络协议参数,无法直接通过 set(['worker_num' => X]) 来独立设置 Worker 进程数量。也就是说,默认情况下它们必然会共享主服务器的 Worker 进程。
为了真正实现 RPC 端口和 Websocket 端口的 Worker 进程隔离,在 think-swoole 架构下有以下两种最佳实践方案:
方案一:通过多进程自定义进程(Process)进行隔离(推荐)
这是在一个 ThinkPHP 项目中实现隔离的最佳方式。让主进程(9512)只负责 Websocket 和 HTTP,而 RPC 服务(9513)不再作为子端口监听,而是通过 Swoole 的 Custom Process(自定义进程) 单独启动一个独立的 RPC 服务器。
1. 修改 config/swoole.php
关闭 ports 中的 RPC 配置,改为在 custom_process 中注册一个自定义进程:
php
return [
'server' => [
'host' => '0.0.0.0',
'port' => 9512, // 9512 专门给 Websocket / HTTP 使用
'options' => [
'worker_num' => 4, // 这里的 4 个 Worker 专门处理 Websocket
],
],
// 清空原有的 ports 监听,防止冲突
'ports' => [],
// 注册自定义进程来运行 RPC 服务
'custom_process' => [
'rpc_server_process' => \app\process\RpcServerProcess::class,
],
];
请谨慎使用此类代码。
2. 创建自定义进程类 app/process/RpcServerProcess.php
利用 Swoole 原生的 Server 在独立进程中监听 9513 端口。这样 RPC 拥有自己独立的事件轮询,绝不受 Websocket 广播影响。
php
<?php
namespace app\process;
use think\swoole\contract\ProcessInterface;
use Swoole\Process as SwooleProcess;
use Swoole\Server as SwooleServer;
class RpcServerProcess implements ProcessInterface
{
public function __construct() {}
public function handle(SwooleProcess $process)
{
// 创建一个纯 TCP 的 RPC 服务器,运行在这个独立进程中
// 注意:此处使用 Swoole\Server 即可,也可以根据框架的 RPC 协议进行解析
$server = new SwooleServer('0.0.0.0', 9513, SWOOLE_PROCESS, SWOOLE_SOCK_TCP);
$server->set([
'worker_num' => 2, // 🔥 这里是专门给 RPC 使用的 Worker 进程数
'open_length_check' => true, // 开启 RPC 协议边界检查(根据你原本的 RPC 配置调配)
// ... 其他 RPC 协议特定配置
]);
$server->on('Receive', function ($serv, $fd, $reactor_id, $data) {
// 在这里处理 RPC 请求逻辑
// 可以手动调用 think-swoole 内部的 rpc 调度器,或者自己解析封装
$serv->send($fd, "RPC Response");
]);
$server->start();
}
}
请谨慎使用此类代码。
方案二:服务拆分(生产环境最终方案)
如果你不想自己去通过自定义进程重写 RPC 的协议解析,最彻底、最稳妥的架构是将它们拆分为两个独立运行的 ThinkPHP 进程。
项目拷贝或共享代码:保持代码一份,通过不同的配置文件或环境变量来启动。
Websocket 服务的配置 (
config/swoole_ws.php):端口配置为
9512。关闭 RPC 关联功能。
RPC 服务的配置 (
config/swoole_rpc.php):主端口直接配置为
9513。关闭 Websocket 功能。
启动命令:
在服务器上开启两个终端或通过 Supervisor 启动两个独立进程:
bash
# 启动 Websocket 服务
php think swoole start --config=swoole_ws
# 启动 RPC 服务
php think swoole start --config=swoole_rpc
请谨慎使用此类代码。
注:think-swoole 默认命令行不支持 --config 参数,你可以通过定义不同的环境变量(如 ENV_SERVICE_TYPE=rpc),在标准的 config/swoole.php 中内部用 if-else 读取环境变量来返回不同的配置数组。
环境变量隔离示例 (config/swoole.php):
php
$type = env('SERVICE_TYPE', 'ws');
if ($type === 'rpc') {
return [
'server' => [
'host' => '0.0.0.0',
'port' => 9513, // 主端口直供 RPC
'options' => ['worker_num' => 2],
],
// 关闭 websocket
];
} else {
return [
'server' => [
'host' => '0.0.0.0',
'port' => 9512, // 主端口直供 Websocket
'options' => ['worker_num' => 4],
],
];
}
请谨慎使用此类代码。
启动命令切换:
bash
SERVICE_TYPE=ws php think swoole start
SERVICE_TYPE=rpc php think swoole start
请谨慎使用此类代码。
使用方案二(服务拆分)是目前主流微服务架构中最安全、最容易维护的做法。
如果你打算改造,你目前的 RPC 传递数据使用的是 think-swoole 自带的 RPC 协议,还是自定义的 JSON-RPC 协议?如果是自带的,采用方案二会让你免去手动解析协议的麻烦。