Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >MySQL 案例:关于程序端的连接池与数据库的连接数

MySQL 案例:关于程序端的连接池与数据库的连接数

作者头像
王文安@DBA
修改于 2020-08-31 09:08:03
修改于 2020-08-31 09:08:03
3K0
举报

前言

Oracle 在 Youtube 分享了一段关于JDBC 连接池的视频,演示了同等业务压力下,不同的连接池线程数设置对数据库性能的影响,HikariCP 转载了这个视频,并进行了一些分析。本文主要内容为英文原文的翻译(推荐阅读原文),部分内容为转述。

虽然作为文章中心思想的视频是 11 年的,但是从个人的经验来看,当单个 SQL 语句的效率足够高(<5ms)的时候,这个结论在方向性上是没问题的,连接数/并发数并不一定是越高越好。

正文

开发者在配置连接池的时候经常会犯下一些错误,因为理解了一些连接池参数的意义之后,实际配置的数值可能是反直觉的。

模拟 1 万前端用户

假设有一个网站总是有 10000 个用户在访问,并且 TPS 为 20000,一般都会这么考虑:连接池需要设置成多大才能承载这个业务压力?但是真相可能会非常令人意外:需要考虑的是连接池需要设置成多小。Oracle Real-World Performance group 发布了一个视频来演示这个场景。

第一轮测试使用了 2048 个线程作为连接池的配置,测试结果如下图:

2048 线程
2048 线程

TPS 约 160k 左右,实际 SQL 执行的时间是 78ms,在连接池队列的等待时间为 39ms,截图最下方展示了等待事件的 TOP 5,数据库层面有很多的等待事件。CPU 的使用率也很高(dbsvr1):

CPU 使用率
CPU 使用率

当连接池的线程数降到 1024 的时候,测试结果如下图:

1024 线程
1024 线程

TPS 约 170k 左右,没有明显的变化,队列等待时间有少量下降,但是 SQL 的执行时间从 78ms 降到了 38ms,效果很明显。而等待事件中,CPU 等待事件也变多了。

当连接池的线程数降到 96 的时候,测试结果如下图:

96 线程
96 线程

TPS 约 200k 左右,提升了约 20%,队列等待时间和 SQL 执行时间都有大幅度的下降,等待事件中全部变成了 CPU 等待。

PS:视频作者也吐槽了一下,I got a lot of resistance and a lot of argument,被很多人挑战过,也阻止过。

原因是什么?

不止数据库,其他的软件也有类似情况,比如 4 线程的 Nginx web-server 为什么会比 100 线程的 Apache web-server 性能要好。这实际上和计算机 CPU 和系统的特点有关,有时候,线程少比线程多要好。

现实情况中,即便只有一核,看起来也能处理数十个或者是数百个线程。但是很多人(应该要)知道这是是操作系统的时分(时间分片)技术带来的效果。实际上一个核心是只能执行一个线程的工作的,但是操作系统通过上下文切换让 CPU 的核心把工作内容切换成其他线程的任务,通过不停的切换,达到了“并行处理工作”的效果。从理论上说,先执行完工作 A,再执行工作 B 是比通过上下文切换“并行”执行要快,因为上下文切换是会浪费时间的。因此一旦线程的数量超过了 CPU 的核心数,继续加线程数只会让任务处理越来越慢。

有限的资源

当然,实际情况并不会像上文描述一样那么简单,但是变慢的现象一般还是存在的。可能成为数据库瓶颈的,一般就是三大基础资源:CPU,磁盘,网络。内存其实也是应该考虑的一项资源,不过内存的带宽和磁盘,网络要差上几个数量级,所以一般不会遇到瓶颈。

假设磁盘和网络都没有瓶颈,那么事情会变得很简单:在一个 8 核的服务器上,8 个线程是最佳的性能,超过 8 线程之后就会因为上下文切换导致性能被浪费。当加上磁盘和网络的影响之后,事情就不是那么简单了,传统的机械盘由于存在碟片转动以及寻道时间等消耗,如果一个核心一直在处理一个线程的任务,那么就会有不少时间处于“IO 等待”,触发这个等待事件的时候 CPU 核心是空闲状态的,因此通过上下文切换,去执行其他线程的任务能够高效的利用 CPU 核心的计算能力。

