939
技術社區[雲棲]
Swoole筆記(二)
本文示例代碼詳見:https://github.com/52fhy/swoole_demo。
重新打開日誌
在1.8.11及之後版本支持重新打開日誌:向Server主進程發送SIGRTMIN信號。假設主進程id是3427,那麼我們可以:
kill -34 3427
注:SIGRTMIN信號的id是
34
。通過kill -l
查看。
那麼如何利用這個特征實現每天自動寫入新的日誌文件裏麵呢?
假設日誌文件是/log/swoole.log
,我們可以在每天0點運行shell命令:
mv /log/swoole.log /log/$(date -d '-1 day' +%y-%m-%d).log
kill -34 $(ps aux|grep swoole_task|grep swoole_task_matser|grep -v grep|awk '{print $2}') # 找到主進程,需要提前命名
我們也可以把master進程的PID寫入到文件:
$server->set(array(
'pid_file' => __DIR__.'/server.pid',
));
在Server關閉時自動刪除PID文件。此選項在1.9.5或更高版本可用。
信號管理
Swoole支持的信號:
SIGKILL -9 pid 強製殺掉進程
SIGUSR1 -10 master_pid 重啟所有worker進程
SIGUSR2 -12 master_pid 重啟所有task_worker進程
SIGRTMIN -34 master_pid 重新打開日誌(版本1.8.11+)
master_pid代表主進程pid。示例(假設主進程名稱是swoole_server,pid是3427):
# 殺掉進程swoole_server
kill -9 $(ps aux|grep swoole_server|grep -v grep|awk '{print $2}')
# 重啟swoole_server的worker進程
kill -10 $(ps aux|grep swoole_server|grep -v grep|awk '{print $2}')
# 重新打開日誌
kill -34 3427
Task
我們可以在worker進程中投遞一個異步任務到task_worker池中。此函數是非阻塞的,執行完畢會立即返回。worker進程可以繼續處理新的請求。
通常會把耗時的任務交給task_worker來處理。
我們可以通過如下代碼判斷是Worker進程還是TaskWorker進程:
function onWorkerStart($serv, $worker_id) { if ($worker_id >= $serv->setting['worker_num']) { //超過worker_num,表示這是一個task進程
}
}
看一個示例:
``` php
<?php
$server = new \swoole_server("127.0.0.1",8088);
$server->set(array(
'daemonize' => false,
'reactor_num' => 2,
'worker_num' => 1,
'task_worker_num' => 1,
));
$server->on('start', function ($serv){
swoole_set_process_name("swoole_task_matser"); //主進程命名
});
$server->on('connect', function ($serv, $fd){
echo "client connect. fd is {$fd}\n";
});
$server->on('receive', function ($serv, $fd, $from_id, $data){
echo sprintf("onReceive. fd: %d , data: %s\n", $fd, json_encode($data) );
$serv->task(json_encode([
'fd' => $fd,
'task_name' => 'send_email',
'email_content' => $data,
'email' => 'admin@qq.com'
]));
});
$server->on('close', function ($serv, $fd){
echo "client close. fd is {$fd}\n";
});
$server->on('task', function (swoole_server $serv, $task_id, $from_id, $data){
echo $data;
$data = json_decode($data, true);
$serv->send($data['fd'], "send eamil to {$data['email']}, content is : {$data['email_content']}\n");
//echo 'task finished';
//return 'task finished';
$serv->finish('task finished');
});
$server->on('finish', function (swoole_server $serv, $task_id, $data){
echo 'onFinish:' .$data;
});
$server -> start();
這裏新建了一個tcp服務器,參數裏設置worker_num
進程為1,task_worker_num
為1。
配置了task_worker_num
參數後將會啟用task功能,swoole_server
務必要注冊onTask/onFinish
2個事件回調函數。如果沒有注冊,服務器程序將無法啟動。
onTask回調接收4個參數,分別是serv對象、任務ID、自於哪個worker進程、任務的內容。注意的是,$data
必須是字符串。我們可以在worker進程裏使用swoole_server->task
進行任務投遞。
($data)
onFinish回調用於將處理結果告知worker進程,此回調必須有,但是否被調用由OnTask決定。在OnTask裏使用return
或者finish()
可以將處理結果發生到onFinish回調,否則onFinish回調是不會被調用的。也就是說:finish()
是可選的。如果worker進程不關心任務執行的結果,不需要調用此函數。onFinish回調裏的$data
同樣必須是字符串。
我們新起一個窗口,使用telnet
發送消息到服務端進行測試:
client端:
telnet 127.0.0.1 8088
Trying 127.0.0.1...
Connected to 127.0.0.1.
hhh
send eamil to admin@qq.com, content is : hhh
server端:
client connect. fd is 1
onReceive. fd: 1 , data: "hhh\r\n"
{"fd":1,"task_name":"send_email","email_content":"hhh\r\n","email":"admin@qq.com"}
onFinish:task finished
onFinish回調裏不使用return
或者finish()
,我們將看不到server端最後一行輸出。
此時服務器進程模型:
pstree -ap | grep swoole
| | `-php,3190 swoole_task.php
| | |-php,3192 swoole_task.php
| | | |-php,3194 swoole_task.php
| | | `-php,3195 swoole_task.php
看到兩個worker進程,其中一個是worker進程,另外一個是task_worker進程。
定時器
Swoole提供強大的異步毫秒定時器,基於timerfd+epoll實現。主要方法:
1、swoole_timer_tick:周期性定時器,類似於JavaScript裏的setInterval()
。
2、swoole_timer_after:一次性定時器。
3、swoole_timer_clear:清除定時器。
# 周期性定時器
int swoole_timer_tick(int $ms, callable $callback, mixed $user_param);
# 一次性定時器
swoole_timer_after(int $after_time_ms, mixed $callback_function, mixed $user_param);
# 清除定時器
bool swoole_timer_clear(int $timer_id)
# 定時器回調函數
function callbackFunction(int $timer_id, mixed $params = null);
注意:
-
$ms
最大不得超過 86400000。 - manager進程中不能添加定時器。
- 建議在
WorkerStart
回調裏寫定時器。
定時器示例:
$server->on('WorkerStart', function (\swoole_server $server, $worker_id){
if ($server->worker_id == 0){//防止重複
//每隔2000ms觸發一次
swoole_timer_tick(2000, function ($timer_id) {
echo "tick-2000ms\n";
});
//3000ms後執行此函數
swoole_timer_after(3000, function () {
echo "after 3000ms.\n";
});
}
});
最後更新:2017-06-06 13:01:30