Implementation of Swoole Redis connection pool

This article only implements a Redis connection pool, which is too short. By the way, integrate the previous several articles.

These points are roughly included in the Demo:

Implement MySQL connection pool

Implement MySQL CURD method definition

Realize Redis connection pool

Implement the definition of Redis method

Meet HTTP, TCP, WebSocket calls

Provide Demo for testing

Adjust directory structure

HTTP call:

Implement the Demo to read data in MySQL

Implement the Demo of reading data in Redis

640?wx_fmt=png

TCP call:

Implement the Demo to read the data in MySQL

Implement the Demo of reading data in Redis

640?wx_fmt=png

WebSocket call:

Implementation shows the number of API calls per second Demo

640?wx_fmt=gif
directory structure

    ├─ client    
    │  ├─ http    
 - mysql.php / / test MySQL connection 

    │  ├─ tcp    
 - mysql.php / / test MySQL connection 

    │  ├─ websocket    
index.html / / display API usage
    ├─ controller    
Order.php / / implement MySQL CURD
Product.php / / implementation of Redis call
Data of simulated API calls
    ├─ server    
    │  ├─ config    
Configuration.php / / default configuration
 - mysql.php / / MySQL configuration

    │  ├─ core    
Common.php / / public methods
Core.php / / core file
 Ɏ - HandlerException.php / / exception handling
Call / / callback processing
    │         ├── OnRequest.php    
    │         ├── OnReceive.php    
    │         ├── OnTask.php    
    │         ├── ...    
    │     ├── mysql    
    │         ├── MysqlDB.php    
    │         ├── MysqlPool.php    
    │     ├── redis    
    │         ├── RedisDB.php    
    │         ├── RedisPool.php    
Read / write permission required
    │     ├── ...    
├ - index.php / / entry file

Code

server/core/redis/RedisPool.php

    <?php    
    if (!defined('SERVER_PATH')) exit("No Access");    
    class RedisPool    
    {    
        private static $instance;    
        private $pool;    
        private $config;    
        public static function getInstance($config = null)    
        {    
            if (empty(self::$instance)) {    
                if (empty($config)) {    
                    throw new RuntimeException("Redis config empty");    
                }    
                self::$instance = new static($config);    
            }    
            return self::$instance;    
        }    
        public function __construct($config)    
        {    
            if (empty($this->pool)) {    
                $this->config = $config;    
                $this->pool = new chan($config['master']['pool_size']);    
                for ($i = 0; $i < $config['master']['pool_size']; $i++) {    
                    go(function() use ($config) {    
                        $redis = new RedisDB();    
                        $res = $redis->connect($config);    
                        if ($res === false) {    
                            throw new RuntimeException("Failed to connect redis server");    
                        } else {    
                            $this->pool->push($redis);    
                        }    
                    });    
                }    
            }    
        }    
        public function get()    
        {    
            if ($this->pool->length() > 0) {    
                $redis = $this->pool->pop($this->config['master']['pool_get_timeout']);    
                if (false === $redis) {    
                    throw new RuntimeException("Pop redis timeout");    
                }    
                defer(function () use ($redis) { //release    
                    $this->pool->push($redis);    
                });    
                return $redis;    
            } else {    
                throw new RuntimeException("Pool length <= 0");    
            }    
        }    
    }

 



