workerman icon indicating copy to clipboard operation
workerman copied to clipboard

about sessions & token support

Open raghuveer opened this issue 2 years ago • 16 comments

Hi,

I am interested to know, if you recommend any sessions library that works in async mode instead of $_SESSIONS superglobal with Workerman?

I came across https://docs.mezzio.dev/mezzio-session/, but that still implements $_SESSIONS and some token based sessions alternatively.

please check and share your inputs

thank you

raghuveer avatar Dec 17 '21 06:12 raghuveer

Workerman has its own session management mechanism. Global variable $_SESSION cannot be used. The documentation on the use of session by workerman is here workerman http session (Sorry, there are no English documents at present). I think it is simple enough that no other session libraries are required.

walkor avatar Dec 17 '21 06:12 walkor

Hi

Is there any possibility to use Redis as Session store in Workerman http session library scenario?

please share your inputs

Thank you

raghuveer avatar Dec 17 '21 13:12 raghuveer

Yes, use Redis as Session store in Workerman the codes like this.

<?php
use Workerman\Worker;
use Workerman\Protocols\Http\Session;
use Workerman\Protocols\Http\Session\RedisSessionHandler;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('http://0.0.0.0:8080');

$config = [
    'host'     => '127.0.0.1', 
    'port'     => 6379,       
    'timeout'  => 2,           
    'auth'     => '',    
    'database' => 1,           
    'prefix'   => 'session_'   
];
Session::handlerClass(RedisSessionHandler::class, $config);

$worker->onMessage = function(TcpConnection $connection, Request $request)
{
    $session = $request->session();
    $session->set('somekey', rand());
    $connection->send($session->get('somekey'));
};

Worker::runAll();

Here is the document https://www.workerman.net/doc/workerman/http/session-control.html#%E6%9B%B4%E6%94%B9session%E5%AD%98%E5%82%A8%E5%BC%95%E6%93%8E

walkor avatar Dec 17 '21 13:12 walkor

Awesome Walkor, thank you

raghuveer avatar Dec 17 '21 16:12 raghuveer

a query Walkor,

We generally use https://www.php.net/manual/en/function.session-regenerate-id.php, every time user login request becomes successful, any method is implemented in this respect in https://www.workerman.net/doc/workerman/http/session.html

please share your inputs

thank you

raghuveer avatar Dec 18 '21 01:12 raghuveer

Workerman does not implement session at present. Maybe we will try it in V5. In workman V4, we need to implement it with codes similar to the following

<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
use Workerman\Protocols\Http\Session;
use Workerman\Protocols\Http\Response;
use Workerman\Protocols\Http\Request;
$worker = new Worker('http://0.0.0.0:12345');
$worker->onMessage = function($connection, Request $request)
{
     $session = $request->session();
     $session_data = $session->all();
     $new_sid = \bin2hex(\pack('d', \microtime(true)) . \pack('N', \mt_rand()));
     $session = new Session($new_sid);
     $session->put($session_data);
     $response = (new Response(200, [],  'html data'))->cookie('PHPSID' , $new_sid);
     $connection->send($response);
};

Worker::runAll();

walkor avatar Dec 19 '21 13:12 walkor

@walkor I suppose Workerman sessions are not async? I got about -80% performance degradation with sessions.

vandergrafgenerator avatar Dec 19 '21 16:12 vandergrafgenerator

Asynchronous session storage may cause some problems. For example, the same user initiates two requests, and the second request depends on the session of the first request. If asynchronous is used, the session may not be stored to the disk after the first request returns successfully. At this time, the session obtained by the second request may be expired.

Session is a relatively slow io. The speed of disk or network IO is much lower than that of memory storage, so QPS decline is a normal phenomenon. At this time, you can try to alleviate this problem by setting more processes through $worker - > count.

walkor avatar Dec 20 '21 01:12 walkor

I am fine to add session related code as shown in the example and I asked about Redis handler to be able to handle sessions for multiple servers without using sticky sessions in load balancer scenario. While I used to use $_SESSION well earlier, since the thought process is to have things to support async scenarios, if sessions can be managed to multiple users?

implementation of session_regenerate_id scenario as a method in session library of workerman also may help I think...

please share your inputs

Thank you

raghuveer avatar Dec 20 '21 02:12 raghuveer

