Scalable WebSocket Server for Laravel Applications

Why WebSockets? Old days of web page consist of the only HTTP Omni directional requests. But when need to bi-directional real-time communication arises, it solved by methods like long pooling, [...]

Why WebSockets?

Old days of web page consist of the only HTTP Omni directional requests. But when need to bi-directional real-time communication arises, it solved by methods like long pooling, which is not exactly HTTP is built for. WebSocket solves the problem of real-time bi-directional communication.

Most of the steps including advantages of WebSocket communication, covered in in my previous blog post.

The shortcoming in jithinjose2/websocket V1

WebSocket version 1 address the problem of easy integration and use of WebSocket in PHP applications. It does work great for an application which has less number of clients. Most of the shortcomings of V1 is unnoticeable if each request messages requires very less processing time. Which can be useful for applications like chats and games.

Weboscket V1 problems

WebSocket V1 problems

The problem related to V1 become more visible if individual messages take some time to process in the server. If message 1 takes 5seconds to process, which will blocks all other messages comes to the server in that 5 seconds. This also makes internal message queue to grow larger. Since message2 has to wait for 5 seconds it has to wait for additional 5 seconds to process the queue.

Another problem associated with WebSocket package is the message triggering is limited by the WebSocket clients only. Which means normal HTTP requests or another PHP process cannot send a message to a client connected to WebSocket server. This limits the usage of the module system because it is always WebSocket client to WebSocket client communication.

Another problem associated with the same implementation is scalability. This limits the number of requests can be handled in a single instance because message processing also is done on the same instance running WebSocket server. Which limits the scalability of the system. WebSocket package V2 is created to address these problems.

Improving latency and adding scalability in V2

The above-stated problems are solved by implementing Incoming and Outgoing queues in WebSocket. In the new architecture, the duty of the WebSocket server is to push new messages to the output queue and send input queue messages to the respectively connected clients.

Websocket 2.0 archteture solving scalabilty problems.

Websocket 2.0 architecture solving scalability problems.

In V2 if message1 received by the server it is validated and moved to a processing queue by WebSocket server. So the server is instantly available to accept new connections. So message1 coming to the server does not need any waiting time and instantly get processed. As we can notice the total processing time reduced from 10 seconds to 6 seconds.

Another important advantage is scalability. Each message added to the queue is processed by workers. depending on system load we deploy any number of workers on multiple systems. This gives the flexibility to scale the system depending on system load. ALl worker process will pop messages from queue and process one by one. So more the worker process faster the messages in the queue will be executed.

WebSocket server also listens to input queue for any messages, if any messages are present in the queue, it will forward that message to the respective clients. This enables sending messages to any of the clients from anywhere in the cloud.

Installation

Websocket v 2.* is created to use with laravel applications. First install package using composer.

[bash]
composer require jithinjose2/websocket
[/bash]

After updating composer, add the ServiceProvider to the provider’s array in config/app.php

[php]
JithinJose2\WebSocket\ServiceProvider::class
[/php]

Copy the package config to your local config with the publish command:

[bash]
php artisan vendor:publish
[/bash]

Configuration

WebSocket server is default configuration can be changed in config/websocket.php, this includes listening address and port number.

[php]
// Websocket hostname
‘host’ => ‘localhost’,

// Port at which websocket server is listening on
‘port’ => ‘8000’,

// Need to use ssl for wss connections
‘ssl’ => false,

// Websocker Handler for websocket events
‘handler’ => \Chat\Wshandle::class,

‘actions’ => [
‘chat_text’ => \Chat\Actions\ChatMessageAction::class
]
[/php]

Handler

Handler plays important part in WebSocket connections. This class handles basic WebSocket events and should implement [code]JithinJose2\WebSocket\Interfaces\WebsocketHandleInterface[/code] interface.

[php]
public function connect($data);

public function disconnect($connectionId, $userId);

public function loop();

public function action($connectionId, $userID, $action, $data);
[/php]

connect function will be called when the client is requesting for the registration. The connect request should return connection_id and guest_id. Guest_id used for identifying the user, but connection_id should be unique for each connection. That means we can have multiple connections for the same user.

disconnect function trigger when a client is disconnected from the server.

loop function will be called in each iteration of WebSocket server.

action function will be called when a message coming from the client and no specific handler for that action.

Actions

The action is each message from the client. Each message sends to the client and received from the client includes an ‘action’ key. Action handlers handle one action. The key in the ‘actions’ array is the action string sent by the client. each action handler should implement [code]JithinJose2\WebSocket\Interfaces\WebsocketActionInterface[/code] interface. this includes only one function.

[php]
public function handle($connectionId, $userId, $data, $meta);
[/php]

Handle function will be called a when an incoming message from a client with given action. connection_id and user_id indicate action source. $data will have the payload of the message and $meta is contained metadata.

Websocket server uses Redis as queue. It will use Redis connection configuration in config/redis.php so make sure that it is configured properly.

Usage

Once the configuration is done we can start WebSocket server by the following command.

[bash]
$ php artisan websocket:serve

Starting Websocket server AT: ws://127.0.0.1:8000
2017-08-20 09:10:56 [info] Server started listening to port 8000
[/bash]

After that need to start worker process using the folwing command, and you can start multiple processes in multiple instances.

[bash]
$ php artisan websocket:work
[/bash]

All the worker process should use same redis instance.

Once server and worker are running, we can send messages to any client from any process (artisan commands, normal HTTP requests) using websocket() helper.
[php]
websocket()->to($connectionId)->send(‘chat_text’, $data);
[/php]

Previous:

Tagged with:

jithinjose2

I am a Software Engineer with more than 5+years of experience.

Website: http://jithin.pw/