Application of Swoole Task

Keywords: PHP Unix socket

Catalog

Summary

Swoole asynchronous Task, which mainly implements execution of invoking asynchronous tasks.

Common scenarios: asynchronous payment processing, asynchronous order processing, asynchronous log processing, asynchronous e-mail/text messaging, and so on.

Swoole is implemented by the worker process processing data requests and assigning them to the task process for execution.

Official Introduction:

task uses the Unix Socket pipeline to communicate at the bottom, which is full memory and does not consume IO.Single-process read and write performance can reach 1 million/s, and different processes use different pipelines to communicate, maximizing the use of multiple cores.

Local version: PHP 7.2.6, Swoole 4.3.1.

Not to mention more, first look at the effect map:

Code

server.php

<?php

class Server
{
    private $serv;

    public function __construct() {
        $this->serv = new swoole_server('0.0.0.0', 9501);
        $this->serv->set([
            'worker_num'      => 2, //Open two worker processes
            'max_request'     => 4, //Each worker process max_request is set to 4 times
            'task_worker_num' => 4, //Open 4 task processes
            'dispatch_mode'   => 2, //Packet Distribution Policy - Fixed Mode
        ]);

        $this->serv->on('Start', [$this, 'onStart']);
        $this->serv->on('Connect', [$this, 'onConnect']);
        $this->serv->on("Receive", [$this, 'onReceive']);
        $this->serv->on("Close", [$this, 'onClose']);
        $this->serv->on("Task", [$this, 'onTask']);
        $this->serv->on("Finish", [$this, 'onFinish']);

        $this->serv->start();
    }

    public function onStart($serv) {
        echo "#### onStart ####".PHP_EOL;
        echo "SWOOLE ".SWOOLE_VERSION . " Service started".PHP_EOL;
        echo "master_pid: {$serv->master_pid}".PHP_EOL;
        echo "manager_pid: {$serv->manager_pid}".PHP_EOL;
        echo "########".PHP_EOL.PHP_EOL;
    }

    public function onConnect($serv, $fd) {
        echo "#### onConnect ####".PHP_EOL;
        echo "Client:".$fd." Connected".PHP_EOL;
        echo "########".PHP_EOL.PHP_EOL;
    }

    public function onReceive($serv, $fd, $from_id, $data) {
        echo "#### onReceive ####".PHP_EOL;
        echo "worker_pid: {$serv->worker_pid}".PHP_EOL;
        echo "Client:{$fd} From Email:{$data}".PHP_EOL;
        $param = [
            'fd'    => $fd,
            'email' => $data
        ];
        $rs = $serv->task(json_encode($param));
        if ($rs === false) {
            echo "Task Assignment Failed Task ".$rs.PHP_EOL;
        } else {
            echo "Task Assignment Successful Task ".$rs.PHP_EOL;
        }
        echo "########".PHP_EOL.PHP_EOL;
    }

    public function onTask($serv, $task_id, $from_id, $data) {
        echo "#### onTask ####".PHP_EOL;
        echo "#{$serv->worker_id} onTask: [PID={$serv->worker_pid}]: task_id={$task_id}".PHP_EOL;

        //Business Code
        for($i = 1 ; $i <= 5 ; $i ++ ) {
            sleep(2);
            echo "Task {$task_id} Completed {$i}/5 Tasks".PHP_EOL;
        }

        $data_arr = json_decode($data, true);
        $serv->send($data_arr['fd'] , 'Email:'.$data_arr['email'].',Send Successfully');
        $serv->finish($data);
        echo "########".PHP_EOL.PHP_EOL;
    }

    public function onFinish($serv,$task_id, $data) {
        echo "#### onFinish ####".PHP_EOL;
        echo "Task {$task_id} Completed".PHP_EOL;
        echo "########".PHP_EOL.PHP_EOL;
    }

    public function onClose($serv, $fd) {
        echo "Client Close.".PHP_EOL;
    }
}

$server = new Server();

client.php

<?php

class Client
{
    private $client;

    public function __construct() {
        $this->client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);

        $this->client->on('Connect', [$this, 'onConnect']);
        $this->client->on('Receive', [$this, 'onReceive']);
        $this->client->on('Close', [$this, 'onClose']);
        $this->client->on('Error', [$this, 'onError']);
    }

    public function connect() {
        if(!$fp = $this->client->connect("127.0.0.1", 9501 , 1)) {
            echo "Error: {$fp->errMsg}[{$fp->errCode}]".PHP_EOL;
            return;
        }
    }

    public function onConnect($cli) {
        fwrite(STDOUT, "input Email:");
        swoole_event_add(STDIN, function() {
            fwrite(STDOUT, "input Email:");
            $msg = trim(fgets(STDIN));
            $this->send($msg);
        });
    }

    public function onReceive($cli, $data) {
        echo PHP_EOL."Received: ".$data.PHP_EOL;
    }

    public function send($data) {
        $this->client->send($data);
    }

    public function onClose($cli) {
        echo "Client close connection".PHP_EOL;
    }

    public function onError() {

    }
}

$client = new Client();
$client->connect();

Summary

1. How many processes have been started in the above configuration?

A total of 8 processes (1 master process, 1 manager process, 4 task processes, 2 worker processes)

Rerun may not match the process number shown above:

master process: 22481

manager process: 22485

The task process: 22488, 22489, 22490, 22491

worker process: 22492, 22493

Refer to the official process diagram:

2. Why has the worker process number changed after five executions?

Because we set max_request=4 for the worker process, a worker process will exit automatically after completing the maximum number of requests. Process exit will free up all memory and resources. This mechanism mainly solves the memory overflow problem of the PHP process.

3. When the task executes abnormally, will we kill a task process and add another one?

Meeting.

4. How to set task_worker_num?

The maximum value must not exceed SWOOLE_CPU_NUM * 1000.

View the number of native CPU cores:

echo "swoole_cpu_num:".swoole_cpu_num().PHP_EOL;

Depending on the amount of tasks in the project, for example, 200 tasks will be generated in one second, and 500 ms will be required to perform each task.

To complete 200 task s in 1s, 100 task processes are required.

100 = 200/(1/0.5)

5. How to set up worker_num?

The default setting is the number of CPU cores on this machine, and the maximum must not exceed SWOOLE_CPU_NUM * 1000.

For example, a request takes 10 ms and 10 processes must be configured to provide 1000QPS processing power.

10 = 0.01*1000

Assuming that each process consumes 40M of memory, 10 processes require 400M of memory.

extend

  • Server->taskwait
  • Server->taskWaitMulti
  • Server->taskCo

Reference Documents

This article welcomes forwarding, please indicate the author and source, thank you!

Posted by zrobin01 on Thu, 09 May 2019 10:30:38 -0700