hyperf / hyperf

🚀 A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.

Home Page:https://www.hyperf.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Higher CPU usage compare to swoole itself

foremtehan opened this issue · comments

I wanted to test the framework. So far, it's good, but i've noticed that it consumes more cpu compared to Swoole itself.

these are the changes i made to the framework:

composer require hyperf/database-pgsql

edited the database config:

return [
    'default' => [
        'driver' => 'pgsql',
        'host' => '',
        'database' => '',
        'port' => 5432,
        'username' => '',
        'password' => "",
        'charset' => env('DB_CHARSET', 'utf8'),
        'collation' => env('DB_COLLATION', 'utf8_unicode_ci'),
        'prefix' => '',
        'schema' => 'public',
        'pool' => [
            'min_connections' => 1,
            'max_connections' => 10,
            'connect_timeout' => 10.0,
            'wait_timeout' => 3.0,
            'heartbeat' => -1,
            'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),
        ],
        'commands' => [
            'gen:model' => [
                'path' => 'app/Model',
                'force_casts' => false,
                'inheritance' => 'Model',
                'refresh_fillable' => true
            ],
        ],
    ]
];

Default Controller:

class IndexController extends AbstractController
{
    public function index()
    {
        return Db::table('users')->first();
    }
}
ab -c 300 -n 20000 http://ip:port

image

Now same thing in the swoole:

<?php

require __DIR__.'/vendor/autoload.php';

use Illuminate\Database\Capsule\Manager as Capsule;
use Swoole\Http\Request;
use Swoole\Http\Response;
use Swoole\Http\Server;

$capsule = new Capsule;

$capsule->addConnection([
    'driver' => 'pgsql',
    'host' => 'postgres',
    'database' => 'your_db_name',
    'username' => 'your_db_user',
    'password' => 'your_db_password',
    'charset' => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix' => '',
]);

// Set the event dispatcher used by Eloquent models... (optional)
use Illuminate\Events\Dispatcher;
use Illuminate\Container\Container;

// Make this Capsule instance available globally via static methods... (optional)
$capsule->setAsGlobal();

// Setup the Eloquent ORM... (optional; unless you've used setEventDispatcher())
$capsule->bootEloquent();

$http = new Server('0.0.0.0', 9501);

$http->on(
    'start',
    function (Server $http) {
        echo "Swoole HTTP server is started.\n";
    }
);

$http->on(
    'request',
    function (Request $request, Response $response) use($capsule, $bot) {
        $result = $capsule->connection()->table('users')->first();
        $response->end($result);
    }
);

$http->start();

image

This test was conducted on a server with 4gb ram and a 2 cpu (2.5GHz) setup. Do I need to modify anything to reduce cpu usage, or is this just how it is?

In the Illuminate library setup you provided, the Capsule Manager does indeed add a database connection, but it doesn't explicitly define a connection pool. Each time a request is made to the database, a new connection may be established, without much control over connection reuse or management. This can lead to potential inefficiencies, especially in high-concurrency scenarios, as opening and closing connections frequently can incur unnecessary overhead.

On the other hand, the Hyperf framework configuration explicitly defines a connection pool for PostgreSQL. By specifying parameters like min_connections, max_connections, and other pool-related settings, Hyperf effectively manages a pool of database connections. This approach is more efficient, as it maintains a set of pre-established connections that can be reused as needed, reducing the overhead of connection establishment and teardown (but can higher CPU usage).

Start Hyperf application and execute:
ab -c 300 -n 20000 http://ip:port

Later, execute in PostgreSQL:

SELECT 
    usename AS username,
    COUNT(*) AS total_connections
FROM 
    pg_stat_activity
GROUP BY 
    usename;

...Make equal process in swoole application and verify :)

I removed the database layer and tested a simple "Hello, World!" response.

hyperf:

class IndexController
{
    public function index()
    {
        return 'Hello, World!';
    }
}

image

Swoole:

image

In every scenario, it consumes twice as much as swoole itself.

In your config file server.app is defined like:

return [
    'mode' => SWOOLE_PROCESS,
    'servers' => [
        [
            'name' => 'http',
            'type' => Server::SERVER_HTTP,
            'host' => '0.0.0.0',
            'port' => 9501,
            'sock_type' => SWOOLE_SOCK_TCP,
            'callbacks' => [
                Event::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
            ],
        ],
    ],
    'settings' => [
        Constant::OPTION_ENABLE_COROUTINE => true,
        Constant::OPTION_WORKER_NUM => swoole_cpu_num(), // <- CHANGE TO 1 CPU WORKER AND VERIFY
        Constant::OPTION_PID_FILE => BASE_PATH . '/runtime/hyperf.pid',
        Constant::OPTION_OPEN_TCP_NODELAY => true,
        Constant::OPTION_MAX_COROUTINE => 100000,
        Constant::OPTION_OPEN_HTTP2_PROTOCOL => true,
        Constant::OPTION_MAX_REQUEST => 100000,
        Constant::OPTION_SOCKET_BUFFER_SIZE => 2 * 1024 * 1024,
        Constant::OPTION_BUFFER_OUTPUT_SIZE => 2 * 1024 * 1024,
    ],
    'callbacks' => [
        Event::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
        Event::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'],
        Event::ON_WORKER_EXIT => [Hyperf\Framework\Bootstrap\WorkerExitCallback::class, 'onWorkerExit'],
    ],
];

Function swoole_cpu_num() in your case added 2 cpu workers and consume higher CPU.
Hyperf start full complete server with various components. Normal consume CPU Hyperf be higher what Swoole simple app.

'mode' => SWOOLE_BASE

really...