数据库连接池设置多少连接才合适?

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 前段时间在一个老项目中经历过一个问题:一个 Dubbo 服务,启动的时候慢的要死,后来看日志查原因整个过程一直在初始化数据库连接。一看数据库连接参数,连接池大小:1024。很多入行晚的同学没有经历过手写 JDBC 连接的日子。那个时候没有数据库连接池的概念,都是原生代码一顿搞,后来有了 iBATIS 之后 Java 开发的繁杂程度才逐渐减轻,也衍生 C3P0 数据库连接池这种基础的东西。

前段时间在一个老项目中经历过一个问题:一个 Dubbo 服务,启动的时候慢的要死,后来看日志查原因整个过程一直在初始化数据库连接。一看数据库连接参数,连接池大小:1024。


很多入行晚的同学没有经历过手写 JDBC 连接的日子。那个时候没有数据库连接池的概念,都是原生代码一顿搞,后来有了 iBATIS 之后 Java 开发的繁杂程度才逐渐减轻,也衍生 C3P0 数据库连接池这种基础的东西。


罗马不是一天建成的,可是互联网发展太快了,技术压力逼迫下各种中间件被迫研发,大家加班加点搞出来各种高大上的脚手架,也成就很多伟人。


数据库连接使用 TCP 的方式,建立连接需要3次握手,释放连接需要4次挥手,当今这种互联网使用频率下,如果每一次访问数据库都重新建立连接,我估计你们公司倒闭800次都不够。


1. 数据库连接的过程是怎样的

Java 鼻祖 Sun 公司是想以一套API统一天下,奈何各个数据库服务器厂商太给力统一不了。无奈之举是创建了一个统一的接口,提出一套统一接入的步骤,各个厂商实现接口,按照步骤加载自己的数据库。所以现在的方案就是4板斧:


注册驱动,为人所知的:Class.forName();

获取Connection,成功即与数据库建立连接;

拿到Statement对象,用于操作数据库的CRUD;

获取数据库返回结果ResultSet。

大家应该都知道数据库本身是一个客户端程序,只有启动了才能连接。拿 MYSQL 举例,我们在安装并启动了服务的机器上,命令行的方式输入:mysql -uroot -p 即可连接当前数据库。


MYSQL 连接方式有很多种,区分Unix系统 和 Windows 系统以及通用的连接方式,在这里仅说两种方式:一种为 unix domain socket,另外一种为基于 tcp/ip 协议,一般我们如果远程访问数据库肯定是基于 tcp/ip 的,但是如果我们在本机登录就会分为使用 socket 还是 tcp/ip。

socket:mysql -uroot -p
tcp/ip:mysql -h127.0.0.1 -uroot -p

当数据库服务器和应用服务器位于不同的主机时就要使用 tcp/ip 的方式建立连接。每一个连接在操作系统中占用一个线程来维护。建立连接也分为两类:短连接和长连接。

短连接

所谓短连接就是指应用程序和数据库通信完毕之后连接关闭。这种连接每次的操作就是:

这样做的问题是:


频繁的建立 / 释放连接对数据库来说增加了系统负担;

应用程序每次操作数据库的过程将会变得很慢;

应用系统每次建立连接都要占用一个端口,频繁的建立/释放,每个被释放的连接在发出释放请求之后并不是马上就执行,必须经历一个 FIN 阶段的等待直到确认为止。所以在每秒几千次数据库请求的时候,应用服务器端口很有可能被消耗完。

长连接


长连接即在建立连接后一直打开,直到应用程序关闭才释放。使用长连接的好处是减少每次创建连接带来的开销。


对于应用服务器来说维持长连接的好处不言自明,但是对于数据库服务器来说,过多的长连接则是灾难。


MYSQL的TCP连接支持长连接,所以每次操作完数据库,可以不必直接关掉连接,而是等待下次使用的时候在复用这个连接。所有的Socket长连接都是通过TCP自带的ping来维持心跳(TCP保活),从而保持连接状态,而我们熟悉的websocket,也正是通过TCP的心跳来维持连接不被中断。


连接池


长连接的好处这么大,自然大家都用长连接。慢慢就搞出一套长连接维护的工具 - 数据库连接池。


设计连接池也没有多么复杂,大致的步骤就是:


初始化连接;

业务取出连接;

业务发送请求;

放回连接。

除了上面的基本功能以外,还要处理并发问题,多数据库服务器和多用户,事务处理,连接池的配置与维护。大概就这些功能。有了连接池之后,连接的建立和释放跟业务就没有关系,交给交接池来维护。


2. MYSQL 能支持多少连接

MYSQL 的最大连接数在5.7版本中默认是151, 最大可以达到16384(2^14)。如何设置最大连接数在于你的服务器性能,查看 MYSQL连接数信息命令如下:

mysql> show variables like '%max_connections%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 5050  |
+-----------------+-------+
1 row in set (0.00 sec)

我们生产环境MYSQL的最大连接数设置为 5050,注意不能设置的太小,太小造成的后果是连接失败:“query failed Error 1040: Too many connections“ 错误。太大且当连接该数据库的机器比较多的时候则会对当前MYSQL的性能产生影响。


