Build Websocket microservices through gatewayworker / workman

background

Recently, some projects need to use Websocket to push real-time to grouped users, and there is less information to be transmitted from the front end to the back end. Through various considerations, we chose to build microservices through the gateway worker framework (based on workman).

introduce   Workerman

Workerman is an open source high-performance PHP socket service framework developed in pure PHP.

Workman is not a repeated wheel. It is not an MVC framework, but a more general socket service framework. You can use it to develop tcp agent, ladder agent, game server, mail server, ftp server, and even develop a PHP version of redis, PHP version of database, PHP version of nginx, PHP version of PHP FPM, etc. Workerman can be said to be an innovation in the field of PHP, allowing developers to completely get rid of the shackles that PHP can only do WEB.

In fact, workman is similar to a PHP version of nginx, and its core is multi process + Epoll + non blocking IO. Workman can maintain tens of thousands of concurrent connections per process. Due to its permanent memory, it does not rely on Apache, nginx and PHP FPM containers, and has ultra-high performance. At the same time, it supports TCP, UDP, UNIXSOCKET, long connection, communication protocols such as Websocket, HTTP, WSS, HTTPS and various custom protocols. It has many high-performance components, such as timer, asynchronous socket client, asynchronous Mysql, asynchronous Redis, asynchronous HTTP, asynchronous message queue and so on.

github address: GitHub - walkor/Workerman: An asynchronous event driven PHP socket framework. Supports HTTP, Websocket, SSL and other custom protocols. PHP>=5.3.

file: http://doc.workerman.net/315110

GatewayWorker

Based on a project framework developed by workman, GatewayWorker is used to quickly develop TCP long connection applications, such as app push server, real-time IM server, game server, Internet of things, smart home, etc

Gateway Worker uses the classic gateway and Worker process model. The gateway process is responsible for maintaining the client connection and forwarding the client data to the BusinessWorker process for processing. The BusinessWorker process is responsible for processing the actual business logic (calling Events.php to process the business by default) and pushing the results to the corresponding client. Gateway Services and BusinessWorker services can be deployed separately on different servers to realize distributed clustering.

GatewayWorker provides a very convenient API, which can broadcast data globally, broadcast data to a group, or push data to a specific client. With the timer of Workerman, you can also push data regularly.

github address: GitHub - walkor/GatewayWorker: Distributed realtime messaging framework based on workerman.

file: http://doc2.workerman.net/326102

Relationship between workman and gateway worker

Workerman can be regarded as a pure socket class library, which can develop almost all network applications, whether TCP or UDP, long connection or short connection. Workman code is concise, powerful and flexible, and can quickly develop various network applications. At the same time, compared with gateway worker, workman is also lower level, and developers need to have some multi process programming experience.

Because the goal of most developers is to develop TCP long connection applications based on Workerman, and long connection application servers have a lot in common, such as they have the same process model and interface requirements such as single sending, group sending and broadcasting. That's why there is the Gateway Worker framework. Gateway Worker is a TCP long connection framework developed based on Workerman, which realizes the necessary interfaces for long connections such as single sending, group sending and broadcasting. The Gateway Worker framework implements the Gateway Worker process model, which naturally supports distributed multi server deployment. It is very convenient to expand and shrink capacity, and can deal with massive concurrent connections. It can be said that Gateway Worker is a more perfect project framework based on workman implementation, which is specially used to realize TCP long connection.

GatewayClient

GatewayClient is the client program of GatewayWorker, which can push, group, count and other operations.

Introduction to websocket microservice

In general, the websocket microservice does not process business logic. It is only a one-way connection and is only responsible for pushing information. However, when the client connects to the websocket microservice, the websocket microservice returns the client clientId, and the client invokes the interface to pass the clientId to the back end. At this time, the back end can bind users to specific groups through the gateway client. However, when push is needed, communicate with GatewayWorker through text protocol, pass the clientId or packet to be pushed to GatewayWorker, and then the GatewayWorker pushes it to the client. The diagram is as follows:

