CloudNativeEra
  • Introduction
  • 名词解释
  • Computer Science
    • Computer Organization
      • CPU
      • 二进制、电路、加法器、乘法器
      • 编译、链接、装载
      • 存储器
      • IO
    • Operating System
      • 操作系统基础知识
      • 系统初始化
      • 进程管理
      • Everything about Memory
      • 文件系统
      • 并行编程
      • Linux
        • CPU
        • IO 多路复用
        • DMA IO and Linux Zero Copy
    • Computer Network
      • 网络相关命令
      • 评估系统的网络性能
      • 网络抓包
      • Linux 最多支撑的 TCP 连接
      • 网络虚拟化
      • DHCP 工作原理
    • Data Structure and Algorithm
      • 题目列表
      • Summarize
        • 方法总结
        • 二分思想
        • 树的演化
        • 算法思想总结
      • Data Structure
        • Data Struct - Array
        • Tree
        • Heap
        • Hash
        • 字符串
      • Algorithm
        • Sorting Algorithm
        • 查找
        • 贪心算法
        • 动态规划
        • 位运算
      • Practice Topics
        • Data Struct in SDK
        • Topic - Tree
        • Topic - Graph
        • Topic - 滑动窗口
        • 剑指 Offer 题解
    • 并发编程
      • 并发模式
      • 并发模型
  • 系统设计
    • 软件设计
      • 软件架构
      • 编程范式
      • 系统设计题
      • 设计原则
      • 计算机程序的构造和解释 SICP
    • 领域驱动设计
      • 应用:在线请假考勤管理
      • 应用: library
    • 微服务与云原生
      • Designing and deploying microservices
      • 容器技术
      • Docker
      • Etcd
      • Kubernetes
        • Kubernetes - Mapping External Services
      • Istio
      • 监控
    • 分布式系统
      • 分布式理论
      • 分布式事务
    • 后端存储设计
      • 缓存设计
      • 数据库架构设计
    • CI/CD
    • 设计最佳实践
    • 测试
    • 安全
    • 综合
      • 开发实践
      • 分布式锁
      • 分布式计数服务
      • 弹幕系统设计
      • 消息队列设计
      • 分布式ID生成算法
      • 限流设计
      • 网关设计
      • 通用的幂等设计
      • 分布式任务调度
        • Timer
        • ScheduledExecutorService
        • Spring Task
        • Quartz
      • 交易系统
      • 权限设计
  • 编程语言
    • 编程语言
    • C & C++
    • Java
      • JVM
        • JVM Bytecode
      • Java 核心技术
      • Java 8 新特性
      • Java 集合框架
      • Java NIO
      • 并发编程
        • 线程生命周期与线程中断
        • 三个线程交替打印
        • 两个线程交替打印奇偶
        • 优雅终止线程
        • 等待通知机制
        • 万能钥匙:管程
        • 限流器
        • 无锁方案 CAS
    • Java 源码阅读
      • Unsafe
      • 异步计算 Future
      • Java Queue
      • CoalescingRingBuffer 分析
      • Java Collections
        • PriorityQueue 分析
        • HashMap 分析
        • TreeMap
    • Golang
    • Python
  • 框架/组件/类库
    • Guava
      • Guava Cache
      • Guava EventBus
    • RxJava
    • Apache MINA
    • Netty
      • 网络 IO 模型
      • Netty 生产问题
    • Apache Tomcat
    • MyBatis
    • 限流框架
    • Spring Framework
      • Spring Core
      • Spring 事务管理
    • Spring Boot
    • Spring Cloud
      • Feign & OpenFeign
      • Ribbon
      • Eurake
      • Spring Cloud Config
    • FixJ
    • Metrics
    • Vert.x
  • 中间件
    • Redis
      • Redis 基础
        • Redis 数据结构设计与实现
        • Redis 高性能网络模型
      • Redis checklist
      • 应用案例 - Redis 数据结构
      • 应用案例 - Redis 缓存应用
      • 应用案例 - Redis 集群
      • Redis 客户端
      • Redis 生产案例
        • [译] 在 Redis 中存储数亿个简单键值对
    • MySQL
      • MySQL 基础
      • MySQL Index
      • MySQL Transaction
      • MySQL 优化
      • MySQL 内核
      • MySQL Command
      • MySQL Checklist
      • MySQL Analysis Tool
      • 实现 MySQL
    • State Machine
    • 数据库连接池
    • MQ
      • 高性能内存队列 Disruptor
      • Kafka
      • Pulsar
      • RocketMQ
        • Broker 的设计与实现
      • NSQ
  • 实际案例
    • 线上 Case
      • Request Aborted
      • MySQL - Specified key was too long
      • Java 应用 CPU 100% 排查优化
      • 频繁 GC 导致的 Java 服务不响应
      • 导出优化
  • 大数据
    • 流计算
    • Flink
  • 其他
    • 工具
    • 读书
      • 设计数据密集型应用
      • 实现领域驱动设计
      • 精通比特币
      • 提问的智慧
    • 论文
    • 工程博客
    • 阅读源码
    • 面试
      • 如何在最短的时间里对对方有个全面的了解
    • 分享
    • 软技能
    • Todo
  • Blog
    • #算法
      • 查找
      • 位运算
      • 树
    • #架构
      • 1- 通信
    • Design & Dev & Opt
      • High Performance Data structure Design
  • Tiny Project
    • A Simple WeChat-like Instant Messaging Platform
