layout: posttitle: Swoole 极简版MySQL连接池
subtitle: Swoole 极简版MySQL连接池
date: 2019-04-20
author: he xiaodong
header-img: img/default-post-bg.jpg
catalog: true
tags:
- Swoole
- MySQL连接池

额外注意:MySQL 连接池只能减轻业务连接数据库时候的操作,他允许同一个连接多次被使用,而不是每次重新创建连接。需要额外注意的最小连接数和最大连接数,
最小连接数意味着一直需要维护的资源,如果不需要这么多连接,将造成资源浪费。而最大连接数则是超出这个数量,后面的连接请求将需要等待,也会有一些影响。最大连接数也受 max_connections 配置数量的制约。

mysqlPool.php

  1. <?php
  2. use Swoole\Runtime;
  3. Runtime::enableCoroutine(true);
  4. class MysqlPool
  5. {
  6. protected $min;
  7. protected $max;
  8. protected $queue;
  9. protected $config = [
  10. 'host' => '127.0.0.1',
  11. 'port' => 3306,
  12. 'username' => 'root',
  13. 'password' => 'root',
  14. 'db' => 'business',
  15. 'charset' => 'utf8'
  16. ];
  17. public function __construct($min = 10, $max = 100)
  18. {
  19. $this->min = $min;
  20. $this->max = $max;
  21. $this->queue = new SplQueue();
  22. }
  23. /**
  24. * 初始化
  25. */
  26. public function init()
  27. {
  28. for ($i = 0; $i < $this->min; $i++) {
  29. $this->generate();
  30. }
  31. }
  32. /**
  33. * 生成连接
  34. */
  35. public function generate()
  36. {
  37. $swooleMysql = new Swoole\Coroutine\MySQL();
  38. $swooleMysql->connect([
  39. 'host' => $this->config['host'],
  40. 'port' => $this->config['port'],
  41. 'user' => $this->config['username'],
  42. 'password' => $this->config['password'],
  43. 'database' => $this->config['db'],
  44. 'charset' => $this->config['charset']
  45. ]);
  46. $this->queue->push($swooleMysql);
  47. }
  48. /**
  49. * @param integer $timeout
  50. * 获取连接
  51. */
  52. public function getConnection($timeout = 10)
  53. {
  54. $time = time();
  55. while ($time + $timeout > time()) {
  56. try {
  57. $connection = $this->queue->pop();
  58. break;
  59. } catch (Exception $e) {
  60. sleep(1);
  61. }
  62. }
  63. return $connection;
  64. }
  65. /**
  66. * @param string $connection
  67. * 释放连接
  68. */
  69. public function free($connection)
  70. {
  71. $this->queue->push($connection);
  72. }
  73. /**
  74. * 维持当前的连接数不断线,并且剔除断线的链接 .
  75. */
  76. public function keepAlive()
  77. {
  78. swoole_timer_tick(2000, function() {
  79. while ($this->queue->count() > 0 && $next = $this->queue->shift()) {
  80. $next->query("select 1" , function($db, $res){
  81. if ($res === false) {
  82. return;
  83. }
  84. echo "当前连接数:" . $this->queue->count() . PHP_EOL;
  85. $this->queue->push($db);
  86. });
  87. }
  88. });
  89. swoole_timer_tick(2000 , function() {
  90. if($this->queue->count() > $this->max) {
  91. while($this->max < $this->queue->count()) {
  92. $next = $this->queue->shift();
  93. $next->close();
  94. echo "关闭连接..." . PHP_EOL;
  95. }
  96. }
  97. });
  98. }
  99. }
  100. // 测试部分
  101. go(function () {
  102. $pool = new MysqlPool();
  103. $pool->init();
  104. $num = 200;
  105. while ($num-- > 0) {
  106. go(function () use ($pool) {
  107. $conn = $pool->getConnection();
  108. if (!$conn) {
  109. echo "get conn error.\n";
  110. return;
  111. }
  112. $statement = $conn->prepare('select * from users where id = ?');
  113. $id = mt_rand(0, 10);
  114. $result = $statement->execute([$id]);
  115. var_dump($result);
  116. $pool->free($conn);
  117. });
  118. }
  119. });

取消注释的测试部分代码,然后执行 php mysqlPool.php 进行测试,连接池默认的最大连接是 100,测试中是 200 个连接,超出部分将有一个等待过程,为了方便查看数据,可以将这两个数字都调小。

keepAlive 方法可以在 workerStart 事件中调用,直接利用 swoole 的定时器特性轮训,维护连接池状态。

© 原创文章

其他参考:

  1. 韩天峰 MySQL连接池
  2. Swoole MySQL连接池文档

最后恰饭 阿里云全系列产品/短信包特惠购买 中小企业上云最佳选择 阿里云内部优惠券