什么是数据库连接池?
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
数据库连接池有什么好处?
数据库连接池技术带来的优势:
1. 资源重用
由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。
2. 更快的系统响应速度
数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
3. 新的资源分配手段
对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术,几年钱也许还是个新鲜话题,对于目前的业务系统而言,如果设计中还没有考虑到连接池的应用,那么…….快在设计文档中加上这部分的内容吧。某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。
4. 统一的连接管理,避免数据库连接泄漏
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。一个最小化的数据库连接池实现:
在其它语言的开发当中如java等都有数据库连接池的解决方案,那么在php中怎么去实现数据库连接池呢。
其实很简单,我们需要一个中间件去连接数据库,而不是通过php内置扩展连接数据库。
阿里云RDS 或是 PolarDB Mysql
如果你的项目已经上线,不易调整数据库的连接方式和对数据库数据的管理方式,我建议你用阿里云RDS服务来使用数据库链接池,因为RDS本身就是一个中间件。
原理结构示意图
我们是通过RDS中间件去实现的连接池管理
RDS 原理结构示意图
看到了吧,RDS本身来为我们缓冲数据库连接池。而我们平时使用短连接连接RDS服务就可以了,甚至连接RDS服务的方式和平时我们连接本地数据库的方式都是一样的,如mysql_connect new PDO() 这些扩展都能连接和直接使用RDS服务。我们只需要将我们的数据库迁移到RDS下面就可以了。
如果你的项目没有使用RDS服务,或者是因某些原因不能使用RDS,那么你可以在本地服务器上安装一个php 扩展,让这个扩展来帮助你实现数据库连接池的功能。
php + SQL Relay + mysql
其中 SQL Relay 就是数据库中间件,我们通过连接中间件来管理数据库。原理RDS原理 让SQL Relay 来管理数据库连接池。
php swoole 实现数据库连接池(SMProxy)
与阿里云提供的短链接优化服务类似,也是 一个中间来对外提供服务,但本身内部是采用数据库连接池来进行sql处理。
SMProxy文档地址
原理
将数据库连接作为对象存储在内存中,当用户需要访问数据库时,首次会建立连接,后面并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。 使用完毕后,用户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。而连接的建立、断开都由连接池自身来管理。
同时,还可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大空闲时间等等。 也可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。超出最大连接数会采用协程挂起,等到有连接关闭再恢复协程继续操作。
特性
支持读写分离
支持数据库连接池,能够有效解决 PHP 带来的数据库连接瓶颈
支持 SQL92 标准
采用协程调度
支持多个数据库连接,多个数据库,多个用户,灵活搭配
遵守 MySQL 原生协议,跨语言,跨平台的通用中间件代理
支持 MySQL 事务
支持 HandshakeV10 协议版本
完美兼容 MySQL5.5 - 8.0
兼容各大框架,无缝提升性能
使用
1、将项目拷贝至本地
git clone https://github.com/louislivi/SMProxy.git
2、设置配置参数
配置文件位于 smproxy/conf 目录中,其中大写 ROOT 代表当前 SMProxy 根目录。
database.json
{
"database": {
"account": {
"自定义用户名": {
"user": "必选,数据库账户",
"password": "必选,数据库密码"
},
"...": "必选1个,自定义用户名 与serverInfo中的account相对应"
},
"serverInfo": {
"自定义数据库连接信息": {
"write": {
"host": "必选,写库地址 多个用[]表示",
"port": "必选,写库端口",
"timeout": "必选,写库连接超时时间(秒)",
"account": "必选,自定义用户名 与 account中的自定义用户名相对应",
"maxConns": "重载,对应databases",
"maxSpareConns": "重载,对应databases",
"startConns": "重载,对应databases",
"maxSpareExp": "重载,对应databases"
},
"read": {
"host": "可选,读库地址 多个用[]表示",
"port": "可选,读库端口",
"timeout": "可选,读库连接超时时间(秒)",
"account": "可选,自定义用户名 与 account中的自定义用户名相对应",
"maxConns": "重载,对应databases",
"maxSpareConns": "重载,对应databases",
"startConns": "重载,对应databases",
"maxSpareExp": "重载,对应databases"
}
},
"...": "必选1个,自定义数据库连接信息 与databases中的serverInfo相对应,read读库可不配置"
},
"databases": {
"数据库别名": {
"databaseName": "可选,指定真实链接数据库名称(默认不指定与别名相同)",
"serverInfo": "必选,自定义数据库连接信息 与serverInfo中的自定义数据库连接信息相对应",
"maxConns": "必选,该库服务最大连接数,支持计算",
"maxSpareConns": "必选,该库服务最大空闲连接数,支持计算",
"startConns": "可选,该库服务默认启动连接数,支持计算",
"maxSpareExp": "可选,该库服务空闲连接数最大空闲时间(秒),默认为0,支持计算",
"charset": "可选,该库编码格式"
},
"...": "必选1个,数据库名称 多个数据库配置多个"
}
}
}
参数名称 | 描述 |
---|---|
maxSpareExp | 活动连接的最大空闲时间,单位为秒 超过此时间的连接会被释放到连接池中,针对未被关闭的活动连接。 |
maxSpareConns | 连接池中最多可空闲maxConns个连接 ,这里取值为20,表示即使没有数据库连接时依然可以保持20空闲的连接,而不被清除,随时处于待命状态。 |
maxConns | 连接池支持的最大连接数,这里取值为20,表示同时最多有20个数据库连接。一般把maxConns设置成可能的并发量就行了。 |
startConns | 初始化连接数目,服务启动时生成连接数。 |
server.json
{
"server": {
"user": "必选,SMProxy服务用户",
"password": "必选,SMProxy服务密码",
"charset": "可选,SMProxy编码,默认utf8mb4",
"host": "可选,SMProxy地址,默认0.0.0.0",
"port": "可选,SMProxy端口,默认3366 如需多个以`,`隔开",
"mode": "可选,SMProxy运行模式,SWOOLE_PROCESS多进程模式(默认),SWOOLE_BASE基本模式",
"sock_type": "可选,sock类型,SWOOLE_SOCK_TCP tcp",
"logs": {
"open":"必选,日志开关,true 开 false 关",
"config": {
"system": {
"log_path": "必选,SMProxy系统日志目录",
"log_file": "必选,SMProxy系统日志文件名",
"format": "必选,SMProxy系统日志目录日期格式"
},
"mysql": {
"log_path": "必选,SMProxyMySQL日志目录",
"log_file": "必选,SMProxyMySQL日志文件名",
"format": "必选,SMProxyMySQL日志目录日期格式"
}
}
},
"swoole": {
"worker_num": "必选,SWOOLE worker进程数,支持计算",
"max_coro_num": "必选,SWOOLE 协程数,推荐不低于3000",
"pid_file": "必选,worker进程和manager进程pid目录",
"open_tcp_nodelay": "可选,关闭Nagle合并算法",
"daemonize": "可选,守护进程化,true 为守护进程 false 关闭守护进程",
"heartbeat_check_interval": "可选,心跳检测",
"heartbeat_idle_time": "可选,心跳检测最大空闲时间",
"reload_async": "可选,异步重启,true 开启异步重启 false 关闭异步重启",
"log_file": "可选,SWOOLE日志目录"
},
"swoole_client_setting": {
"package_max_length": "可选,SWOOLE Client 最大包长,默认16777216MySQL最大支持包长"
},
"swoole_client_sock_setting": {
"sock_type": "可选,SWOOLE Client sock 类型,默认tcp 仅支持tcp"
}
}
}
Laravel .env
DB_CONNECTION=mysql
DB_HOST=server.json中配置的host
DB_PORT=server.json中配置的port
DB_DATABASE=databse.json中配置的数据库名称
DB_USERNAME=server.json中配置的user
DB_PASSWORD=server.json中配置的password
运行
需要给予 bin/SMProxy 执行权限。
SMProxy [ start | stop | restart | status | reload ] [ -c | --config <configuration_path> | --console | -f | --force ]
SMProxy -h | --help
SMProxy -v | --version