Sorry, I can't fully understand your post. session_regenerate_id is expected to be supported in V5.

walkor avatar Dec 20 '21 03:12 walkor

what I meant is:

Everytime we use multiple web servers with php and behind a load balancer, we always used $_SESSION superglobal with redis as session store, when developing php code in synchronous way over years, all this before we started thinking- to try async libraries like amphp/reactphp/workerman etc... libraries that helps us do in async way.

While you suggested about using https://www.workerman.net/doc/workerman/http/session.html and when you confirmed that Redis handler is available too, I felt really happy as we will be able to add few additional lines of session related configuration when including workerman, which is fine and I am happy to hear from you that you will support php's inbuilt session_regenerate_id functionality in Workerman (either part of https://www.workerman.net/doc/workerman/http/session.html or as inbuilt functionality of Workerman itself when releasing the Workmerman v5 version).

The only thing I am thinking about is if, session functionality works fine if implemented in sync way, with other async functionality, and @walkor , as you mentioned in one of your previous reply, can we make sessions handling faster if we increase number of workers?

Unlike php setup using php-fpm or mod_apache where a request parses all libraries that are added using include/require statements or autoloaded using PSR-4 auto loader, in async scenario, we load the application through CLI and then connect to that from web application. While $_SESSION kind of superglobals are not used, new sessions be created and we be able to regenerate session id after change of privileges (example: after successful user login activity), while also be able to destroy sessions of a user when the user logout or when no activity is observed for a set period of time like 5 minutes in time sensitive application scenarios in banking/stocks etc... scenarios?

P.S. While I am watching async libraries like reactphp, amphp, swoole, workerman, symplely over years, I took time to try some libraries beyond default examples and I made my start few months earlier when me and some of my team members created wrappers for amphp libraries and used that in a websocket service that I had built using ratchet, amphp libraries, redis pubsub, mariadb etc back in march 2021. AMPHP developer helped a lot then, a quick flashback...

raghuveer avatar Dec 20 '21 05:12 raghuveer

can we make sessions handling faster if we increase number of workers?

If there is blocked IO, the throughput can be increased by increasing the number of processes. But too many processes will increase the overhead of CPU process switching. So we need to find a balance. The number of processes is recommended to be 2-3 times that of CPU.

Let me talk about my view of PHP asynchrony. At present, it is very difficult to implement asynchrony in all IO in PHP. Although many frameworks / extensions are doing this(thanks to the efforts of these projects), the overall effect is not good enough. And asynchrony has changed our programming habits and made the program more complex. Although php8 1 has built-in fiber. At present, some of our commonly used extensions, such as PDO and redis, do not support fiber natively, which may require us to implement these with PHP code. However, it takes a lot of CPU for PHP to implement MySQL protocol parsing, so we will see that even if we implement the asynchrony of MySQL, redis and other clients, the overall performance may not be as good as that of PHP's native PDO redis extension. Look at techempower benchmark. Workerman uses php native PDO and blocking io , and its performance is higher than that of other asynchronous concurrency frameworks with database connection pool. This makes us think that we have done so much work for asynchrony, but the effect is not particularly prominent. If I am a project leader, I will base my project on workerman and use traditional blocking IO programming. That is simpler and easier to maintain, and we can reuse a large number of existing composer class libraries, and has very good performance too. The fiber ecology of PHP has just begun, and there is still a long way to go.

walkor avatar Dec 20 '21 06:12 walkor

I am really surprised to read what you wrote.

You are right, while I am used to php-fpm setup and took lot of time to turn towards PHP cli based script triggering (other than when implementing cron jobs), and into async programming ways.

while I love to use PDO, I had used wrapper mysql library of amphp mysql library.

I hope to see the difference as a benchmark through comparison if possible

Coming to configuring the workers, is there no way to auto-configure no. of workers triggered with workerman? or we can dynamically change no. of workers as CPU resources are increased/decreased on the cloud for specific virtual machine?

This above question is asked in vertical auto scaling perspective (i.e., scale up/down) only as horizontal auto scaling (scale out/in) might be out of scope in many way even to think of....

+++++++++ while I always felt bad to leave PDO that I used over 10 to 15 years towards async mysql implementations, in one of the recent projects, you breathed life into my thought process as sync approach code may perform better than async code that comes with keywords like yield, yieldfrom, await, etc..., that I am not used to, after handling procedural oriented programming over decade+ years.