Concrete implementation   Installing the GatewayWorker kernel

Create a new blank project (not in PHP frameworks such as Laravel/Lumen/ThinkPHP) and execute it

composer require workerman/gateway-worker

  Startup file

Create start.php as the startup file in the root directory. Code:

<?php

ini_set('display_errors', 'on');
use Workerman\Worker;

if(strpos(strtolower(PHP_OS), 'win') === 0)
{
    exit("start.php not support windows, please use start_for_win.bat\n");
}

// Check extension
if(!extension_loaded('pcntl'))
{
    exit("Please install pcntl extension. See http://doc3.workerman.net/appendices/install-extension.html\n");
}

if(!extension_loaded('posix'))
{
    exit("Please install posix extension. See http://doc3.workerman.net/appendices/install-extension.html\n");
}

// Flag is global startup
define('GLOBAL_START', 1);

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

// Load all Applications/*/start.php to start all services
foreach(glob(__DIR__.'/src/start*.php') as $start_file)
{
    require_once $start_file;
}
// Run all services
Worker::runAll();

Register class

The Register class is responsible for registering the internal communication address. After the Gateway process and BusinessWorker process are started, Register their own communication addresses with the Register process respectively. After the Gateway process and BusinessWorker get the communication addresses through the Register process, they can establish a connection and communicate.

How GatewayWorker works

src/start_register.php (the directory name can be defined by yourself) code:

<?php 

use \GatewayWorker\Register;

// register service must be a text protocol
$register = new Register('text://0.0.0.0:1238');

Register Gateway class

The Gateway class is used to initialize the Gateway process. The Gateway process is the process exposed to the client to connect. All client requests are received by the Gateway and then distributed to the business worker for processing. Similarly, the business worker will forward the response to the client through the Gateway.

src/start_gateway.php Code:

<?php
use \Workerman\Worker;
use \Workerman\WebServer;
use \GatewayWorker\Gateway;
use \GatewayWorker\BusinessWorker;
use \Workerman\Autoloader;

// gateway process
$gateway = new Gateway("websocket://0.0.0.0:8282");
// gateway name and status are easy to view
$gateway->name = 'business-gateway';
// Number of gateway processes
$gateway->count = 2;
// Native ip. Intranet ip is used for distributed deployment
$gateway->lanIp = '127.0.0.1';
// Internal communication start port. If $Gateway - > count = 4, the start port is 4000
// Generally, 4000 4001 4002 4003 ports will be used as internal communication ports 
$gateway->startPort = 2900;
// Service registration address (register class address)
$gateway->registerAddress = '127.0.0.1:1238';

Register BusinessWorker class

BusinessWorker is a process that runs business logic. When BusinessWorker receives events and requests forwarded by the Gateway, it will call the onConnect onMessage onClose method in Events.php by default to process events and data. Developers control business and processes by implementing these callbacks.

src/start_businessworker.php Code:

<?php

use \Workerman\Worker;
use \Workerman\WebServer;
use \GatewayWorker\Gateway;
use \GatewayWorker\BusinessWorker;
use \Workerman\Autoloader;

// bussinessWorker process
$worker = new BusinessWorker();
// worker name
$worker->name = 'Steam-BusinessWorker';
// Number of bussinessWorker processes
$worker->count = 1;
// Service registration address
$worker->registerAddress = '127.0.0.1:1238';

Events class

The Events class is used to capture GatewayWorker Events, where you can write some callback information.

src/Events.php Code:

<?php

/**
 * It is used to detect problems such as business code deadlock or long-time blocking
 * If the business card is found dead, you can open the following declare (remove the / / comment) and execute php start.php reload
 * Then observe the workerman.log for a period of time to see if there is a process_timeout exception
 */
//declare(ticks=1);

use \GatewayWorker\Lib\Gateway;