server/core/redis/RedisDB.php

    <?php    
    if (!defined('SERVER_PATH')) exit("No Access");    
    class RedisDB    
    {    
        private $master;    
        private $slave;    
        private $config;    
        public function __call($name, $arguments)    
        {    
            // Operation of TODO main library    
            $command_master = ['set', 'hset', 'sadd'];    
            if (!in_array($name, $command_master)) {    
                $db = $this->_get_usable_db('slave');    
            } else {    
                $db = $this->_get_usable_db('master');    
            }    
            $result = call_user_func_array([$db, $name], $arguments);    
            return $result;    
        }    
        public function connect($config)    
        {    
            //Main library    
            $master = new Swoole\Coroutine\Redis();    
            $res = $master->connect($config['master']['host'], $config['master']['port']);    
            if ($res === false) {    
                throw new RuntimeException($master->errCode, $master->errMsg);    
            } else {    
                $this->master = $master;    
            }    
            //Slave Library    
            $slave = new Swoole\Coroutine\Redis();    
            $res = $slave->connect($config['slave']['host'], $config['slave']['port']);    
            if ($res === false) {    
                throw new RuntimeException($slave->errCode, $slave->errMsg);    
            } else {    
                $this->slave = $slave;    
            }    
            $this->config = $config;    
            return $res;    
        }    
        private function _get_usable_db($type)    
        {    
            if ($type == 'master') {    
                if (!$this->master->connected) {    
                    $master = new Swoole\Coroutine\Redis();    
                    $res = $master->connect($this->config['master']['host'], $this->config['master']['port']);    
                    if ($res === false) {    
                        throw new RuntimeException($master->errCode, $master->errMsg);    
                    } else {    
                        $this->master = $master;    
                    }    
                }    
                return $this->master;    
            } elseif ($type == 'slave') {    
                if (!$this->slave->connected) {    
                    $slave = new Swoole\Coroutine\Redis();    
                    $res = $slave->connect($this->config['slave']['host'], $this->config['slave']['port']);    
                    if ($res === false) {    
                        throw new RuntimeException($slave->errCode, $slave->errMsg);    
                    } else {    
                        $this->slave = $slave;    
                    }    
                }    
                return $this->slave;    
            }    
        }    
    }

 



client/http/redis.php

    <?php    
    $demo = [    
        'type'  => 'SW',    
        'token' => 'Bb1R3YLipbkTp5p0',    
        'param' => [    
            'class'  => 'Product',    
            'method' => 'set',    
            'param' => [    
                'key'   => 'C4649',    
                'value' => 'Order-C4649'    
            ],    
        ],    
    ];    
    $ch = curl_init();    
    $options = [    
        CURLOPT_URL  => 'http://10.211.55.4:9509/',    
        CURLOPT_POST => 1,    
        CURLOPT_POSTFIELDS => json_encode($demo),    
    ];    
    curl_setopt_array($ch, $options);    
    curl_exec($ch);    
    curl_close($ch);

 

 

client/tpc/redis.php

    <?php    
    class Client    
    {    
        private $client;    
        public function __construct() {    
            $this->client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);    
            $this->client->on('Connect', [$this, 'onConnect']);    
            $this->client->on('Receive', [$this, 'onReceive']);    
            $this->client->on('Close', [$this, 'onClose']);    
            $this->client->on('Error', [$this, 'onError']);    
        }    
        public function connect() {    
            if(!$fp = $this->client->connect("0.0.0.0", 9510, 1)) {    
                echo "Error: {$fp->errMsg}[{$fp->errCode}]".PHP_EOL;    
                return;    
            }    
        }    
        public function onConnect() {    
            fwrite(STDOUT, "test RPC (Y or N):");    
            swoole_event_add(STDIN, function() {    
                $msg = trim(fgets(STDIN));    
                if ($msg == 'y') {    
                    $this->send();    
                }    
                fwrite(STDOUT, "test RPC (Y or N):");    
            });    
        }    
        public function onReceive($cli, $data) {    
            echo '[Received]:'.$data;    
        }    
        public function send() {    
            $demo = [    
                'type'  => 'SW',    
                'token' => 'Bb1R3YLipbkTp5p0',    
                'param' => [    
                    'class'  => 'Product',    
                    'method' => 'get',    
                    'param' => [    
                        'code' => 'C4649'    
                    ],    
                ],    
            ];    
            $this->client->send(json_encode($demo));    
        }    
        public function onClose() {    
            echo "Client close connection".PHP_EOL;    
        }    
        public function onError() {    
        }    
    }    
    $client = new Client();    
    $client->connect();

 



