Swoole Redis 连接池的实现

这篇文章仅仅只实现一个 Redis 连接池,篇幅就太少了,顺便将前几篇整合一下。

Demo 中大概包含这些点:

    实现 MySQL 连接池

    实现 MySQL CURD 方法的定义

    实现 Redis 连接池

    实现 Redis 方法的定义

    满足 HTTP、TCP、WebSocket 调用

    提供 Demo 供测试

    调整 目录结构

HTTP 调用:

    实现 读取 MySQL 中数据的 Demo

    实现 读取 Redis 中数据的 Demo

640?wx_fmt=png

TCP 调用:

    实现 读取 MySQL 中数据的 Demo

    实现 读取 Redis 中数据的 Demo



WebSocket 调用:

    实现 每秒展示 API 调用量 Demo

目录结构

    ├─ client    
    │  ├─ http    
    │     ├── mysql.php //测试 MySQL 连接    
    │     ├── redis.php //测试 Redis 连接    
    │  ├─ tcp    
    │     ├── mysql.php //测试 MySQL 连接    
    │     ├── redis.php //测试 Redis 连接    
    │  ├─ websocket    
    │     ├── index.html //实现 API 调用量展示    
    ├─ controller    
    │  ├─ Order.php     //实现 MySQL CURD    
    │  ├─ Product.php   //实现 Redis 调用    
    │  ├─ Statistic.php //模拟 API 调用数据    
    ├─ server    
    │  ├─ config    
    │     ├── config.php //默认配置    
    │     ├── mysql.php  //MySQL 配置    
    │     ├── redis.php  //Redis 配置    
    │  ├─ core    
    │     ├── Common.php //公共方法    
    │     ├── Core.php   //核心文件    
    │     ├── HandlerException.php //异常处理    
    │     ├── callback //回调处理    
    │         ├── OnRequest.php    
    │         ├── OnReceive.php    
    │         ├── OnTask.php    
    │         ├── ...    
    │     ├── mysql    
    │         ├── MysqlDB.php    
    │         ├── MysqlPool.php    
    │     ├── redis    
    │         ├── RedisDB.php    
    │         ├── RedisPool.php    
    │  ├─ log  -- 需要 读/写 权限    
    │     ├── ...    
    ├─ index.php //入口文件

代码

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) { //释放    
                    $this->pool->push($redis);    
                });    
                return $redis;    
            } else {    
                throw new RuntimeException("Pool length <= 0");    
            }    
        }    
    }

 

这里我还准备了一分学习图和资料,如下:

链接:https://pan.baidu.com/s/1v5gm7n0L7TGyejCmQrMh2g 提取码:x2p5

免费分享,但是X度限制严重,如若链接失效点击链接或搜索加群 群号518475424



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)    
        {    
            // TODO 主库的操作    
            $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)    
        {    
            //主库    
            $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 = 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' => '订单-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, "测试RPC (Y or N):");    
            swoole_event_add(STDIN, function() {    
                $msg = trim(fgets(STDIN));    
                if ($msg == 'y') {    
                    $this->send();    
                }    
                fwrite(STDOUT, "测试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>    
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->    
    <div id="main" style="width: 900px;height:400px;"></div>    
    <script type="text/javascript">    
        if ("WebSocket" in window) {    
            // 基于准备好的dom,初始化echarts实例    
            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 连接成功...');    
                } else {    
                    console.log('WebSocket 连接失败...');    
                }    
                if (ws.readyState == 1) {    
                    ws.send('开始请求...');    
                } else {    
                    alert('WebSocket 连接失败');    
                }    
            };    
            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 发生错误');    
                console.log(evt);    
            };    
            ws.onclose = function() {    
                alert('WebSocket 连接关闭');    
                console.log('WebSocket 连接关闭...');    
            };    
            // 指定图表的配置项和数据    
            $.ajax({    
                url      : 'http://10.211.55.4:9509/', // 请求url    
                type     : "post", // 提交方式    
                dataType : "json", // 数据类型    
                data : {    
                    'type'  : 'SW',    
                    'token' : 'Bb1R3YLipbkTp5p0',    
                    'param' : {    
                        'class'  : 'Statistic',    
                        'method' : 'init'    
                    }    
                },    
                beforeSend:function() {    
                },    
                success : function(rs) {    
                    if (rs.code != 1) {    
                        alert('获取数据失败');    
                    } else {    
                        var option = {    
                            title: {    
                                text: 'API 调用量',    
                                x:'center'    
                            },    
                            tooltip: {    
                                trigger: 'axis',    
                                axisPointer: {    
                                    animation: false    
                                }    
                            },    
                            xAxis: {    
                                type : 'category',    
                                data : rs.data.time    
                            },    
                            yAxis: {    
                                type: 'value',    
                                boundaryGap: [0, '100%'],    
                                name: '使用量',    
                                splitLine: {    
                                    show: false    
                                }    
                            },    
                            series: [{    
                                name: '使用量',    
                                type: 'line',    
                                showSymbol: false,    
                                hoverAnimation: false,    
                                data: rs.data.value    
                            }]    
                        };    
                        // 使用刚指定的配置项和数据显示图表。    
                        if (option && typeof option === "object") {    
                            myChart.setOption(option, true);    
                        }    
                    }    
                },    
                error : function(){    
                    alert('服务器请求异常');    
                }    
            });    
        } else {    
            alert("您的浏览器不支持 WebSocket!");    
        }    
    </script>    
    </body>    
    </html>

 


还涉及到,OnMessage.php、OnTask.php 、OnWorkerStart.php 等,就不贴代码了。

posted @ 2019-11-06 22:24  it-world  阅读(919)  评论(0编辑  收藏  举报