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.