Swoole Redis 连接池的实现

概述

这是关于 Swoole 入门学习的第九篇文章:Swoole Redis 连接池的实现。

  • 第八篇:Swoole MySQL 连接池的实现
  • 第七篇:Swoole RPC 的实现
  • 第六篇:Swoole 整合成一个小框架
  • 第五篇:Swoole 多协议 多端口 的应用
  • 第四篇:Swoole HTTP 的应用
  • 第三篇:Swoole WebSocket 的应用
  • 第二篇:Swoole Task 的应用
  • 第一篇:Swoole Timer 的应用

收到读者反馈,“亮哥,文章能多点图片吗?就是将运行结果以图片的形式展示...”

我个人觉得这是比较懒、动手能力差的表现,恩... 要勤快些。

但谁让文章是写给你们看的那,我以后尽量文章写的图文并茂一点。

上篇文章 分享了 MySQL 连接池,这篇文章 咱们来分享下 Redis 连接池。

在上篇文章的基础上进行简单调整即可,将实例化 MySQL 的地方,修改成实例化 Redis 即可,还要注意一些方法的调整。

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

大概 Demo 中包含这些点:

  • 实现 MySQL 连接池
  • 实现 MySQL CURD 方法的定义
  • 实现 Redis 连接池
  • 实现 Redis 方法的定义
  • 满足 HTTP、TCP、WebSocket 调用
  • 提供 Demo 供测试
  • 调整 目录结构

HTTP 调用:

  • 实现 读取 MySQL 中数据的 Demo
  • 实现 读取 Redis 中数据的 Demo

Swoole Redis 连接池的实现_第1张图片

TCP 调用:

  • 实现 读取 MySQL 中数据的 Demo
  • 实现 读取 Redis 中数据的 Demo

WebSocket 调用:

  • 实现 每秒展示 API 调用量 Demo

Swoole Redis 连接池的实现_第2张图片

目录结构

├─ 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

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");
        }
    }
}

server/core/redis/RedisDB.php

_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

 '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

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




    
    
    
    
    
    Demo
    
    



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

运行

小框架的启动/关闭/热加载,看看这篇文章: 第六篇:Swoole 整合成一个小框架

里面 Demo 在 client 文件夹下。

http 目录下的文件,放到自己虚拟目录下,用浏览器访问。

tcp 目录下的文件,在 CLI 下运行。

websocket 目录下的文件,直接点击在浏览器访问。

扩展

官方协程 Redis 客户端手册:

https://wiki.swoole.com/wiki/page/589.html

大家可以尝试使用官方提供的其他方法。

小结

Demo 代码仅供参考,里面有很多不严谨的地方,根据自己的需要进行修改 ...

上面的 Demo 需要源码的,加我微信。(菜单-> 加我微信-> 扫我)

本文欢迎转发,转发请注明作者和出处,谢谢!

你可能感兴趣的:(Swoole Redis 连接池的实现)