DBA面试,问一台MySQL服务器最大能支持多少连接?问倒一片候选人。。。
最近,有读者交流时,说面试DBA时,被问了这样一个问题:
“一台MySQL服务器最大能支持多少连接?”
回答的乱七八糟,现场气氛一度很尴尬。
所以,今天就来讨论一下这个问题。
个人观点:其实这个问题没有标准答案,不用直接回答100还是200,而是看你的回答思路是否正确?
概要
MySQL层连接数
Linux服务器的TCP连接数
Linux系统的文件打开数
示例
MySQL层连接数
这里不仅仅指配一个max_connections的参数
MySQL的连接数限制受多个因素影响,包括服务器硬件资源、MySQL配置和系统参数。
在评估一台服务器能支撑的MySQL连接数时,最重要的因素之一就是内存的合理分配。
MySQL服务器的内存分配通常分为三类
01
预留给缓冲池
MySQL的InnoDB引擎需要为缓冲池(Buffer Pool)预留大量内存,通常建议将物理内存的60-70%用于InnoDB缓冲池。这个缓冲池用于缓存数据和索引,提升查询性能,因此内存的合理分配至关重要。
02
每个连接的内存开销
每个MySQL连接都会占用线程资源,以下是一些与每个线程相关的内存参数:
thread_stack:每个线程的栈大小
join_buffer_size:用于联接操作的缓冲区大小。
read_buffer_size:顺序读取时的缓冲区大小
read_rnd_buffer_size:随机读取时的缓冲区大小。
sort_buffer_size:用于排序操作的内存空间。
tmp_table_size:使用临时表的大小
这些参数的大小直接决定了每个线程的内存消耗,过大的设置可能导致内存紧张,影响连接数。
03
系统预留内存
除了MySQL的内存消耗外,系统自身的内存需求也必须被考虑。Linux系统需要预留一部分内存用于系统进程、缓存和其他服务。通常建议保留10-20%的系统内存给操作系统,以确保系统的稳定性
通过合理调整MySQL配置参数,可以有效提高连接数。
根据内存容量、配置以及实际负载,MySQL的连接数可以从数百到数千个不等。
Linux服务器的TCP连接数
MySQL的每个连接实际上对应着一个TCP连接。
MySQL的每个客户端连接到服务器时,会通过TCP协议建立一个socket连接。
这就意味着服务器在支持MySQL连接数时,除了要考虑MySQL的参数配置,还要确保系统可以支撑足够多的TCP连接。
TCP连接数:理论上,Linux系统可以支持大量的TCP连接,但受限于系统资源。影响因素包括内存、CPU、网络带宽等。在理想状态下,仅维护空闲TCP连接,一个TCP连接大概需要3K左右的内存。4GB内存的服务器可以支持100万以上的连接数。
TCP四元组:每个TCP连接由源IP、源端口、目标IP和目标端口四元组唯一确定。在MySQL的连接场景中,服务器会消耗一个端口和相关资源来处理每个TCP连接。
以上仅为理论值,实际应用中,不同的业务类型需要收发的数据大小不同,所需的内存也不同。
所有不以业务为导向的理论都是耍流氓!
Linux系统的文件打开数
在Linux中,文件描述符用于标识已打开的文件,而socket连接也被视为文件。因此,MySQL连接数还受系统能打开的最大文件数限制。
系统级别的文件数限制
fs.file-max:系统级别能打开的最大文件数。可以通过调整这个参数来扩大系统的文件打开数上限。
fs.nr_open:控制整个 Linux 系统中 单个进程 可以打开的文件描述符(file descriptors, FD)总数上限。也就是说,它设置了一个进程能打开的文件数量的绝对上限。
进程级别的文件数限制
soft nofile: 表示用户可以在正常情况下打开的最大文件数。
hard nofile:表示可以提升 soft nofile
到的最大值,即用户进程能打开的文件数硬性上限,用户不能自行超越 hard nofile
,但可以通过管理员权限调整。
这几个参数相互耦合,调整时需要注意:
soft nofile不能超过hard nofile,否则实际生效值会按照两者中的较小值来确定。
hard nofile必须小于fs.nr_open,否则可能导致用户无法登录。
配置文件调整
假设我们需要让进程支持100万连接,可以通过以下配置文件来调整:
vim /etc/sysctl.conf
fs.file-max=1100000 # 系统级别设置成110万,多留点buffer
fs.nr_open=1100000 # 进程级别也设置成110万,因为要保证比 hard nofile大
以上配置生效: /etc/sysctl -p
vim /etc/security/limits.conf
# 用户进程级别都设置成100万
soft nofile 1000000
hard nofile 1000000
示例
通过一个具体的示例再详细说明一下
内存分配策略
InnoDB缓冲池
由于MySQL的InnoDB引擎对缓冲池的依赖较大,建议将内存的60-70%分配给InnoDB缓冲池。
对于128G内存的服务器,预留70%内存给缓冲池:
innodb_buffer_pool_size = 128G * 0.7 = 89.6G
系统预留内存
通常需要预留10-20%的内存给操作系统以及其他服务
我们选择预留15%:
128G * 0.15 = 19.2G
MySQL线程
剩余内存分配给MySQL线程
128G - 89.6G - 19.2G = 19.2G
MySQL每个连接的内存消耗
假设每个MySQL连接的内存消耗主要来源于以下几个配置项:
(参数设置偏低,实际应用中会有差别)
thread_stack = 256K
sort_buffer_size = 2M
read_buffer_size = 1M
read_rnd_buffer_size = 512K
join_buffer_size = 1M
tmp_table_size = 16M
每个连接的总内存消耗为:
thread_stack + sort_buffer_size + read_buffer_size + read_rnd_buffer_size + join_buffer_size + tmp_table_size
= 256K + 2M + 1M + 512K + 1M + 16M
≈ 20M
每个连接大约消耗20MB的内存。
计算可支持的MySQL连接数
在128GB内存的服务器上,MySQL线程可使用的总内存为19.2GB,因此可支撑的连接数为:
可支持的连接数 = 可用内存 / 每个连接的内存消耗
= 19.2G / 20M
≈ 960 个连接
因此,在没有其他额外负载的情况下,这台128GB内存的服务器大约可以支撑960个并发MySQL连接。(这其实还是一个理论值,因为参数设置相对较低)
考虑文件描述符和TCP连接限制
文件描述符限制
每个MySQL连接都会占用一个文件描述符,假设系统的文件描述符限制足够高(如上设置为100万),不会成为瓶颈。
TCP连接数限制
Linux系统的TCP连接数通常不会成为瓶颈,但仍需要确保系统配置足够:
net.ipv4.ip_local_port_range = 1024 65535 #端口号
net.core.somaxconn = 1024 # 增加全连接队列长度
示例总结
这台128GB内存的Linux服务器,通过合理分配内存资源(例如InnoDB缓冲池和系统预留),可以大约支撑960个并发MySQL连接。这还是一个基于简单应用的理论值,实际项目过程中比这个值要少,还是要通过压力测试再进一步的接近实际值。
掌握了解决这个问题的思路即可,不需要过分纠结的具体数字,实际应用中很难预估的很准确。
【以上仅为个人观点,如有不同意见,欢迎留言讨论!】
点击蓝字 关注我们