由 GitBook 提供支持
在本页

这有帮助吗?

  1. 中间件

数据库连接池

上一页State Machine下一页MQ

最后更新于4年前

这有帮助吗?

HikariCP 数据库连接池

什么是数据库连接池? 数据库连接池和线程池是一样的,都属于池化资源,不同的是资源本身的不同,数据库连接池是对数据库连接的建立、关闭和管理,主要作用是避免频繁的创建和销毁数据库连接,因为数据库连接建立和销毁是一个重量级的操作(涉及到TCP的三次握手和四次挥手,mysql用户登陆,权限验证等,这也是会引发问题的地方);我们使用数据库的核心操作是使用一个连接执行一个或多个SQL,获取结果,所以多个SQL之间共享一个连接是可行的,数据库连接池就是这样一种池化技术,需要连接时从连接池中获取,不需要时归还给连接池,而连接的创建和关闭由连接池独立管理。 连接池的原理如下: 应用服务和数据库之间使用连接池做缓冲,应用服务在发起数据库操作时,都从连接池中获取连接、使用连接、归还连接,连接池负责连接生命周期的管理。 JDBC 规范JDBC 其实是 JDBC API,它提供了大量的接口规范,用来定义应用程序如何使用数据库。 为什么需要JDBC?我们在做业务开发时,需要用到数据库进行数据持久化,然后数据库厂商是多种多样的,每个厂商都可以开发自己的数据库应用驱动程序,但是不同厂商开发的驱动必定是多样性的,这为业务程序的开发带来了复杂性,如果我们要切换一个数据库产品,带来了维护的复杂性,所以有一套标准可以简化很多事情,而且无需过多关注驱动的实现细节,JDBC 就是这样一套标准。 JDBC 向上为 Java 的应用程序提供统一的数据库操作接口,向下屏蔽了多个数据库厂商之间的差异性,使得数据库操作标准化和流程化:

  1. 通过数据源DataSource或DriverManager获取 Connection

  2. 通过 Connection 创建 Statement

  3. 通过 Statement 执行 SQL

  4. 通过 ResultSet 获取 SQL 执行结果

  5. 迭代 ResultSet 来进行业务处理

  6. 释放 ResultSet

  7. 释放 Statement

  8. 释放 Connection

此外,JDBC 利用 SPI 机制进行服务发现,典型的面向接口编程,高内聚松耦合,彻底解耦具体的数据库驱动实现。 以 MySQL 为例,分析整个过程是如何完成的

  1. 建立数据库连接,首先进行 TCP 的三次握手,然后根据 MySQL 协议发送 Login Request,MySQL 服务器返回 OK;然后发送 SQL 语句,执行 SQL;然后返回 SQL 执行结果;最后关闭连接 conn.close(), 进行 TCP 四次挥手;整个过程耗时(在SQL不出现慢查询的情况下)100ms ~ 500 ms,可见其开销还是比较大的。

  2. JDBC 规范本身包含连接池的规范,连接池是为了提升性能,降低复杂度而引入的池化技术

  3. JDBC 为了屏蔽具体的数据库厂商的驱动实现,采用了 SPI 机制,叫 Service Provider Interface;具体实现是使用 ServiceLoader.load 加载实现了某个接口的所有实现类,这些实现类配置在 META-INF/services/java.sql.Driver 文件中,由实现了 JDBC 规范的驱动的jar包中指定; 其加载的本质是使用 Class.forName 的反射机制

查看 JDBC 规范了解详情:

  1. 创建和销毁连接都比较耗时,并发用户多时会让应用服务卡顿

  2. 数据库的连接是有限的,如果并发量大,数据库连接的总数会很快被用完,新的连接就会失败,同时大量的连接会占用内存和CPU资源,严重时会造成数据库性能下降,甚至宕机

  3. 我们的目的是执行一条SQL,但是产生了大量和网络IO相关的事情

  4. 频繁的创建和销毁数据库连接,会造成 JVM 临时对象增多,会触发频繁 GC

  5. 频繁关闭连接后会产生大量的 TIME_WAIT 状态的连接(在2个MSL之后关闭),不能及时回收资源,是很多问题产生的原因

  6. 并发量上来后,应用的RT会增加,QPS降低

