//$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作個代理就好了