内容简介:如果你发现没有文档里manager进程,这个运行模式有关,后面再说测试了下, swoole 的 worker进程在收到请求后执行 $server->task()将任务转给task进程这个操作是非阻塞的, 后面压测会发现
- 平时基本上都在写http+json这种api,经常遇到想把一些不重要的操作改成异步的时候
- 之前的方案是利用redis, lpush到队列, 然后另起个 php 脚本,brpop出来操作。
- 为了防止brpop连接闲置太久抛异常,引入的supervisor进行管理,出现异常脚本退出了supervisor会自动重启
- 最近做一个新的独立项目,刚好看到这篇文章 在php-fpm/apache中使用task功能 ,打算实践下
开发调试跑起来
- 首先是把代码抄过来,然后调试+加东西,完成版的代码贴出来
//$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(); 复制代码
- 服务启动后的进程树如下,这块不熟先看下文档 Swoole 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-fpm里lpush(提交异步任务)肯定要快啊
测试了下, swoole 的 worker进程在收到请求后执行 $server->task()将任务转给task进程这个操作是非阻塞的, 后面压测会发现
压测下 task 进程的处理能力和反应
- 压测准备
onTask
里加个sleep(1)s 来控制每个任务的处理时间
-
用
redis-benchmark -h 127.0.0.1 -p 9501 -c 1 -n 20 -t lpush
进行测试 - 测试1,启动2个task进程,lpush 1000个任务,花了8分多钟,跟推测吻合(每个任务1s,2个人干), 压测时通过 Swoole server->stats() 观察到tasking_num(排队任务数)
- 测试2,启动20个task,lpush 1000个任务,执行时间50s
-
测试3,还是20个进程,lpush 110万,很快就会出现
[2019-06-03 10:54:20 *10542.0] WARNING swReactor_write (ERROR 1008): socket#18 output buffer overflow
, 同时 worker 进程cpu很快飚到100%
此时lpush是失败的,worker进程也没死,收到的任务也仍然在按个处理
结论
- 设置多少个task 进程要根据每个task处理的耗时+QPS来定。 每个任务10ms,那1s能处理100个任务,你qps是1000的话,就得启动10个task进程
- 如果投递容量超过处理能力,task会塞满缓存区,导致worker进程发生阻塞。worker进程将无法接收新的请求;但是已经转给task进程的任务会继续执行
部署运维---平滑重启
这种常驻内存的服务不想nginx+php-fpm,需要我们自己写脚本来搞定这个事情
- 需求我总结了下
- 代码部署完能自动生效,立刻还是延迟点无所谓
- 同时不影响正在处理的任务
- 调用方没有感知
- 先看下官方文档 wiki.swoole.com/wiki/page/2… ,试了下主要几个信号的结果
- kill -9 master_pid 只是干掉master,其他还活着
- kill -15 master_pid 干掉所有
- kill -USR1 平滑重启所有worker进程
- kill -USR2 平滑重启所有task进程
- 按照 使用systemd管理swoole服务 来配置, reload 使用 USR2信号
[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进程会继续处理积压的任务,处理完后退出
坑 SWOOLE_BASE 模式
-
$server = new Server("127.0.0.1", 9501, SWOOLE_BASE);
这句.SWOOLE_BASE
是Server的两种运行模式 之一,这种模式下 kill -USR1 或者 kill -USR2 都只能重启worker进程,不会重启task进程,也就做不到平滑重启(因为无法让新代码生效) -
SWOOLE_BASE 模式下运行的结果跟文档说的也有点不一样
- 文档说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 复制代码
Todo 部署运维--监控
-
服务挂掉了要报警
机器监控进程是否活者
+定时ping下看是否活着
- task finish回调里,看下剩余的tasking_num, 有积压发报警出来
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- vue项目实践004~~~一篮子的实践技巧
- HBase实践 | 阿里云HBase数据安全实践
- Spark 实践:物化视图在 SparkSQL 中的实践
- Spark实践|物化视图在 SparkSQL 中的实践
- HBase实践 | 数据人看Feed流-架构实践
- Kafka从上手到实践-实践真知:搭建Zookeeper集群
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
随机密码生成器
多种字符组合密码
UNIX 时间戳转换
UNIX 时间戳转换