使用了数据库连接池,主要是复用了已有的连接而不是重新建立和销毁,可以很好的解决上面的问题:

  1. 资源重用。数据库连接得到重用,减少了大量连接的创建和销毁带来的开销,也大量减少了内存碎片和数据库临时线程进程的数量

  2. 系统调优更简单,减少了对 TIME_WAIT 状态的连接的调优,需要针对连接池进行调优即可

  3. 系统响应更快。在启动应用时会初始化一定数量的连接,再加上重用连接,在执行SQL时,直接使用,大大节省了时间,系统响应更快

  4. 连接管理更灵活。连接池担当了有界缓冲,还可以自行配置连接的最小数量、最大数量、最常空闲时间、获取连接超时间、心跳检测等。另外,用户也可以结合新的技术趋势,增加数据库连接池的动态配置、监控、故障演习等一系列实用的功能

  • 连接的测试在getConnection时同步进行,并有独特的优化。

  • 在自己的事务中封装内部池的查询,含testQuery一级initSQLQuery。

  • 当连接Connections归还给连接池的时候,执行rollback操作。

  • 在Connection.close的时候,跟踪并关闭废弃语句Statements。

  • 在将Connection连接归还到客户端之前清除SQL警告。

  • 默认参数支持自动提交、事务隔离级别、catalog和只读状态。

  • 对于一些诸如“SQLException对象是否存在断开连接错误”等陷阱进行检查

  • 字节码级别的优化;优化字节码输出,精简字节码,优化拦截器

这个优化主要是使用 Javassist 生成动态代理,编译时自动生成代理类的字节码文件,使得生成的字节码更少,性能更好;此外,针对 JIT 做了有优化,HikariCP在精简字节码的时候,研究了编译器的字节码输出,甚至是JIT的汇编输出,以将关键部分限制为小于JIT内联阈值,展平了继承层次结构,阴影成员变量,消除了强制转换。

  • 微观层面的优化:FastList 替换 ArrayList

FastList 是对 List 接口的精简实现,主要做了两方面的优化:

  1. 在每次调用 get() 时,去除了 rangeCheck(),节省了字节码和执行时间

  2. 在调用 remove 删除 statement 时,优化为逆序删除,也就是后add进来的先删除,这也符合connection创建statement然后关闭的顺序,相比ArrayList的顺序查找逆序删除要高效

  • 微观层面的优化:更好的并发集合 ConcurrentBag

连接池中的连接是多线程共享的资源,既要保障线程安全,又要有极致的并发读写性能,这样才能最大限度的降低因并发操作带来的性能影响。ConcurrentBag 具有无锁设计、ThreadLocal缓存、队列窃取、直接切换优化四大特点:

  1. ConcurrentBag 的实现并没有使用 synchronized 和 Lock,而是使用了 lock-free 算法,主要借助了几个成员变量:CopyOnWriteArrayList sharedList, SynchronousQueue handoffQueue, AtomicInteger waiters

  2. 队列窃取机制:首先尝试从ThreadLocal中获取属于当前线程的元素来避免锁竞争,如果没有可用元素则扫描公共集合,再从共享的CopyOnWriteArrayList中获取

  3. SynchronousQueue 存在资源等待线程时的第一手资源交接

  4. ThreadLocal 无共享设计,最大限度的重用本地线程的资源

  5. CopyOnWriteArrayList 负责存放ConcurrentBag中全部用于出借的资源, 只有在 add 和 remove 时才复制一份数据进行修改

HiKariCP 原理分析 以正确的姿态在项目中使用 HiKariCPHiKariCP 被作为 SpringBoot2.x 的默认数据库连接池SpringBoot 2.x:HikariCP →Tomcat pool → Commons DBCP2SpringBoot 1.x:Tomcat pool → HikariCP → Commons DBCP → Commons DBCP2

jdbcUrl=jdbc:mysql://localhost:3306/simpsons username=test password=test dataSource.cachePrepStmts=true dataSource.prepStmtCacheSize=250 dataSource.prepStmtCacheSqlLimit=2048 dataSource.useServerPrepStmts=true dataSource.useLocalSessionState=true dataSource.rewriteBatchedStatements=true dataSource.cacheResultSetMetadata=true dataSource.cacheServerConfiguration=true dataSource.elideSetAutoCommits=true dataSource.maintainTimeStats=false

  1. prepStmtCacheSize:这将设置MySQL驱动程序将为每个连接缓存的预准备语句数。默认值为保守25。我们建议将其设置为250~500。

  2. prepStmtCacheSqlLimit:这是驱动程序将缓存的已准备SQL语句的最大长度。MySQL的默认值是256。根据我们的经验,特别是对于像Hibernate这样的ORM框架,这个默认值远低于生成的语句长度的阈值。我们推荐的设置是2048。

  3. cachePrepStmts:如果事实上禁用了高速缓存,则上述任何参数都不会产生任何影响,因为它是默认情况下。必须将此参数设置为true。

  4. useServerPrepStmts:较新版本的MySQL支持服务器端预处理语句,这可以提供显著的性能提升。应将此属性设置为true。

  • HiKariCP 监控及监控架构

  • 常见问题分析

  • 数据库连接池不是万能的,HiKariCP 同样不是万能的