因此在现实中,存在线程数高于 CPU 核心数时,性能在继续提升的现象。那么到底线程数设置为多少会比较好?从上面的描述可以知道,这个数字取决于磁盘系统,由于 SSD 存储的普及,现在的磁盘存储已经没有寻道时间或者碟片转动的消耗了。那么因为 SSD 的“IO 等待”很少,所以能设置更高的线程数?结论可能是 180 度反转的。正因为“IO 等待”很少,所以 CPU 在处理线程任务的时候,空闲(即被 IO 阻塞)的时间很少,所以线程数越接近核心数,性能越好。更多的线程适合于经常被阻塞的场景,因为大量的空闲、阻塞时间可以用来执行其他线程的任务。

网络方面的情况也和磁盘比较类似,当写入的数据超过网卡的写入/发送队列的上限时,也会出现阻塞的情况,使用高流量,比如 10G 的网卡比 1G 的网卡更不容易出现阻塞。不过网络瓶颈的优先级较低,一般是最后才会考虑到的,甚至有一些人会完全忽略网络瓶颈的可能性(取决于网络环境建设能力)。

图表比文字更形象,可以参考如下测试结果图:

测试结果
测试结果

这个测试结果来自于 PostgreSQL 基准测试,纵坐标是 TPS,横坐标是 Client 数量,从 1 到 50 个线程的并发。虽然 Oracle 的视频中展示了线程数从 2048 降到 96 的测试结果,但是 96 实际上都太高了,除非服务器上的核心数有 16 个或者 32 个。

计算公式

PostgreSQL 项目组给了一个计算公式来计算并发的连接数,计算出来的值可以作为最初的参考设置。这个计算方式其实对大多数数据库都有参考价值。具体的设置建议以参考值为基准,尽量在接近生产压力的环境下进行测试和调整。

计算公式为:connections = ((core_count * 2) + effective_spindle_count)

  • core_count:不是“超线程”技术之后看到的核心数,而是实际的核心数。
  • effective_spindle_count:如果数据可以完全 cache 到内存则取 0,否则随着 cache 命中率降低,则这个数值会变高。
    • MySQL 方面,可以认为是 innodb_buffer_pool 的命中率。

所以一个 4 核的酷睿 I7 服务器只有一块磁盘的情况下,连接池的线程数可以设置成:9 = ((4 * 2) + 1),用 10 作为一个取整的数值就不错。看起来有点低?可以试试看,可以打个赌,这个设置可以轻松支撑 3000 前端用户,接近 6000 TPS 的简单查询。用同样的硬件配置,当连接数设置得比 10 高很多的时候,可以从压力测试中看到 TPS 开始下降,前端用户的响应时间开始攀升。

公理

应用需要一个小的“池子”,和等待使用这个池子中连接的应用线程。

如果有个网站有 10000 个前端用户,连接池设置成 10000 会非常的疯狂,1000 也会很恐怖,甚至 100 都过量了。实际上连接池的线程数只需要几十就够了,剩下的应用线程只需要在连接池那里等待连接可用就行了。如果连接池的线程数参数已经好好优化过,那么这个设置一般不会比 core_count * 2 高,或者不会高很多。

然而在实际情况中,内部 web 应用会使用一些“令人惊奇”的设置:比如,仅有几十个用户在周期性的执行一些操作,但是连接池的线程数设置为 100。请不要过度配置这些参数和数据库

Pool-locking

Pool-locking 被关注的原因是会出现单个应用层线程同时使用多个数据库连接的情况,这个问题更多的是应用层需要考虑的。当然,增加连接池的线程数可以减少这种场景下互相抢占连接池线程的几率,但是强烈建议先在应用侧考虑如果解决这个问题,而不是直接增大连接池的线程数。

比如最大有 N 个应用层的线程,每个应用层的线程需要使用 M 个数据库连接,那么连接池想要避免 Pool-locking 就至少需要N x (M - 1) +1个数据库连接。在某些场景下,使用 JTA(Java Transaction Manager)可以显著的减少当个应用层线程需要的数据库连接数,因为getConnection()这个函数会返回当前事务已经持有的数据库连接。

注意事项

连接池的线程数和实际的情况是紧密相关的。

