在性能调优过程中,通过监控数据经常发现接口花费大量时间在获取数据库连接中,那如何通过优化数据库连接池的配置来优化服务的性能呢?

什么是数据库连接池

创建数据库连接是一个很耗时的操作,也容易对数据库造成安全隐患。所以,在程序初始化的时候,集中创建多个数据库连接,并把他们集中管理,供程序使用,可以保证较快的数据库读写速度,还更加安全可靠

官方解释:
数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。

为什么需要连接池

任何数据库的访问都需要首先建立数据库连接。这是一个复杂、缓慢的处理。牵涉到通信建立(包括 TCP 的三次握手)、认证、授权、资源的初始化和分配等一系列任务
在应用启动时预先建立一些数据库连接,应用程序使用已有的连接可以极大提高响应速度。另外,Web 服务应用当客户很多时,有很多线程,连接数目过多以及频繁创建/删除连接也会影响数据库的性能

连接池带来的好处:

  • 节省了创建数据库连接的时间,通常这个时间大大超过处理数据访问请求的时间
  • 统一管理数据库请求连接,避免了过多连接或频繁创建/删除连接带来的性能问题
  • 监控数据库连接的运行状态和错误报告,减少应用服务的这部分代码

实现原理

在应用开始时创建一组数据库的连接,也可以动态创建但是复用已有的连接。这些连接被存储到一个共享的资源数据结构,称为连接池(典型的生产者-消费者并发模型)

连接逻辑
每个线程在需要访问数据库时借用(borrow)一个连接,使用完成则释放(release)连接回到连接池供其他线程使用
比较好的线程池构件会有二个参数动态控制线程池的大小:最小数量和最大数量

最小数量指即使负载很轻,也保持一个最小数目的数据库连接以备不时之需
当同时访问数据库的线程数超过最小数量时,则动态创建更多连接。最大数量则是允许的最大数据库连接数量,当最大数目的连接都在使用而有新的线程需要访问数据库时,则新的线程会被阻塞直到有连接被释放回连接池
当负载变低,池里的连接数目超过最小数目而只有低于或等于最小数目的连接被使用时,超过最小数目的连接会被关闭和删除以便节省系统资源。

连接泄露
连接池的实际应用中,最担心的问题就是借了不还的这种让其他人无资源可用的人品问题
编码逻辑错误或者释放连接放代码没有放到 finally 部分都会导致连接池资源枯竭从而造成系统变慢甚至完全阻塞的情况。类似于内存泄露,因而也叫连接泄露

连接池系统架构

连接池只是给业务应用提供已建立的连接,所有的访问请求都通过连接转发到后台数据库服务器

具体来说,连接池是两个线程池的中间通道。可以看成下面的结构:

hyperf mysql连接池 mysql 连接池设置_数据库连接


上图中,连接池和应用服务线线程池在同一个进程里面。每个访问数据库的应用服务进程都有自己的线程池和对应的数据库连接池。数据库服务器可能需要处理来自一个或多个服务器的多个应用服务进程内的数据库连接池数据访问请求

连接池的运行机制

  1. 程序初始化时创建连接池
  2. 使用时向连接池申请可用连接
  3. 使用完毕,将连接返还给连接池
  4. 程序退出时,断开所有连接,并释放资源

配置考虑因素

  • 当前连接DB的规模
  • 并发情况
  • 执行db的响应时间

做为应用服务和数据库的桥梁,连接池参数配置的目标是全局优化。具体的优化目的有四个:

  1. 尽可能满足应用服务的并发数据库访问
  2. 不让数据库服务器过载
  3. 能发现用了不还造成的死锁
  4. 不浪费系统资源

不浪费系统资源是指配置过大的连接池会浪费应用服务器的系统资源,包括内存,网络端口,同步信号等。同时线程池的重启和操作都会响应变慢。不过应用端连接池的开销不是很大,资源的浪费通常不是太大问题

配置参数解读

  1. 初始化连接:可考虑设置为3个连接 。对于db规模特别大的情况下可考虑设置为1个。避免启动时间过长
  2. 最小连接:可考虑该值的设置和初始化连接保持一致
  3. 最大连接:对于有较大DB规模,最大连接不要设置过大,避免本地维护的db太大。如果对应到数据源的并发数过高,可考虑增大最大连接数
  4. 获取连接的超时时间:如果连接全部被占用,需要等待的时间。可以根据当前系统的响应时间判定,如果容忍度较高,可以大点。容忍度较低,设置小点
  5. 获取连接和释放连接心跳检测:建议全部关闭,否则每个数据库访问指令会对数据库生产额外的两条心跳检测的指令,增加数据库的负载。连接有效性的检查改用后台空闲连接检查
  6. 连接有效性检测时间:该值需要结合数据库的wait_timeout,interactive_timeout值进行设置。假如数据库为120s,则心跳检测时间在120s以内越大越好。如果太小,心跳检测时间会比较频繁。建议设置为90s
  7. 最大空闲时间:如果连接超过该时间没有使用过,则会进行close掉。 该值不要太小,避免频繁的建立连接关闭连接。也不要太大,导致一直无法关闭
  8. 心跳检查的sql语句:尽量使用ping命令,ping的性能较查询语句高。大部分的数据库连接池不配置query语句,便会调用ping命令。
  9. prepareStatement缓存:可以根据自己的业务来判定是否开启。开启后对性能的影响依赖于具体业务和并发情况。可考虑暂时不开启
  10. 连接使用超时:业务拿到一个连接,如果超过指定的时间未归还,是否把该连接给给回收掉。超时时间等和具体的业务关联。暂时建议先不开启

如何配置数据库连接池

druid配置

介绍:https://github.com/alibaba/druid

hyperf mysql连接池 mysql 连接池设置_hyperf mysql连接池_02


配置说明:

  1. minEvictableIdleTimeMillis(最大空闲时间):默认为30分钟,配置里面不进行设置
  2. testOnBorrow ,testOnReturn 默认为关闭,可以设置为不配置
  3. testWhileIdle(在获取连接后,确定是否要进行连接空闲时间的检查)。默认为true。配置里面不再进行设置

流程说明:

  1. 在第一次调用connection的时候,才会进行 initialSize的初始化
  2. 心跳检测时间线程,会休眠timeBetweenEvictionRunsMillis时间,然后只对(没有borrow的线程 减去 minIdle)的线程进行检查,如果空闲时间大于minEvictableIdleTimeMillis则进行close
  3. testWhileIdle必须设置为true,在获取到连接后,先检查testOnBorrow,然后再判定testwhileIdle,如果连接空闲时间大于timeBetweenEvictionRunsMillis,则会进行心跳检测
  4. 不需要配置validationQuery,如果不配置的情况下会走ping命令,性能更高
  5. 连接保存在数组里面,获取连接的时候,获取数组的最后一位。在timeBetweenEvictionRunsMillis时是从前往后进行检查连接的有效性