HiKariCP 是最快的数据库连接池之一,但是不能把它当作万能工具,需要有更广阔的视野和更广阔的知识面。使用连接池需要注意:

  1. 多线程之间不要共享 Connection,用作局部变量是最好的

  2. 尽在需要时获取Connection,最大限度的缩短它离开池的时间;尽量先执行长时间的耗时操作,然后获取Connection,执行SQL,归还Connection

参考资料

  • Book: High-Performance Java Persistence

  • HiKariCP 数据库连接池实战

为什么数据库连接池如此重要? 数据库的连接建立需要TCP三次握手、数据库应用层协议的登陆验证过程等,连接断开需要4次挥手,可见是一个耗时长、性能低、代价高的操作,频繁的进行数据库连接的创建和销毁,在并发量高的情况下,耗时的数据库连接会让系统变得卡顿,QPS降低,RT增加;此外,数据库连接是有上限的,到达后,新的连接只能排队,甚至连接超时。那么,重用数据库连接就变得很有必要了,这样可以减少应用和数据库之间的创建和销毁TCP连接的开销。 如下是应用服务和 MySQL 数据库建立连接,执行SQL和断开连接的过程 总结一下这种方式的主要缺点:

上面是有无数据库连接池的对比,比较了4种数据库和HiKariCP连接池在打开和关闭 1000 个连接的数据对比,可见提升快 100 倍的速度 数据库连接池的原理原理:在系统初始化的时候,在内存中开辟一片空间,将一定数量的数据库连接作为对象存储在对象池里,并对外提供数据库连接的获取和归还方法。用户访问数据库时,并不是建立一个新的连接,而是从数据库连接池中取出一个已有的空闲连接对象;使用完毕归还后的连接也不会马上被关闭,而是由数据库连接池统一管理回收,为下一次借用做好准备。如果由于高并发请求导致数据库连接池中的连接被借用完毕,其他线程就会等待,直到有连接被归还。整个过程中,连接并不会被关闭,而是源源不断地循环使用,有借有还。数据库连接池还可以通过设置其参数来控制连接池中的初始连接数、连接的上下限数,以及每个连接的最大使用次数、最大空闲时间等,也可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。 还必须再支持一些实用的功能,如并发(锁性能优化乃至无锁)、连接数控制(不同的系统对连接数有不同的需求)、监控(一些自身管理机制来监视连接的数量及使用情况等)、外部配置(各种主流数据库连接池官方文档最核心的部分)、资源重用(数据库连接池的核心思想)、检测及容灾(面对一些网络、时间等问题的自愈)、多库多服务(如不同的数据库、不同的用户名和密码、分库分表等情况)、事务处理(对数据库的操作符合ALL-ALL-NOTHING原则)、定时任务(如空闲检查、最小连接数控制)、缓存(如PSCache等避免对SQL重复解析)、异常处理(对JDBC访问的异常统一处理)、组件维护(如连接状态、JDBC封装的维护)等 数据库连接池比较 数据库中断的处理,HiKariCP 等待5秒,若连接未恢复,抛出SQLExceptions异常,后续getConnection()同样处理。HikariCP在其他方面还有很多值得称赞的地方:

HiKariCP 为何如此快?上有 HiKariCP 的基准测试,这里是 HiKariCP 所做的优化:HiKariCP 如此受欢迎的原因是其极致的性能,同时还保证了正确性和可靠性。 主要有如下优化

HiKariCP ,使用HiKariCP 时大部分情况下是不需要修改默认的配置参数的,在高并发情况下需要进行调优

, MySQL 的手册中也有很多配置跟性能相关, 还有一个

参考:追光者系列

JDBC 4.2 规范解读
jdbc4.1-spec.pdf
部分接口的解读
JDBC 规范对池化的介绍
JDK8 API Doc
The JNDI Tutorial
JNDI Intro
HiKariCP GitHub
Down the Rabbit Hole
参数配置
HiKariCP MySQL Configuration 可以优化 MySQL 的性能
ppt
HiKariCP 连接池监控指标实战
理解数据库连接池底层原理之手写实现
MySQL 数据库连接池专题
高性能数据库连接池 HiKariCP
有赞数据库连接池配置及案例优化
高性能数据库连接池内幕