HikariCP连接池

HikariCP连接池是高性能的JDBC连接池,官网标注的三大特点:快速、简单、可靠,性能优于其他连接池。

官网详细地说明了HikariCP所做的一些优化,总结如下:

  • 字节码精简:优化代码,直到编译后的字节码最少(展平继承层次结构,掩饰成员变量,消除强制类型转换),这样,CPU缓存可以加载更多的程序代码;
  • 优化代理和拦截器:减少代码,例如HikariCP的Statement proxy只有100行代码,只有BoneCP的十分之一;
  • 自定义数组类型(FastStatementList)代替ArrayList:避免每次get()调用都要进行range check,避免调用remove()时的从头到尾的扫描;
  • 自定义无锁集合类型(ConcurrentBag):提高并发读写的效率;

HikariCP的使用

由于SpringBoot2默认集成HikariCP,因此需要再引入依赖。主要是项目mysql和springboot mybatis的依赖。

Yaml配置

# 配置数据源信息
spring:
  datasource:                                           # 数据源的相关配置
    type: com.zaxxer.hikari.HikariDataSource          # 数据源类型:HikariCP
    driver-class-name: com.mysql.jdbc.Driver          # mysql驱动
    url: jdbc:mysql://localhost:3306/foodie-dev?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
    username: root
    password: 123456
    hikari:
      connection-timeout: 30000        # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 默认:30秒
      minimum-idle: 5                  # 最小连接数
      maximum-pool-size: 20            # 最大连接数
      auto-commit: true                # 事务自动提交
      idle-timeout: 600000             # 连接超时的最大时长(毫秒),超时则被释放(retired),默认:10分钟
      pool-name: DateSourceHikariCP     # 连接池名字
      max-lifetime: 1800000             # 连接的生命时长(毫秒),超时而且没被使用则被释放(retired),默认:30分钟 1800000ms
      connection-test-query: SELECT 1  # 连接测试语句

# mybatis配置
mybatis:
  type-aliases-package: com.lzp.pojo          # 所有POJO类所在包路径
  mapper-locations: classpath:mapper/*.xml      # mapper映射文件

连接池连接数的设置

引入数据库连接池

数据库连接是有限的、昂贵的资源,一个数据库连接对象对应一个物理数据库的连接,如果每次数据库操作都创建新的连接,使用完后释放,会导致系统性能低下,这就引出了连接池的概念。

数据库连接池是负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,可以视作一个存放数据库连接的容器。

数据库连接池采用了资源池设计模式,用于资源共享,避免资源的频繁分配与释放问题。同时便于统一管理,可以通过对连接池的控制,限制系统与数据库的连接,监视数据库的连接数量和使用情况。

连接池的必要性

1、不使用连接池流程

下面以访问MySQL为例,执行一个SQL命令,如果不使用连接池,需要经过哪些流程。

不使用数据库连接池的步骤:

  1. TCP建立连接的三次握手
  2. MySQL认证的三次握手
  3. 真正的SQL执行
  4. MySQL的关闭
  5. TCP的四次握手关闭

可以看到,为了执行一条SQL,却多了非常多网络交互。
优点:实现简单
缺点:

  • 网络IO较多
  • 数据库的负载较高
  • 响应时间较长及QPS较低
  • 应用频繁的创建连接和关闭连接,导致临时对象较多,GC频繁
  • 在关闭连接后,会出现大量TIME_WAIT 的TCP状态(在2个MSL之后关闭)
2、使用连接池流程

使用数据库连接池的步骤:

第一次访问的时候,需要建立连接。 但是之后的访问,均会复用之前创建的连接,直接执行SQL语句。
优点:

  • 较少了网络开销
  • 系统的性能会有一个实质的提升
  • 没了麻烦的TIME_WAIT状态

数据库连接数设置

系统可采取设置最小连接数和最大连接数等参数来控制连接池中的连接。最小连接数是系统启动时创建的数据库连接数。最小连接数小,则启动快,响应慢。通常设置较大一些。最小连接数可以设置为5个-10个。最大连接数根据硬件配置设置,4核心机器可以设为10个,8核心可以设为20个。

HikariCP的默认的最大和最小连接数是10。作者建议是设置最大和最小连接数为相同的值,维护一个高性能连接池。

为什么连接池数并不是越大越好?

第一点,首先我们要知道单核CPU“同时”运行多个线程,只不过是假象。单核CPU同一时刻只能执行一个线程,然后操作系统切换上下文,CPU 核心快速调度,执行另一个线程的代码。这其中便涉及到了大量上下文切换带来的额外性能损耗。

第二点,由上可知,一个N核心服务器,设置数据库连接数为N便能提供最优性能。然而,实际情况会受到磁盘IO和网络IO的影响,在IO等待时间内,线程阻塞等待,CPU处于空闲状态。因此,在线程处理I/O密集业务操作时,需要设置线程/连接数比CPU大一些,以提高吞吐量。

连接数的计算公式

连接数 = ((核心数 * 2) + 有效磁盘数)

服务器 CPU 是 4核 i7 的,连接池大小应该为 ((4 * 2) + 1) = 9 ~ 10个。具体需要根据实际业务场景做调整。

业务场景

  • 对于并发访问,可以采用小的数据库连接池,然后将剩下的业务线程放在队列中等待。
  • 如果系统中混合了长事务和短事务,正确的做法应该是创建两个连接池,一个服务于长事务,一个服务于"实时"查询,也就是短事务。

参考文档

  1. https://www.jianshu.com/p/15b846107a7c