比如一套系统中,一部分业务逻辑使用长连接,一部分业务使用短连接,最好的办法是创建两个连接池,而不是考虑怎么去优化一个池子的设置。另外一些系统则存在外部原因会限制数据库连接数,比如业务层的 JOB 并发数量是有上限的,或者是固定的,那么连接池的线程数就可以参考这些“外部原因”的限制,设置成一样的值,或者是在这个数量附近浮动。

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
数据库连接池到底应该设多大?这篇文章可能会颠覆你的认知
数据库连接池大小往往是一个很容易被大家所忽略的参数,通常这个参数也和公司或者组内文化有关系,以前在美团的时候基本所有的项目连接池大小都设置20, 当时也没有考虑为什么会这么设置,反正就跟着大伙儿用。后来来到了猿辅导,发现大家使用的连接池是tomcat-jdbc,并没有针对连接池大小做特殊配置,使用的是默认的100。
用户5397975
2019/11/28
2.4K0
数据库连接池到底应该设多大?这篇文章可能会颠覆你的认知
技术经理:求求你,别再乱改数据库连接池的大小了!
基本上来说,大部分项目都需要跟数据库做交互,那么,数据库连接池的大小设置成多大合适呢?
JAVA葵花宝典
2019/05/24
1.2K0
Mysql连接数设置获取
Threads_connected 跟show processlist结果相同,表示当前连接数。准确的来说,Threads_running是代表当前并发数
码客说
2020/05/09
3.9K0
面试官问:高并发下,你都怎么选择最优的线程数?
为了加快程序处理速度,我们会将问题分解成若干个并发执行的任务。并且创建线程池,将任务委派给线程池中的线程,以便使它们可以并发地执行。在高并发的情况下采用线程池,可以有效降低线程创建释放的时间花销及资源开销,如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及“过度切换”(在JVM中采用的处理机制为时间片轮转,减少了线程间的相互切换) 。
芋道源码
2020/06/16
1.1K0
连接池技术:简单而强大的加速数据库访问方法
以操作数据库为例,当一个数据库操作任务到来时,程序需要和数据库建立连接,进行三次握手、数据库用户验证,然后执行SQL语句,最后用户退出、四次挥手关闭连接。每次任务都执行这样的流程,那么整个流程中,真正有效而且变化的只有<执行SQL语句>这一步骤,而且每次建立连接、用户验证、关闭连接都耗费时间。
Lion 莱恩呀
2024/09/24
2070
连接池技术:简单而强大的加速数据库访问方法
【追光者系列】Hikari连接池配多大合适?
摘自【工匠小猪猪的技术世界】 首先声明一下观点:How big should HikariCP be? Not how big but rather how small!连接池的大小不是设置多大,不是
用户1655470
2018/07/24
2K0
解惑:为什么300的并发能把支持最大连接数4000数据库压死?
买了一台数据库,最大连接数的参数是 4000,看起来很棒!但是 cpu 和内存并不咋好!是 2c4g的超低配制。
烂猪皮
2021/04/23
1.1K0
解惑:为什么300的并发能把支持最大连接数4000数据库压死?
详解数据库连接池 Druid
在 Spring Boot 项目中,数据库连接池已经成为标配,然而,我曾经遇到过不少连接池异常导致业务错误的事故。很多经验丰富的工程师也可能不小心在这方面出现问题。
勇哥java实战
2023/12/09
2.3K0
【追光者系列】HikariCP 连接池配多大合适(第一弹)?
首先声明一下观点:How big should HikariCP be? Not how big but rather how small!连接池的大小不是设置多大,不是越多越好,而是应该少到恰到好处
芋道源码
2018/07/31
4.1K0
Tomcat线程数超过350,是否服务就有问题?
Tomcat 的线程数大于 350 是否过多,实际上取决于多个因素,包括你的服务器硬件配置、应用负载、并发请求的量以及你所配置的 Tomcat 参数。没有一个固定的标准值说“350 线程就是太多”,但我们可以根据以下几个方面来评估和判断:
Linux运维技术之路
2025/01/07
1950
Tomcat线程数超过350,是否服务就有问题?
如何减少频繁创建数据库连接的性能损耗?
大多系统初生时就是这样,只是随业务不但发展变得复杂,架构迭代。系统上线后,虽用户量不大,但运行一切正常。不过领导觉得用户量太少,紧急调动运营做了某音的推广。带来大波流量,系统访问速度突然开始变慢。
JavaEdge
2023/01/16
1.6K0
数据库连接(2) - 为什么C3P0连接池那么慢
在上一篇中我们介绍说客户端建立一次连接耗时太长(建立连接,设置字符集,autocommit等),如果在每个sql操作都需要经历建立连接,关闭连接。不仅应用程序响应慢,而且会产生很多临时对象,应用服务器GC压力大。另外数据库server端对连接也有限制,比如MySQL默认151个连接(实际环境中一般会调大这个值,尤其是多个服务时)
方丈的寺院
2019/08/05
1.1K0
数据库连接(2) - 为什么C3P0连接池那么慢
用了这么久的数据库连接池,你知道原理吗?
这次我们采取技术演进的方式来谈谈数据库连接池的技术出现过程及其原理,以及当下最流行的开源数据库连接池jar包。
Bug开发工程师
2019/06/17
1.2K0
用了这么久的数据库连接池,你知道原理吗?
数据库连接池学习笔记(一):原理介绍+常用连接池介绍
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。
全栈程序员站长
2022/09/30
3.5K0
数据库连接池学习笔记(一):原理介绍+常用连接池介绍
数据库连接池配置(案例及排查指南)
墨墨导读:本文以 druid 1.1.5 (https://github.com/alibaba/druid) 连接池为例来阐述几个参数的重要性及如果避免踩坑,虽然下面提到的都是druid的配置项,但多数连接池(不限于数据库)其实也都有类似的配置,基本用法和场景均可借鉴。
数据和云
2019/06/20
1.5K0
数据库连接池配置(案例及排查指南)
数据库连接池:从JDBC到高效管理的演进
从最初的JDBC手动连接数据库,到后来的ORM框架如iBATIS,再到数据库连接池如C3P0,技术的进步和互联网的发展速度是非常惊人的。现在层出不穷的各种中间件和脚手架,都是为了提高开发效率,降低开发难度,让开发者能够更专注于业务逻辑的实现。
不惑
2024/05/07
3300
数据库连接池:从JDBC到高效管理的演进
SpringBoot 官方推荐,连接池,太快了!
大家好,现在介绍一款非常强大,高效,并且号称“史上最快连接池”。由此可见他是有多受人喜欢,并且在SpringBoot2.0之后,采用的默认数据库连接池就是Hikari。 我们知道的连接池有C3P0,DBCP,它们都比较成熟稳定,但性能不是十分好。所以有了BoneCP这个连接池,它是一个高速、免费、开源的JAVA连接池,它的性能几乎是C3P0、DBCP的25倍,十分强悍 在我们平常的编码中,通常会将一些对象保存起来,这主要考虑的是对象的创建成本。 比如像线程资源、数据库连接资源或者 TCP 连接等,这类对象
java思维导图
2022/08/26
9970
SpringBoot 官方推荐,连接池,太快了!
连接池
连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用。 好处 编辑 这种连接“汇集”起来的技术基于这样的一个事实:对于大多数应用程序,当它们正在处理通常需要数毫秒完成的事务时,仅需要能够访问JDBC连接的 1 个线程。当不处理事务时,这个连接就会闲置。相反,连接池允许闲置的连接被其它需要的线程使用。 事实上,当一个线程需要用 JDBC 对一个 GBase 或其它数据库操作时,它从池中请求一个连接。当这个线程使用完了这个连接,将它返回到连接池中,这样这就可以被其它想使用它的线程使用
李海彬
2018/03/22
1.1K0
数据库连接池
数据库连接对象是有限资源,所以数据库连接池是用于负责分配、管理和释放数据库连接对象,它允许应用程序重复使用一个现有的数据库连接对象,而不是再重新建立一个;这一点实际上和线程池的概念差不多。数据库连接池会释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏,这项技术能明显提高对数据库操作的性能。
端碗吹水
2020/09/23
1.5K0
数据库连接池
jdbc是数据库连接池么_java的jdbc连接数据库
JDBC 是Java应用程序用来连接关系型数据库的标准API,为多种关系型数据库提供一个统一的访问接口。Sun公司一共定义4种 JDBC 驱动类型,一般使用第4种,该类型的Driver完全由Java代码实现,通过使用socket与数据库进行通信。
全栈程序员站长
2022/09/30
3.2K0
jdbc是数据库连接池么_java的jdbc连接数据库
推荐阅读
相关推荐
数据库连接池到底应该设多大?这篇文章可能会颠覆你的认知
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档