php搭建mysql连接池

彭鸿彩
2023-12-01

一直以来,php一直没有mysql连接池的概念,而在开发中大多数框架也是直接使用了长连接的方式。如Thinkphp就是使用的长连接。对于并发较小的项目来说,长连接确实可以提高查询效率,php不用每次去与mysql服务器建立连接,只要某个php-cgi连接过mysql,那么本次访问结束后,php不会释放与mysql的连接。当下次请求过来的时候,php就可以复用之前的连接,从而消除了建立连接是的额外损耗。
举个栗子:
假如有一台mysql服务器MA允许的最大连接数为50。有一台php-fpm服务器PA,PA常驻的php-cgi进程数量设置为100。

  • 当并发量查询访问小于50的时候,php使用长连接不会有问题。
  • 当并发量查询大于50的时候,再使用长连接就会出现mysql连接数量不足。如果有60的并发查询访问,那么就会有10请求无法与mysql建立连接。(这里不考虑mysql设置连接等待队列back_log)
解决上面场景问题的思路如下:
1、增加mysql的最大连接数

这种方法增加的数量有限,当超过某个数量时,查询效率与建立连接的效率都会大大折扣。具体与mysql服务器的硬件配置高低有关。

2、使用缓存技术,让查询不会直接冲击到db;

使用redis、memcached做缓存层,减少与mysql的连接频率

3、使用mysql中间件

mycat(国内开源软件)、SMProxy(一款基于swoole的轻量连接池)

4、使用主从数据库

读写分离。可部署多台slave服务器。服务器数量越多也就意味着你可建立的最大连接越多。

步入正题,搭建SMProxy连接池

必须安装php并且安装swoole扩展并把php添加到环境变量中。

1、下载SMProxy
git clone https://github.com/louislivi/SMProxy.git
# 或者直接下载源码包解压
https://github.com/louislivi/SMProxy/releases/latest
2、修改SMProxy配置

SMProxy conf目录有两个配置文件,一个是database.json,用于配置mysql数据库信息。另一个是server.json用于配置连接池的一些信息

  • database.json
{
  "database": {
   # 设置mysql账户信息
    "account": {
      "master_test": {
        "user": "root",
        "password": "root123456"
      }
    },
    # 设置数据库host、端口等信息
    "serverInfo": {
      "server1": {
        "write": {
          "host": ["172.18.0.4"],
          "port": 3306,
          "timeout": 2,
          "account": "master_test"
        }
      }
    },
    # 设置database的名称
    "databases": {
      "test": {
        "serverInfo": "server1",
        "startConns": "swoole_cpu_num()*2",
        "maxSpareConns": "swoole_cpu_num()*2",
        "maxSpareExp": 3600,
        "maxConns": "swoole_cpu_num()*2",
        "charset": "utf8mb4"
      }
    }
  }
}

  • server.json
{
# 设置代理地址端口、账户密码
  "server": {
    "user": "sm_proxy",
    "password": "123456",
    "charset": "utf8mb4",
    "host": "172.18.0.8",
    "port": "3366",
    "mode": "SWOOLE_PROCESS",
    "sock_type": "SWOOLE_SOCK_TCP",
    "logs": {
      "open":true,
      "config": {
        "system": {
          "log_path": "ROOT/logs",
          "log_file": "system.log",
          "format": "Y/m/d"
        },
        "mysql": {
          "log_path": "ROOT/logs",
          "log_file": "mysql.log",
          "format": "Y/m/d"
        }
      }
    },
    "swoole": {
      "worker_num": "swoole_cpu_num()",
      "max_coro_num": 6000,
      "open_tcp_nodelay": true,
      "daemonize": true,
      "heartbeat_check_interval": 60,
      "heartbeat_idle_time": 600,
      "reload_async": true,
      "log_file": "ROOT/logs/swoole.log",
      "pid_file": "ROOT/logs/pid/server.pid"
    },
    "swoole_client_setting": {
      "package_max_length": 16777215
    },
    "swoole_client_sock_setting": {
      "sock_type": "SWOOLE_SOCK_TCP"
    }
  }
}

3、启动SMProxy
[root@35c65981765f /]# SMProxy start
[root@35c65981765f /]# ps -ef|grep SMProxy
root        12     1  0 06:29 ?        00:00:00 SMProxy master  process
root        14    12  0 06:29 ?        00:00:00 SMProxy manager process
root        28    14  0 06:29 ?        00:00:00 SMProxy worker-0  process
root        46    30  0 06:31 pts/1    00:00:00 grep --color=auto SMProxy
4、框架测试

我这里使用的是thinkphp5进行的测试

  • 修改databse.php的配置为SMProxy的server.json设置的信息
return [
    // 数据库类型
    'type'            => 'mysql',
    // 服务器地址
    'hostname'        => '172.18.0.8',
    // 数据库名
    'database'        => 'test',
    // 用户名
    'username'        => 'sm_proxy',
    // 密码
    'password'        => '123456',
    // 端口
    'hostport'        => '3366',
    // 连接dsn
    'dsn'             => '',
    // 数据库连接参数
    'params'          => [
        \PDO::ATTR_CASE => \PDO::CASE_NATURAL,
        \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
        \PDO::ATTR_ORACLE_NULLS => \PDO::NULL_NATURAL,
        \PDO::ATTR_STRINGIFY_FETCHES => false,
        \PDO::ATTR_EMULATE_PREPARES => true,
    ],
    // 数据库编码默认采用utf8
    'charset'         => 'utf8',
    // 数据库表前缀
    'prefix'          => 'think_',
    // 数据库调试模式
    'debug'           => true,
    // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
    'deploy'          => 0,
    // 数据库读写是否分离 主从式有效
    'rw_separate'     => false,
    // 读写分离后 主服务器数量
    'master_num'      => 1,
    // 指定从服务器序号
    'slave_no'        => '',
    // 自动读取主库数据
    'read_master'     => false,
    // 是否严格检查字段是否存在
    'fields_strict'   => true,
    // 数据集返回类型
    'resultset_type'  => 'array',
    // 自动写入时间戳字段
    'auto_timestamp'  => false,
    // 时间字段取出后的默认时间格式
    'datetime_format' => 'Y-m-d H:i:s',
    // 是否需要进行SQL性能分析
    'sql_explain'     => true,
];
  • 测试查询
<?php
/**
 * +----------------------------------------------------------------------
 * |Created by PhpStorm.
 * +----------------------------------------------------------------------
 * |User: gongxulei <email:790707988@qq.com>
 * +----------------------------------------------------------------------
 * |Date: 2020/6/6
 * +----------------------------------------------------------------------
 * |Time: 5:43 下午
 * +----------------------------------------------------------------------
 */

namespace app\index\controller;

use think\Controller;
use think\Db;

class Test extends Controller
{
   
    /**
     * SMProxy查询测试
     * @access public
     * @param mixed $field 字段描述
     * @return mixed
     **/
    public function smProxyAction()
    {
        $res = Db::table('lock1')->field('*')->select();
        return json($res);
    }

}

查询结果如下:

[
    {
        "id": "1",
        "name": "1",
        "create_time": null
    },
    {
        "id": "2",
        "name": "cc",
        "create_time": null
    },
    {
        "id": "3",
        "name": "cc",
        "create_time": null
    },
    {
        "id": "4",
        "name": "cc",
        "create_time": null
    }
]

官方文档地址如下:
https://smproxy.gitee.louislivi.com/#/README

 类似资料: