本篇内容主要讲述了最新的think-worker
扩展的使用。
安装
Workerman
和think-worker
启动
Workerman HTTP
服务守护进程模式
基本操作(只支持
Linux
环境)配置文件
修改地址和端口
文件监控
事件回调
静态资源访问
HTTPS
支持其它注意事项
Windows版本问题
快速启动
Workerman Server
守护进程
配置文件
自定义服务类
启动多个
Workerman
服务GatewayWorker
支持安装
GatewayWorker
守护进程模式
配置文件
分布式部署
本指南的目的不是为了让你掌握
Workerman
开发,而且帮助你使用think-worker
快速部署ThinkPHP5.1
应用到Workerman
的HttpServer
,以及使用快速启动Workerman
服务(包括GatewayWorker
),如果你需要了解Workerman
的具体用法和原理,请参考Workerman官方文档,说的比较详细了。
本文的内容并不适用于ThinkPHP
5.0
及以下版本 !如果你发现文中的例子没法正确执行,请检查你的think-worker扩展是否已经更新到最新版本。
安装Workerman
和think-worker
Workerman是一款纯PHP开发的开源高性能的PHP socket 服务器框架。而
think-worker
则是ThinkPHP官方发布的一个workerman
扩展,从2.0+
版本完善了对Workerman
的支持。
Workerman
是一个纯PHP的实现,因此基本上不需要特殊的安装,你只需要通过composer
直接安装即可。
composer require workerman/workerman
注意,最新版本的workerman已经统一了Linux和Windows版本,因此不需要单独安装windows版本了。
事实上在安装think-worker
扩展的时候会自动安装workerman
依赖包,所以直接在你的项目根目录下运行下面的命令安装扩展,如果你还没有安装workerman
的话也会自动安装。
composer require topthink/think-worker
本文中的内容以最新版本的扩展为例(最好确保安装的是V2.0.8+
版本,可能部分功能老版本的扩展不支持),如果你的扩展版本较旧,请更新框架或者扩展版本。
ThinkPHP5+
的扩展都是基于Composer
安装的,所以确认你已经安装了Composer
。
如果你已经有自己的ThinkPHP5.1
项目了,为了支持最新的特性,建议更新到最新版本(V5.1.20+
),然后可以在应用根目录下使用下面命令安装扩展。
composer require topthink/think-worker
会安装最新的稳定版本的think-worker
扩展。
如果你是第一次使用ThinkPHP5.1
,那么可以先创建一个初始项目,然后再安装扩展,依次执行下面的命令即可。
composer create-project topthink/think tp
cd tp
composer require topthink/think-worker
启动Workerman HTTP
服务
第一个场景(也是该扩展最重要的一个场景),毕竟大部分使用think-worker
扩展的用户都是在使用ThinkPHP开发网站或者项目,使用think-worker
扩展可以让你的产品直接部署到Workerman
上,并且享受下面的优势:
- 无需对代码进行改造就能带来性能的数倍提升;
- 可以在
Apache
/Nginx
等传统WEB服务器和Workerman
之间切换部署;
简单点说,就是你可以在传统模式下开发你的应用,然后直接部署到
Workerman
上运行,但无需针对Workerman
写任何的处理代码。
安装完扩展后,你什么都不需要做,最简单的就是直接在命令行(应用根目录下面)下执行:
php think worker
启动成功后会显示类似下面的信息
Starting Workerman http server...
Workerman[think] start in DEBUG mode
----------------------- WORKERMAN -----------------------------
Workerman version:3.5.13 PHP version:7.2.7-0ubuntu0.18.04.2
------------------------ WORKERS -------------------------------
user worker listen processes status
kancloud thinkphp http://0.0.0.0:2346 4 [OK]
----------------------------------------------------------------
Press Ctrl+C to stop. Start success.
可以看到已经在0.0.0.0:2346
启动一个HTTP Server服务端(默认启动的是调试模式),下面我们可以直接访问当前的应用。
http://localhost:2346
如果你之前已经有运行一个80端口的WEB服务,可以同时访问,你也可以比较下两个页面的区别。
如果你是刚创建的项目,那么可以直接看到ThinkPHP5.1
的欢迎页面。
[图片上传失败...(image-d396aa-1565236395761)]
否则你会看到你的项目首页。
守护进程模式
如果需要使用守护进程模式运行(只支持Linux
环境),可以使用
php think worker -d
会看到类似下面的信息:
Starting Workerman http server...
----------------------- WORKERMAN -----------------------------
Workerman version:3.5.13 PHP version:7.2.7-0ubuntu0.18.04.2
------------------------ WORKERS -------------------------------
user worker listen processes status
kancloud thinkphp http://0.0.0.0:2346 4 [OK]
----------------------------------------------------------------
Input "php think stop" to stop. Start success.
注意,最后一句
php think stop
提示信息并不正确,这是由于Workerman
没有准确定位到入口文件导致。stop
命令的正确用法,我们会在后面讲到。
基本操作(只支持Linux
环境)
这一节的内容只支持
Linux
环境
可以在命令行使用
php think worker [操作]
如果没有输入任何操作,则默认为
start
操作。
支持的操作包括:
操作 | 描述 |
---|---|
start | 启动服务(默认操作) |
reload | 平滑重启 |
stop | 停止服务 |
restart | 重启服务 |
status | 查看服务运行信息 |
connections | 查看连接信息 |
如果要停止服务,可以使用
php think worker stop
reload
服务
php think worker reload
stop
服务
php think worker stop
restart
服务
php think worker restart
restart
和reload
的区别是,restart
会先stop
然后start
,而reload
则是平滑重启服务,不会中断服务。
配置文件
HTTPServer
的参数可以在应用配置目录下的worker.php
里面配置,该文件会在扩展安装的时候自动生成(如果没有则可以自己创建)。
扩展自带的配置参数主要包括:
配置参数 | 描述 | 默认值 |
---|---|---|
host | 监听地址 | 0.0.0.0 |
port | 监听端口 | 2346 |
root | WEB根目录 | public目录 |
app_path | 应用目录(守护进程模式必须设置) | 自动识别 |
file_monitor | 是否监控文件更改(V2.0.9+) | false |
file_monitor_interval | 监控文件间隔(秒)(V2.0.9+) | 2 |
file_monitor_path | 监控目录 (V2.0.9+) | 默认监控application和config目录 |
其它的
workerman
参数可以参考官方文档的Worker类属性,所有Workerman
本身支持的配置参数都可以直接在worker.php
中使用。
修改地址和端口
如果你需要修改地址和端口,可以修改worker.php
配置文件
'host' => 'tp5.com', // 监听地址
'port' => 8080, // 监听端口
改完后,需要重启服务才能生效
php think worker restart
如果是在windows下面的话,可以使用
CTRL+C
停止服务,然后再启动服务。
现在可以直接访问
http://tp5.com:8080
如果你需要设置
80
端口,需要root
权限才可以。
如果你安装的是
2.0.8+
版本的扩展,还可以支持在命令行指定地址和端口,例如:
php think worker -H tp.com -p 2800
会显示如下信息:
Starting Workerman http server...
Workerman[think] start in DEBUG mode
----------------------- WORKERMAN -----------------------------
Workerman version:3.5.13 PHP version:7.2.7-0ubuntu0.18.04.2
------------------------ WORKERS -------------------------------
user worker listen processes status
kancloud thinkphp http://tp.com:2800 4 [OK]
----------------------------------------------------------------
Press Ctrl+C to stop. Start success.
如果配置文件和命令行都指定了
host
和port
选项,则命令行参数优先。
如果启动了多个不同端口的服务,reload
、restart
和stop
等操作必须也是针对某个端口的才能正确操作,我们以reload
操作为例进行说明。
如果我们需要reload
前面启动的tp.com:2800
服务,下面的指令是错误的
php think worker reload
可能会出现错误提示:
Workerman[think] reload
Workerman[think] not run
必须带上正确的端口号(host
不是必须的)
php think worker reload -p 2800
然后,你会看到提示信息如下,表示reload
成功:
Workerman[think] reload
文件监控
由于Workerman
服务运行过程中PHP文件是常驻内存运行的,这样可以避免重复读取磁盘、重复解释编译PHP,以便达到最高性能。所以更改业务代码后必须手动reload
或者restart
才能生效。
think-worker
扩展提供了监控文件更新的功能,在检测到相关目录的文件有更新后会自动reload
,从而不需要手动进行reload
操作,方便开发调试。
如果你的应用开启了调试模式,文件监控功能是自动开启的,为了便于调试,我们强烈建议在开发阶段开启调试模式。
原则上,在部署模式下不建议开启文件监控,一方面有性能损耗,另外一方面对文件所做的任何修改都需要确认无误才能进行更新部署。另外由于
windows
下不支持reload
操作,因此文件监控功能只支持Linux
环境。
如果你确实需要在部署模式下开启文件监控,可以设置如下:
'file_monitor' => true, // 开启文件监控
'file_monitor_interval' => 1, // 文件监控检测的时间间隔
'file_monitor_path' => '', // 文件监控目录 一般不需要设置 默认会监控应用目录和配置目录
在调试模式下,或者开启了文件监控后,我们进行一下测试。
修改你的Index
控制器文件,在index方法中添加一段调试输出代码
dump('hello');
然后刷新你的浏览器访问,看是否已经实时生效了。
文件监控的目录默认会自动监控应用目录application
和配置文件目录config
下面的php
文件,如果你还需要增加其它的监控目录,例如增加路由配置目录,可以设置为:
'file_monitor_path' => [
'/home/www/tp.com/application',
'/home/www/tp.com/config',
'/home/www/tp.com/route',
]
或者设置整个项目目录进行文件监控
'file_monitor_path' => [
'/home/www/tp.com'
]
事件回调
扩展自带的HTTPServer
包含了onWorkerStart
和onMessage
两个事件回调,你如果需要增加其它的回调事件处理,可以在配置文件中直接添加:
'onConnect' => function($connection)
{
echo "new connection from ip " . $connection->getRemoteIp() . "\n";
},
'onClose' => function($connection)
{
echo "connection closed\n";
},
关于事件回调的具体用法,可以参考workerman
官方文档的回调属性。
如果不熟悉内部机制,请勿随意替换和更改
onWorkerStart
和onMessage
事件回调,会导致不可预期的结果。
静态资源访问
为了确保静态资源的正常访问,请确认下面的参数配置正确:
// 网站根目录位置
'root' => Env::get('root_path') . 'public',
使用Chrome浏览器会自动请求一次
favicon.ico
,所以确保你的网站根目录下面有存在favicon.ico
文件,否则会产生一次404
请求的错误日志。
HTTPS
支持
Workerman
开启SSL
的前提如下:
- Workerman版本不小于
3.3.7
- PHP安装了
openssl
扩展 - 已经申请了证书(
pem/crt
文件及key
文件,假设放在了/etc/nginx/conf.d/ssl
下)
然后在worker.php
配置文件中设置
'host' => '0.0.0.0',
'port' => 443,
// 开启SSL访问支持
'ssl' => true,
// 或者改为下面的配置
// 'transport' => 'ssl',
'context' => [
'ssl' => [
'local_cert' => '/etc/nginx/conf.d/ssl/server.pem', // 也可以是crt文件
'local_pk' => '/etc/nginx/conf.d/ssl/server.key',
'verify_peer' => false,
],
],
现在客户端就可以通过https
协议来连接了。
注意:
-
https
端口必须用https
协议访问,http
协议无法访问。 - 证书一般是与域名绑定的,所以测试的时候请使用域名访问,不要使用ip。
- 如果使用
https
无法访问请检查服务器防火墙。
也利用nginx
作为ssl
的代理,具体配置可以参考官方手册说明。
其它注意事项
在
Workerman
下面,不建议直接使用$_GET
、$_POST
、$_REQUEST
、$_SERVER
、$_COOKIE
以及$_SESSION
等原生的PHP用法,推荐使用框架提供的类和方法进行获取。
由于onWorkerStart
运行的时候还没有HTTP_HOST
,因此最好在应用配置文件config/app.php
中设置app_host
。
请不要调用PHP原生的header
方法,使用Response
对象的header
方法替代。
不要使用PHP原生的session
相关函数,使用Session
类的相关方法。
Windows版本问题
Workerman
的Windows
版本与Linux
的主要区别包括:
- win版本
count
属性无效,全部为单进程 - 不支持
start
之外的操作命令(可以用CTRL+C
停止运行) - cmd命令行启动,后面可接多个文件,例如 php start_web.php start_gateway.php start_worker.php
- 无法守护进程,cmd窗口关掉后服务即停止
快速启动Workerman Server
现在来看第二个场景,通过简单的配置快速启动一个Workerman
服务,包括WebSocket
/Http
/Socket
服务。
可以支持直接启动一个Workerman server(需要think-worker
扩展 2.0.7+
版本)
php think worker:server
会显示如下信息:
Starting Workerman server...
Workerman[think] start in DEBUG mode
----------------------- WORKERMAN -----------------------------
Workerman version:3.5.13 PHP version:7.2.7-0ubuntu0.18.04.2
------------------------ WORKERS -------------------------------
user worker listen processes status
kancloud thinkphp websocket://0.0.0.0:2345 4 [OK]
----------------------------------------------------------------
Press Ctrl+C to stop. Start success.
这个时候已经在0.0.0.0:2345
启动一个Websocket
服务。
你可以在浏览器中访问
http://127.0.0.1:2345
会看到如下信息:
400 Bad Request
Sec-WebSocket-Key not found.
This is a WebSocket service and can not be accessed via HTTP.
See http://wiki.workerman.net/Error1 for detail.
这是因为Workerman的WebSocket
协议不支持通过HTTP
访问,可以通过JS代码测试。
ws = new WebSocket("ws://127.0.0.1:2345");
ws.onopen = function() {
alert("连接成功");
ws.send('hello,thinkphp');
alert("给服务端发送一个字符串:hello,thinkphp");
};
ws.onmessage = function(e) {
alert("收到服务端的消息:" + e.data);
};
守护进程
如果需要使用守护进程方式运行,可以使用
php think worker:server -d
配置文件
如果需要自定义参数,可以在config/worker_server.php
中进行配置,包括:
配置参数 | 描述 | 默认值 |
---|---|---|
protocol | 协议 | websocket |
host | 监听地址 | 0.0.0.0 |
port | 监听端口 | 2345 |
socket | 完整socket地址 | 空 |
context | socket 上下文选项 | 空 |
daemonize | 守护进程 | false |
注意不要和
worker.php
文件文件混淆,两者的作用完全不同。
并且支持Workerman
所有的参数,以及支持使用闭包方式定义相关事件回调。
return [
// 扩展自身需要的配置
'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text
'host' => '0.0.0.0', // 监听地址
'port' => 2345, // 监听端口
// 支持workerman的所有配置参数
'name' => 'thinkphp',
'count' => 4,
'daemonize' => false,
'pidFile' => Env::get('runtime_path') . 'worker.pid',
// 支持事件回调
// onWorkerStart
'onWorkerStart' => function ($worker) {
},
// onWorkerReload
'onWorkerReload' => function ($worker) {
},
// onConnect
'onConnect' => function ($connection) {
},
// onMessage
'onMessage' => function ($connection, $data) {
$connection->send('receive success');
},
// onClose
'onClose' => function ($connection) {
},
// onError
'onError' => function ($connection, $code, $msg) {
echo "error [ $code ] $msg\n";
},
];
自定义服务类
如果你需要更高级的自定义事件回调,也可以使用自定义的Worker
服务类。
4,
'pidFile' => Env::get('runtime_path') . 'worker.pid',
'name' => 'think'
];
public function onMessage($connection, $data)
{
$connection->send('receive success');
}
}
自定义服务类必须继承
think\worker\Server
类,支持workerman
所有的回调方法定义(回调方法必须是public
类型)。
然后在worker_server.php
中增加配置参数:
return [
'worker_class' => 'app\http\Worker',
];
定义该参数后,其它配置参数均不再有效。
然后就可以在命令行启动服务端
php think worker:server
一样可以支持使用守护进程模式运行,
php think worker:server -d
同样也支持reload
、restart
和stop
操作。
php think worker:server reload
启动多个Workerman
服务
你可以通过命令行的指令启动多个不同端口的workerman
服务,例如:
php think worker:server -p 2800
php think worker:server -p 2801
如果要分别对不同端口的服务进行stop
操作,务必使用
php think worker:server stop -p 2800
php think worker:server stop -p 2801
如果你自定义了服务入口类,那么可以定义多个入口类
4,
'pidFile' => Env::get('runtime_path') . 'worker1.pid',
'name' => 'think'
];
public function onMessage($connection, $data)
{
$connection->send('receive success');
}
}
4,
'pidFile' => Env::get('runtime_path') . 'worker2.pid',
'name' => 'think'
];
public function onMessage($connection, $data)
{
$connection->send('receive success');
}
}
然后在worker_server.php
中增加配置参数:
return [
'worker_class' => ['app\http\Worker1', 'app\http\Worker2'],
];
运行启动指令后可以看到启动了两个不同的服务
php think worker:server
GatewayWorker
支持
V2.0.8+
版本开始,think-worker
扩展可以支持GatewayWorker
。
GatewayWorker
是基于Workerman
开发的一套TCP长连接的应用框架,实现了单发、群发、广播等接口,内置了mysql类库,GatewayWorker
分为Gateway
进程和Worker
进程,天然支持分布式部署。
安装GatewayWorker
首先确保你已经安装了GatewayWorker
,如果还没有,可以使用下面的命令安装
composer require workerman/gateway-worker
接下来,可以直接在命令行运行
php think worker:gateway
会显示下面的信息,表示启动成功。
Starting GatewayWorker server...
Workerman[think] start in DEBUG mode
----------------------- WORKERMAN -----------------------------
Workerman version:3.5.13 PHP version:7.2.7-0ubuntu0.18.04.2
------------------------ WORKERS -------------------------------
user worker listen processes status
kancloud Register text://127.0.0.1:1236 1 [OK]
kancloud BusinessWorker none 1 [OK]
kancloud thinkphp websocket://0.0.0.0:2348 1 [OK]
----------------------------------------------------------------
Press Ctrl+C to stop. Start success.
守护进程模式
如果需要使用守护进程模式,可以使用
php think worker:gateway -d
同样支持在命令行指定地址和端口
php think worker:gateway -H tp.com -p 2800
显示信息
Starting GatewayWorker server...
Workerman[think] start in DEBUG mode
----------------------- WORKERMAN -----------------------------
Workerman version:3.5.13 PHP version:7.2.7-0ubuntu0.18.04.2
------------------------ WORKERS -------------------------------
user worker listen processes status
kancloud Register text://127.0.0.1:1236 1 [OK]
kancloud BusinessWorker none 1 [OK]
kancloud thinkphp websocket://tp.com:2800 1 [OK]
----------------------------------------------------------------
Press Ctrl+C to stop. Start success.
配置文件
如果需要调整配置,可以修改配置目录下面的gateway_worker.php
文件,内容如下:
return [
// 扩展自身需要的配置
'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text
'host' => '0.0.0.0', // 监听地址
'port' => 2348, // 监听端口
'socket' => '', // 完整监听地址
'context' => [], // socket 上下文选项
'register_deploy' => true, // 是否需要部署register
'businessWorker_deploy' => true, // 是否需要部署businessWorker
'gateway_deploy' => true, // 是否需要部署gateway
// Register配置
'registerAddress' => '127.0.0.1:1236',
// Gateway配置
'name' => 'thinkphp',
'count' => 1,
'lanIp' => '127.0.0.1',
'startPort' => 2000,
'daemonize' => false,
'pingInterval' => 30,
'pingNotResponseLimit' => 0,
'pingData' => '{"type":"ping"}',
// BusinsessWorker配置
'BusinessWorker' => [
'name' => 'BusinessWorker',
'count' => 1,
'eventHandler' => '\think\worker\Events',
],
];
默认配置参数如果需要更改,可以直接修改。
GatewayWorker
开发过程中首先要配置BusinessWorker
下面的eventHandler
参数。系统默认提供了一个think\worker\Events
类作为参考,实际请根据需要进行调整。详细用法请参考GatewayWorker手册。
分布式部署
GatewayWorker
支持分布式部署,假如需要部署三台服务器(192.168.1.1-3)提供高可用服务,可以按照下面的方法进行配置操作。
第一台服务器运行统一的Register
服务(该服务器同时也运行Gateway
进程和BusinessWorker
进程),其它两台则只部署Gateway
服务和BusinessWorker
服务,三台服务器的gateway_worker.php
配置文件分别修改为:
192.168.1.1 gateway_worker.php
// 分布式部署配置
'protocol' => 'websocket',
'host' => '0.0.0.0', // 监听地址
'port' => 2348, // 监听端口
'register_deploy' => true, // 部署register
'businessWorker_deploy' => true, // 部署businessWorker
'gateway_deploy' => true, // 部署gateway
// Register配置
'registerAddress' => '192.168.1.1:1236',
// Gateway配置
'name' => 'thinkphp',
'count' => 1,
'lanIp' => '192.168.1.1',
'startPort' => 2000,
'daemonize' => false,
'pingInterval' => 30,
'pingNotResponseLimit' => 0,
'pingData' => '{"type":"ping"}',
// BusinsessWorker配置
'BusinessWorker' => [
'name' => 'BusinessWorker',
'count' => 1,
'eventHandler' => '\think\worker\Events',
],
192.168.1.2 gateway_worker.php
// 分布式部署配置
'protocol' => 'websocket',
'host' => '0.0.0.0', // 监听地址
'port' => 2348, // 监听端口
'register_deploy' => false, // 不部署register
'businessWorker_deploy' => true, // 部署businessWorker
'gateway_deploy' => true, // 部署gateway
// Register配置
'registerAddress' => '192.168.1.1:1236',
// Gateway配置
'name' => 'thinkphp',
'count' => 1,
'lanIp' => '192.168.1.2',
'startPort' => 2000,
'daemonize' => false,
'pingInterval' => 30,
'pingNotResponseLimit' => 0,
'pingData' => '{"type":"ping"}',
// BusinsessWorker配置
'BusinessWorker' => [
'name' => 'BusinessWorker',
'count' => 1,
'eventHandler' => '\think\worker\Events',
],
192.168.1.3 gateway_worker.php
// 分布式部署配置
'protocol' => 'websocket',
'host' => '0.0.0.0', // 监听地址
'port' => 2348, // 监听端口
'register_deploy' => false, // 不部署register
'businessWorker_deploy' => true, // 部署businessWorker
'gateway_deploy' => true, // 部署gateway
// Register配置
'registerAddress' => '192.168.1.1:1236',
// Gateway配置
'name' => 'thinkphp',
'count' => 1,
'lanIp' => '192.168.1.3',
'startPort' => 2000,
'daemonize' => false,
'pingInterval' => 30,
'pingNotResponseLimit' => 0,
'pingData' => '{"type":"ping"}',
// BusinsessWorker配置
'BusinessWorker' => [
'name' => 'BusinessWorker',
'count' => 1,
'eventHandler' => '\think\worker\Events',
],
如果你需要把
Gateway
和BusinessWorker
服务分开部署,则单独设置开启或者关闭gateway_deploy
和businessWorker_deploy
配置参数即可。
配置调整完成后,按顺序分别启动服务,分布式部署完毕。
注意事项及说明:
1、多机部署时以下端口注意不要被服务器防火墙屏蔽(不知道服务器防火墙如何配置的请自行搜索资料学习):
①、Register
服务监听的端口要可以被其它内网服务器访问(外网访问可以屏蔽);
②、如果startPort=2300; count=4;,则2300 2301 2302 2303四个端口需要被设置成能被其它服务器访问。
2、如果多机部署服务器不在一个局域网,部署时ip参数可以使用外网ip,对应端口防火墙应该设置成能被外网服务器访问。
3、三台GatewayWorker
机器都运行了Gateway
进程和Worker
进程,客户端连接上任意一台GatewayWorker
的Gateway
端口即通讯,开发。
4、为了方便前端接入和扩容,可以在Gateway
前加一层DNS、LVS等负载均衡策略(不熟悉DNS LVS的请自行搜索资料学习)。
5、如果服务器不够用可以使用同样的方法增加服务器
6、如果需要下线服务器,直接stop对应服务器即可。由于Gateway
进程维护着客户端连接,当服务器下线时,对应服务器的客户端会掉线一次。