client/websocket/index.html

    <!DOCTYPE html>    
    <html>    
    <head>    
        <meta charset="utf-8">    
        <meta http-equiv="X-UA-Compatible" content="IE=edge">    
        <meta name="viewport" content="width=device-width, initial-scale=1">    
        <meta name="description" content="">    
        <meta name="keywords" content="">    
        <title>Demo</title>    
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>    
        <script src="http://echarts.baidu.com/gallery/vendors/echarts/echarts.min.js"></script>    
    </head>    
    <body>    
    <!-- by ECharts Prepare a Dom -->    
    <div id="main" style="width: 900px;height:400px;"></div>    
    <script type="text/javascript">    
        if ("WebSocket" in window) {    
            // Initialize the echarts instance based on the prepared dom    
            var myChart = echarts.init(document.getElementById('main'));    
            var wsServer = 'ws://10.211.55.4:9509';    
            var ws = new WebSocket(wsServer);    
            ws.onopen = function (evt) {    
                if (ws.readyState == 1) {    
                    console.log('WebSocket Successful connection...');    
                } else {    
                    console.log('WebSocket connection failed...');    
                }    
                if (ws.readyState == 1) {    
                    ws.send('Start asking...');    
                } else {    
                    alert('WebSocket connection failed');    
                }    
            };    
            ws.onmessage = function (evt) {    
                console.log('Retrieved data from server: ' + evt.data);    
                var evt_data = jQuery.parseJSON(evt.data);    
                myChart.setOption({    
                    xAxis: {    
                        data : evt_data.time    
                    },    
                    series: [{    
                        data: evt_data.value    
                    }]    
                });    
            };    
            ws.onerror = function (evt) {    
                alert('WebSocket Error occurred');    
                console.log(evt);    
            };    
            ws.onclose = function() {    
                alert('WebSocket Connection closure');    
                console.log('WebSocket Connection closure...');    
            };    
            // Specify configuration items and data for the chart    
            $.ajax({    
                url      : 'http://10.211.55.4:9509 / ', / / request url    
                type     : "post", // Submission mode    
                dataType : "json", // data type    
                data : {    
                    'type'  : 'SW',    
                    'token' : 'Bb1R3YLipbkTp5p0',    
                    'param' : {    
                        'class'  : 'Statistic',    
                        'method' : 'init'    
                    }    
                },    
                beforeSend:function() {    
                },    
                success : function(rs) {    
                    if (rs.code != 1) {    
                        alert('Failed to get data');    
                    } else {    
                        var option = {    
                            title: {    
                                text: 'API Adjusting dosage',    
                                x:'center'    
                            },    
                            tooltip: {    
                                trigger: 'axis',    
                                axisPointer: {    
                                    animation: false    
                                }    
                            },    
                            xAxis: {    
                                type : 'category',    
                                data : rs.data.time    
                            },    
                            yAxis: {    
                                type: 'value',    
                                boundaryGap: [0, '100%'],    
                                name: 'Usage quantity',    
                                splitLine: {    
                                    show: false    
                                }    
                            },    
                            series: [{    
                                name: 'Usage quantity',    
                                type: 'line',    
                                showSymbol: false,    
                                hoverAnimation: false,    
                                data: rs.data.value    
                            }]    
                        };    
                        // Use the configuration items and data you just specified to display the chart.    
                        if (option && typeof option === "object") {    
                            myChart.setOption(option, true);    
                        }    
                    }    
                },    
                error : function(){    
                    alert('Server request exception');    
                }    
            });    
        } else {    
            alert("Your browser does not support WebSocket!");    
        }    
    </script>    
    </body>    
    </html>

 


It also involves OnMessage.php, OnTask.php, OnWorkerStart.php, etc., so there is no code to paste.

Tags: PHP Redis MySQL JQuery

Posted on Wed, 06 Nov 2019 11:50:00 -0500 by maxpagels