/**
 * Main logic
 * It mainly deals with three methods: onconnect, onmessage and onclose
 * onConnect And onClose can be implemented and deleted if not required
 */
class Events
{
    /**
     * Triggered when the client connects
     * If the service does not need this callback, you can delete onConnect
     *
     * @param int $client_id Connection id
     */
    public static function onConnect($client_id)
    {
        // To the current client_id send data 
        Gateway::sendToClient($client_id, json_encode([
            'clientId' => $client_id,
        ]));
    }

    /**
     * Triggered when the client sends a message
     * @param int $client_id Connection id
     * @param mixed $message Specific information
     */
    public static function onMessage($client_id, $message)
    {
    }

    /**
     * Triggered when the user disconnects
     * @param int $client_id Connection id
     */
    public static function onClose($client_id)
    {
    }
}

Group or push projects to clients in PHP

This is the code written in your own project. Process: the front end calls the interface to pass the clientId, the back end binds to the group, and then pushes the information to the group or the specified clientId client.

The GatewayClient package needs to be referenced in the project

composer require workerman/gatewayclient

code:

// The gateway client added a namespace after version 3.0.0
use GatewayClient\Gateway;

/**
 * === Specify registerAddress to indicate which gateway worker (cluster) to communicate with===
 * GatewayWorker Register service is used to distinguish clusters, that is, a gateway worker (cluster) has only one register service,
 * GatewayClient To communicate with it, you must know the Register service address. The address format is ip: port,
 * Where ip is the ip of the Register service (if GatewayWorker is deployed in a single machine, ip is the ip of the server running GatewayWorker),
 * The port is start on the server corresponding to the ip_ The listening port in the Register.php file is the port of the Register seen when GatewayWorker starts.
 * GatewayClient To push data to the client, you must know which gateway worker the client is located in,
 * Then connect the ip: port of the gateway worker (cluster) Register service to communicate with the corresponding gateway worker (cluster).
 * This ip: port is specified on the gateway client side using Gateway::$registerAddress.
 * 
 * === If the GatewayClient and GatewayWorker are not on the same server, the following steps are required===
 * 1,Start needs to be set_ lanIp in gateway.php is the actual local intranet IP (if it is not in a LAN, it can also be set as an Internet ip). After setting, restart gateway worker
 * 2,GatewayClient For the Gateway::$registerAddress, fill in the ip and port specified in step 1lanIp above
 * 3,You need to open the firewall of the server where the GatewayWorker is located so that the following ports can be accessed by the server where the GatewayClient is located,
 *    The port includes the port of Rgister service and start_ Several ports specified by lanIp and startPort in gateway.php
 *
 * === If GatewayClient and GatewayWorker are on the same server===
 * GatewayClient Both the and Register services are on the same server. You can fill in 127.0.0.1 and. No other settings are required.
 **/
Gateway::$registerAddress = '127.0.0.1:1236';

// GatewayClient supports all interfaces in GatewayWorker (except gateway:: closecurrentclient gateway:: sendtocurrent client)
Gateway::sendToAll($data);
Gateway::sendToClient($client_id, $data);
Gateway::closeClient($client_id);
Gateway::isOnline($client_id);
Gateway::bindUid($client_id, $uid);
Gateway::isUidOnline($uid);
Gateway::getClientIdByUid($client_id);
Gateway::unbindUid($client_id, $uid);
Gateway::sendToUid($uid, $dat);
Gateway::joinGroup($client_id, $group);
Gateway::sendToGroup($group, $data);
Gateway::leaveGroup($client_id, $group);
Gateway::getClientCountByGroup($group);
Gateway::getClientSessionsByGroup($group);
Gateway::getAllClientCount();
Gateway::getAllClientSessions();
Gateway::setSession($client_id, $session);
Gateway::updateSession($client_id, $session);
Gateway::getSession($client_id);

Keywords: PHP Database websocket

Added by l3asturd on Fri, 17 Sep 2021 19:57:37 +0300