Swoole Redis 連接池的實現

来源:https://www.cnblogs.com/it-3327/archive/2019/11/06/11809147.html
-Advertisement-
Play Games

這篇文章僅僅只實現一個 Redis 連接池,篇幅就太少了,順便將前幾篇整合一下。Demo 中大概包含這些點: 實現 MySQL 連接池 實現 MySQL CURD 方法的定義 實現 Redis 連接池 實現 Redis 方法的定義 滿足 HTTP、TCP、WebSocket 調用 提供 Demo 供 ...


這篇文章僅僅只實現一個 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 等,就不貼代碼了。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Docker中我們一般會有兩種執行命令的方式,一種是直接進入容器的命令行,在終端執行並查看結果,一種是在後臺執行,並不會在終端查看結果。 1、進入容器命令行 su root docker run -i -t ubuntu:16.04 /bin/bash #或者執行下麵這句 docker run -i ...
  • 要運行maven,必須要有 JDK ,maven 是由 Java 語言編寫的 一、JDK 的安裝 "ORACLE 官網下載 " "JDK jdk 8u231 linux x64.tar.gz " 上傳 JDK 至 linux 伺服器 創建文件夾 使用 xftp 工具上傳壓縮文件 連接 Linux 服 ...
  • 在MySLQ中 UPDATA 和 INSERT 數據的時候,如果數據上面帶有emoji圖標,例如:?、?、? 很容易更新或者插入不成功,導致報錯。 1 2 Error: ER_TRUNCATED_WRONG_VALUE_FOR_FIELD: Incorrect string value: '\xF0 ...
  • 1. 初識文件操作 使⽤python來讀寫⽂件是非常簡單的操作。我們使⽤open()函數來打開⼀個⽂件,獲取到⽂ 件句柄,然後通過⽂件句柄就可以進⾏各種各樣的操作了,根據打開⽅式的不同能夠執⾏的操 作也會有相應的差異。 打開⽂件的⽅式: r, w, a, r+, w+, a+, rb, wb, ab ...
  • python學習之路-01 x = 1+2+3+4 print(x) print(x*5) y = x*5 print(y+100-45+2) print('泰哥泰哥,我是小弟') print('泰哥泰哥,我是三弟小妹') t-t = 2 3t_t = 23 *r = 4 _ = 'fdsa' __ ...
  • 這篇文章主要介紹了關於如何使用swoole加速laravel,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下 再來複習一下吧,導致 php 慢的各種因素中解析性語言的特性可以說是罪魁禍首,再加上,每次請求完都釋放請求時所載入的全部文件,因此也就顯得更慢了。 後來我們有了 opcache ...
  • 本篇文章給大家帶來的內容是關於php為什麼需要非同步編程?php非同步編程的詳解(附示例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。 我對 php 非同步的知識還比較混亂,寫這篇是為了整理,可能有錯。 傳統的 php-fpm 一個進程執行一個請求,要達到多少併發,就要生成多少個進程。 ...
  • 最近兩個月一直在研究 Swoole,那麼藉助這篇文章,我希望能夠把 Swoole 安利給更多人。雖然 Swoole 可能目前定位是一些高級 phper 的玩具,讓中低級望而生畏,可能對一些應用場景也一臉懵逼,但其實沒這麼難的。 在 Swoole 官網的自我介紹是“面向生產環境的 PHP 非同步網路通信 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...