MYSQL官网给出了一个设置最大连接数的建议比例:

Max_used_connections / max_connections * 100% ≈ 85%

即已使用的连接数占总上限的85%左右,如果目前已使用的连接数与最大连接数比例小于10%那很显然设置的过大。

查询当前数据库已建立连接数:

mysql> show status like 'Threads_connected';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_connected | 89    |
+-------------------+-------+
1 row in set (0.00 sec)

Mysql的配置可以在全局变量中查询和设置,相关的配置主要可以查询下面这些:

image.png

3. 连接池设置多少连接才合适

设置连接池的大小肯定不是越大越好,需要考虑的是当前服务所在机器的性能,网络状况,数据库机器性能,数据库特性等等。同时也要做到不浪费系统资源,内存,端口,同步信号量等等。


比如说应用服务器Tomcat设置的最大线程池缺省值200,最大假设每个线程会用到一个数据库连接,那么线程池大小应该小于等于200。


另外需要考虑的是,每申请一个长连接都会在物理网络上建立一个用于长连接维护的进程,而进程的执行跟物理机的CPU核数有关。理论上一个8核的服务器将连接池设置为8最佳,每一个核同时处理一个线程,超过8的并发就有线程上下文切换的开销。


这里有一个 Oracle 性能小组发布的简短视频,连接池测试分2个部分,视频中调整了线程池大小为2048的时候数据库性能陡然下降,后面调整到144就恢复了。


PostgreSQL提供了一个设置预期线程池大小的公式:

connections = ((core_count * 2) + effective_spindle_count)

该公式来自于:


https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing


其中,core_count是CPU核心, effective_spindle_count 的含义是有效主轴数,如果你的服务器使用的是带有16个磁盘的RAID,那么valid_spindle_count=16。它实质上是服务器可以管理多少个并行I / O请求的度量。


旋转硬盘一次(通常)一次只能处理一个I / O请求,如果你有16个,则系统可以同时处理16个I / O请求。


我想 Hikari 作为目前最优秀的数据库连接池之一,提出的这个公式还是经得起检验的。


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
29天前
|
数据库 C# 开发者
ADO.NET连接到南大通用GBase 8s数据库
ADO.NET连接到南大通用GBase 8s数据库
|
28天前
|
数据库连接 Linux Shell
Linux下ODBC与 南大通用GBase 8s数据库的无缝连接配置指南
本文详细介绍在Linux系统下配置GBase 8s数据库ODBC的过程,涵盖环境变量设置、ODBC配置文件编辑及连接测试等步骤。首先配置数据库环境变量如GBASEDBTDIR、PATH等,接着修改odbcinst.ini和odbc.ini文件,指定驱动路径、数据库名称等信息,最后通过catalog.c工具或isql命令验证ODBC连接是否成功。
|
1月前
|
SQL Java 数据库连接
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率。本文介绍了连接池的工作原理、优势及实现方法,并提供了HikariCP的示例代码。
55 3
|
27天前
|
JSON JavaScript 关系型数据库
node.js连接GBase 8a 数据库 并进行查询代码示例
node.js连接GBase 8a 数据库 并进行查询代码示例
|
1月前
|
关系型数据库 MySQL Linux
Linux系统如何设置自启动服务在MySQL数据库启动后执行?
【10月更文挑战第25天】Linux系统如何设置自启动服务在MySQL数据库启动后执行?
121 3
|
1月前
|
关系型数据库 MySQL Linux
在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。
本文介绍了在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。同时,文章还对比了编译源码安装与使用 RPM 包安装的优缺点,帮助读者根据需求选择最合适的方法。通过具体案例,展示了编译源码安装的灵活性和定制性。
166 2
|
28天前
|
数据库连接 数据库 C#
Windows下C# 通过ADO.NET方式连接南大通用GBase 8s数据库(上)
Windows下C# 通过ADO.NET方式连接南大通用GBase 8s数据库(上)
|
28天前
|
数据库连接 数据库 C#
Windows下C# 通过ADO.NET方式连接南大通用GBase 8s数据库(下)
本文接续前文,深入讲解了在Windows环境下使用C#和ADO.NET操作南大通用GBase 8s数据库的方法。通过Visual Studio 2022创建项目,添加GBase 8s的DLL引用,并提供了详细的C#代码示例,涵盖数据库连接、表的创建与修改、数据的增删查改等操作,旨在帮助开发者提高数据库管理效率。
|
1月前
|
Java 数据库连接 数据库
深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能
在Java应用开发中,数据库操作常成为性能瓶颈。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能。文章介绍了连接池的优势、选择和使用方法,以及优化配置的技巧。
41 1
|
1月前
|
Java 数据库连接 数据库
Java连接池在数据库性能优化中的重要作用。连接池通过预先创建和管理数据库连接,避免了频繁创建和关闭连接的开销
本文深入探讨了Java连接池在数据库性能优化中的重要作用。连接池通过预先创建和管理数据库连接,避免了频繁创建和关闭连接的开销,显著提升了系统的响应速度和吞吐量。文章介绍了连接池的工作原理,并以HikariCP为例,展示了如何在Java应用中使用连接池。通过合理配置和优化,连接池技术能够有效提升应用性能。
57 1