I will sponsor virtual machines on digitalocean or other kind of, if you can do a benchmark with 1 million requests, for

  1. workerman sessions in filesystem and on redis using your session library
  2. pdo and async mysql on workerman

after workerman v5 is live.

Check this async mysql library, that is based on amphp https://github.com/invincible-tech-systems/easeamp-mysql

Note: I didnot update this, after revoltphp is introduced though.

raghuveer avatar Dec 20 '21 17:12 raghuveer

Coming to configuring the workers, is there no way to auto-configure no. of workers triggered with workerman? or we can dynamically change no. of workers as CPU resources are increased/decreased on the cloud for specific virtual machine?

When workerman starts, we cannot auto change the number of workers. So we must determine the count before starting.

I will sponsor virtual machines on digitalocean or other kind of, if you can do a benchmark with 1 million requests.

Ok

walkor avatar Dec 21 '21 04:12 walkor

Hi @raghuveer

I'm a contributor to php-ngx, workerman, kumbiaphp, .... and maintainer in the Techempower benchmark, where I try to make all php ecosystem faster.

Workerman sessions in filesystem and on redis using your session library?

Surely it is faster the filesystem. In Linux that files will end up in Linux Filesystem Cache (RAM). Also normally the session use more read than write.

Example with Memcache:

Storage-Engine Runtime
sql.php (Mysql) 300 ms
memcache.php 290 ms
memcache.php (localhost) 60 ms
apc.php 10 ms

The use of Redis or Memcache, it is not for performance but for manage multiple app servers.

PDO and async Mysql on Workerman?

@walkor send you the link to the benchmark Techempower Benchmark

There you can check it, with Mysql:

Framework Responses/s Info
Workerman 372,725 PDO no async
Workerman async 175,447 Async using ReactPHP
php-ngx 374,187 PDO no async
php-ngx-async 307,279 php-ngx lib mysql async wihout pool
Swoole 347,815 Swoole lib async mysql with pool
Swoole-noasync 349,992 I added this variant with PDO
Amp 11,409 Amp libs *

Amp in the last runs with v2.6.1, changed event-loop lib ev to lib event and the most important php8.1 is now 46,346 req/s. Less than half than PHP with php-fpm (114,437 req/s). And actually ReactPHP is added with lib event , and only 5,573 req/s.

This week we added Open Swoole, that it's using the php8.1 fibers with swoole event-loop (not revolt). And the results are similar.

Async is not faster but scale better!

The time to receive data from database, redis, memcached, filesystem, .... is the same async or sync.

A good programmer than understand the event-loop and async, can make certain apps faster using a fast framework. If the programmer only add async, without knowledge, will make the app slower. The app will be faster without async and using only the event-loop.

In the bechmark a lot of fw using Swoole are slow.

The latency of PHP with php-fpm is 1.0ms and Workerman 1.4ms. Remember here that if one is sending more request per second, the latency will notice it too.

The async is most useful to make background jobs.

Understand the stack

It's more important than async or sync. Because it will affect in both.

Any tcp call, try to use persistent connections, pool of connections, .... Configurations well done, etc

joanhey avatar Dec 21 '21 21:12 joanhey

@joanhey

thanks for the detailed information, I appreciate this and full agree with.

I made minimal attempts writing code in concurrency perspective and with event based programming models till now, other than the usage of multi-curl in the past and a websocket service implementation that was done in this year using reactphp based ratchet & amphp based libraries etc... that utilizes redis pubsub.

This attempt to break the ice and wet my hands in terms of integrating async libraries, to progress more in handling increased number of requests with my applications (that always run either with nginx & apache or nginx with php-fpm stack most of the time).

By the by, I always used redis as session store when multiple servers are deployed behind a load balancer, to serve the application and specifically to avoid using sticky sessions and in other scenarios, used memcache & redis as in-memory cache for performance in terms of alleviating load on database servers.

While I am worried and am thinking to minimize sync code usage after starting to consider using async libraries, as it might hold the event loop waiting for the response, the benchmark and numbers you had presented is an eye opener, Thanks for that again.

raghuveer avatar Dec 22 '21 01:12 raghuveer