//$server = new Server("127.0.0.1", 9501, SWOOLE_BASE);
$server = new Server("127.0.0.1", 9501, SWOOLE_PROCESS);
$server->set([
'task_worker_num' => 2,
'worker_num' => 1,
]);
$server->setHandler('LPUSH', function($fd, $data) use ($server) {
$taskID = $server->task($data);
if ($taskID === false) {
$server->send($fd, Server::format(Server::ERROR));
} else {
$server->send($fd, Server::format(Server::INT, $taskID));
}
});
$server->on('Start', function($serv) {
cli_set_process_title("php_swoole_task: master");
\Yii::info("redis server master start... pid={$serv->master_pid}", 'business');
});
//不回调这里,不知道为啥,进程是有的
$server->on('ManagerStart', function($serv) {
cli_set_process_title("php_swoole_task: manager");
\Yii::info("redis server manager start... pid={$serv->manager_pid}", 'business');
});
$server->on('WorkerStart', function($serv, $worker_id) {
$type = $serv->taskworker ? 'task' : 'worker';
cli_set_process_title("php_swoole_task: {$type}");
\Yii::info("redis server {$type} start ....worker_id [{$worker_id}]", 'business');
});
$server->on('WorkerError', function($serv, $worker_id, $worker_pid, $exit_code, $signal) {
$type = $serv->taskworker ? 'task' : 'worker';
$msg = "{$type} error, worker_id=[{$worker_id}], pid={$worker_pid}, exit_code=$exit_code, signal=$signal";
\Yii::info($msg, 'business');
});
//task 进程处理完任务回调到这里
$server->on('Finish', function($serv, $taskID, $data) {
\Yii::info('redis_server task finish,id=' . $taskID . ',res=' . $data, 'business');
$stats = $serv->stats();
if ($stats['tasking_num'] > 10) { //tasking_num 当前正在排队的任务数
echo "剩余任务信息:" . json_encode($serv->stats()) . "\n";
\Yii::info('redis_server status tasking_num waring ' . json_encode($serv->stats()), 'business');
}
});
// kill -9 master 进程不会触发这个回调,并且工做进程啥的都还活着
$server->on('Shutdown', function($serv) {
\Yii::info('redis_server shutdown....', 'business');
});
$server->on('Task', function ($serv, $taskID, $workerID, $data) {
\Yii::info('redis_server receive task ' . $taskID, 'business');
list($queue, $info) = $data;
$info = json_decode($info, true);
$res = true;
switch($queue) {
case 'present_multi_gift_order':
$res = LogOrderManager::addPresentSendMultiOrder($info['orderInfo'], $info['receivers']);
break;
case 'present_gift_order':
$res = LogOrderManager::addPresentSendOrder($info['orderInfo']);
break;
default:
echo "不认识的queue\n";
break;
}
return $res ? 'OK' : 'FAIL:' . json_encode($data);
});
$server->start();
复制代码
➜ ~ pstree -p 19455
-+= 00001 root /sbin/launchd
\-+= 00758 momo /Applications/iTerm.app/Contents/MacOS/iTerm2
\-+= 13102 momo /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp momo
\-+= 13103 root login -fp momo
\-+= 13104 momo -zsh
\-+= 19454 root sudo php yii redis-server/start
\-+- 19455 root php_swoole_task: master
|--- 19460 root php_swoole_task: task
|--- 19461 root php_swoole_task: task
\--- 19462 root php_swoole_task: worker
复制代码
若是你发现没有文档里manager进程,这个运行模式有关,后面再说php
测试了下, swoole 的 worker进程在收到请求后执行 $server->task()将任务转给task进程这个操做是非阻塞的, 后面压测会发现html
onTask
里加个sleep(1)s 来控制每一个任务的处理时间nginx
redis-benchmark -h 127.0.0.1 -p 9501 -c 1 -n 20 -t lpush
进行测试[2019-06-03 10:54:20 *10542.0] WARNING swReactor_write (ERROR 1008): socket#18 output buffer overflow
, 同时 worker 进程cpu很快飚到100%此时lpush是失败的,worker进程也没死,收到的任务也仍然在按个处理redis
结论
- 设置多少个task 进程要根据每一个task处理的耗时+QPS来定。 每一个任务10ms,那1s能处理100个任务,你qps是1000的话,就得启动10个task进程
- 若是投递容量超过处理能力,task会塞满缓存区,致使worker进程发生阻塞。worker进程将没法接收新的请求;可是已经转给task进程的任务会继续执行
这种常驻内存的服务不想nginx+php-fpm,须要咱们本身写脚原本搞定这个事情apache
- 代码部署完能自动生效,马上仍是延迟点无所谓
- 同时不影响正在处理的任务
- 调用方没有感知
- kill -9 master_pid 只是干掉master,其余还活着
- kill -15 master_pid 干掉全部
- kill -USR1 平滑重启全部worker进程
- kill -USR2 平滑重启全部task进程
[Unit]
Description=Swoole Task Server
After=network.target
After=syslog.target
[Service]
Type=simple
LimitNOFILE=65535
ExecStart=/usr/bin/php /home/deploy/api-mj/yii redis-server/start
ExecReload=/bin/kill -USR2 $MAINPID
Restart=always
[Install]
WantedBy=multi-user.target
复制代码
- task进程不重启,
新部署的代码是不会生效的
systemctl restart swoole_task.service
全部进程都重启,积压的task会丢弃systemctl reload swoole_task.service
也就是kill -USR2 {master_pid}
, 会启动新task进程,旧task进程会继续处理积压的任务,处理完后退出
$server = new Server("127.0.0.1", 9501, SWOOLE_BASE);
这句. SWOOLE_BASE
是Server的两种运行模式 之一,这种模式下 kill -USR1 或者 kill -USR2 都只能重启worker进程,不会重启task进程,也就作不到平滑重启(由于没法让新代码生效)json
SWOOLE_BASE 模式下运行的结果跟文档说的也有点不同api
- 文档说BASE模式没有master进程,我发现是有的
- 文档说manager进程可选,我测试的结果是无论怎么着都没有manager进程
//$server = new Server("127.0.0.1", 9501, SWOOLE_BASE);
$server = new Server("127.0.0.1", 9501, SWOOLE_PROCESS);
$server->set([
'task_worker_num' => 2,
'worker_num' => 1,
]);
复制代码
SWOOLE_PROCESS
模式下,master(1)+manager(1)+worker(1)+task(2)
共5个➜ ~ pstree -p 19319
-+= 00001 root /sbin/launchd
\-+= 00758 momo /Applications/iTerm.app/Contents/MacOS/iTerm2
\-+= 13102 momo /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp momo
\-+= 13103 root login -fp momo
\-+= 13104 momo -zsh
\-+= 19318 root sudo php yii redis-server/start
\-+- 19319 root php_swoole_task: master
\-+- 19320 root php_swoole_task: manager
|--- 19321 root php_swoole_task: task
|--- 19322 root php_swoole_task: task
\--- 19323 root php_swoole_task: worker
复制代码
SWOOLE_BASE
模式下 master(1)++worker(1)+task(2)
共4个➜ ~ pstree -p 19455
-+= 00001 root /sbin/launchd
\-+= 00758 momo /Applications/iTerm.app/Contents/MacOS/iTerm2
\-+= 13102 momo /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp momo
\-+= 13103 root login -fp momo
\-+= 13104 momo -zsh
\-+= 19454 root sudo php yii redis-server/start
\-+- 19455 root php_swoole_task: master
|--- 19460 root php_swoole_task: task
|--- 19461 root php_swoole_task: task
\--- 19462 root php_swoole_task: worker
复制代码
机器监控进程是否活者
+ 定时ping下看是否活着
这个redis server 确定不能部署个单点,部署多个的话,这又不是http,能够靠dns来负载均衡。。缓存
- 有个可用的ip:port 清单,放哪?
- 单个节点服务启动和挂掉时,怎么方便的从
可用清单
注册和移除该服务?- 调用方什么方式拿到可用清单?
- 服务重启了,phpredis留的坏连接怎么处理? redis->ping 一下再用
- 要解决高可用的问题,按上面的思路我以为太大了。。。看来得换成http server,这样用nginx作个代理就好了