壓測 swoole_websocket_server 性能

概述

這是關於 Swoole 入門學習的第十篇文章:壓測 swoole_websocket_server 性能。php

收到讀者提問 「使用 Swoole 開發的羣聊功能,想知道併發狀況,也就是想壓測下 QPS,一直未找到方法 ...」html

對 swoole_http_server 壓測,我們可使用 Apache 的 ab 命令。c++

對 swoole_websocket_server 壓測,使用 ab 命令是不能壓測的,我從網上一直也沒找到合適的方法,看官方提供的代碼 benchmark/async.php 中,使用的異步模塊 swoole\http\client 方法進行壓測的,但在 Swoole 4.3 版本就移除了異步模塊,讓使用 Coroutine 協程模塊。web

在本地我用 Coroutine 協程實現了一下, 測的差很少的時候,一直不肯定是否正確,就在 segmentfault 發了個提問,沒想到韓老師回答了,'若是的若是'老師也回答了,很是感謝兩位老師的答案,而後整理出文章分享給你們。segmentfault

測試機

Mac 上安裝的 Parallels Desktop 虛擬機websocket

系統:Ubuntu 16.04.3 LTSswoole

內存:併發

  • 數量:1
  • 核數:2

CPU:框架

  • 數量:1
  • 大小:2G

Server 代碼

<?php

class Server
{
    private $serv;
    public function __construct() {
        $this->serv = new Swoole\WebSocket\Server("0.0.0.0", 9501);
        $this->serv->set([
            'task_worker_num'       => 10,
            'enable_coroutine'      => true,
            'task_enable_coroutine' => true
        ]);
        $this->serv->on('open', function ($serv, $request) {});
        $this->serv->on('message', function ($serv, $frame) {
            $serv->task($frame->data);
        });
        $this->serv->on('task', function ($serv, $task) {
            foreach ($serv->connections as $fd) {
                $connectionInfo = $serv->connection_info($fd);
                if (isset($connectionInfo['websocket_status']) && intval($connectionInfo['websocket_status']) == 3) {
                    $serv->push($fd, $task->data);
                }
            }
        });
        $this->serv->on('finish', function ($serv, $task_id, $data) {});
        $this->serv->on('close', function ($serv, $fd) {});
        $this->serv->start();
    }
}

$server = new Server();

壓測腳本

class Test
{
    protected $concurrency; //併發量
    protected $request;     //請求量
    protected $requested = 0;
    protected $start_time;

    function __construct()
    {
        $this->concurrency = 100;
        $this->request     = 10000;
    }

    protected function webSocket()
    {
        go(function () {
            for ($c = 1; $c <= $this->concurrency; $c++ ) {
                $cli = new \Swoole\Coroutine\Http\Client('127.0.0.1', 9501);
                $cli->set(['websocket_mask' => false]);
                $ret = $cli->upgrade('/');
                if ($ret) {
                    $i = $this->request / $this->concurrency;
                    while ($i >= 1) {
                        $this->push($cli);
                        $cli->recv();
                        $i--;
                    }
                }
            }
            $this->finish();
        });
    }

    protected function push($cli)
    {
        $ret = $cli->push('Hello World');
        if ($ret === true) {
            $this->requested ++ ;
        }
    }

    protected function finish()
    {
        $cost_time = round(microtime(true) - $this->start_time, 4);
        echo "Concurrency:".$this->concurrency.PHP_EOL;
        echo "Request num:".$this->request.PHP_EOL;
        echo "Success num:".$this->requested.PHP_EOL;
        echo "Total time:".$cost_time.PHP_EOL;
        echo "Request per second:" . intval($this->request / $cost_time).PHP_EOL;
    }

    public function run()
    {
        $this->start_time = microtime(true);
        $this->webSocket();
    }
}

$test = new Test();
$test->run();

壓測結果

第 1 次:
Concurrency:100
Request num:10000
Success num:10000
Total time:0.846
Request per second:11820

第 2 次:
Concurrency:100
Request num:10000
Success num:10000
Total time:0.9097
Request per second:10992

第 3 次:
Concurrency:100
Request num:10000
Success num:10000
Total time:0.903
Request per second:11074

以上是壓測結果,供參考。異步

小結

經過這個壓測結果,代表 Swoole 的執行效率是槓槓的!

固然還有一些參數是能夠調優的,好比:worker_num、max_request、task_worker_num 等。

在真實的業務場景中,確定會有邏輯處理,也會使用到 MySQL、Redis。

那麼問題來了,前兩篇文章已經分享了,Swoole Redis 鏈接池Swoole MySQL 鏈接池,感興趣的同窗,可使用上兩種鏈接池,而後再進行壓測。

不知不覺,Swoole 入門文章已經寫了 10 篇了,很是感謝你們的捧場,真心但願可以對 Swoole 入門學習的同窗,有點幫助。

本文歡迎轉發,轉發請註明做者和出處,謝謝!

相關文章
相關標籤/搜索