閱讀939 返回首頁    go 技術社區[雲棲]


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/onFinish2個事件回調函數。如果沒有注冊,服務器程序將無法啟動。

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

  上一篇:go  深入淺出 spring-data-elasticsearch 之 ElasticSearch 架構初探(一)
  下一篇:go  初創公司如何快速低耗實現數據化運營