4.3 并发与连接参数


4.3 并发与连接参数

本节摘要:高并发下连接和线程管理决定吞吐。本节讲清楚最大连接数、连接池、线程缓存、超时参数,让数据库扛住并发。

连接管理基础

每个数据库连接占用内存和线程。连接太多——内存爆、上下文切换多、锁竞争。连接太少——请求排队等待。

调优目标:

  • 足够连接扛并发。
  • 不超数据库和系统承载。
  • 连接复用(连接池)减少创建开销。

最大连接数

MySQL max_connections

  • 默认 151,生产调到 500-5000(按并发需求)。
  • 每连接内存——约 1-10MB(线程栈+排序缓冲等),5000 连接可能占 5-50GB。
  • 设太高——内存爆、上下文切换多。设太低——请求等待。
  • 配合应用连接池——应用池限连接,DB max_connections 略高于应用池总和。

PostgreSQL max_connections

  • 默认 100,生产调到 200-1000。
  • PG 每连接 fork 进程(重),高连接用连接池(PgBouncer)。
  • PG 推荐用连接池而非直接加 max_connections——PgBouncer 复用连接,DB 连接少。

原则:DB 连接数不要太高(几百到几千),高并发用连接池复用。每连接占内存,连接数 × 每连接内存 < 物理内存。

连接池

应用层连接池

  • HikariCP(Java)、SQLAlchemy pool(Python)、DBCP(Java)。
  • 复用连接——避免每请求创建/销毁(TCP+认证开销)。
  • 配置:最小空闲、最大连接、超时、空闲回收。
  • 大小——按并发和查询耗时算,不是越大越好(连接多则 DB 压力大)。

数据库层连接池

  • PgBouncer(PG):复用 DB 连接,应用多但 DB 连接少。
  • MySQL:应用层连接池为主,ProxySQL 代理池。
  • Oracle:Shared Server 模式。

连接池大小估算

  • 公式:连接数 = (核心数 × 2) + 有效磁盘数。
  • 或按并发请求 × 查询耗时(秒)算。
  • 通常 10-50 个连接池够多数应用,不是几百。

线程缓存

MySQL thread_cache_size

  • 缓存空闲线程,新连接复用而非创建。
  • 调大减少线程创建开销。
  • 监控 Threads_created(应接近 0,高则缓存不够)。

PostgreSQL

  • 无线程缓存(每连接进程),用 PgBouncer 复用。

超时参数

连接超时

  • wait_timeout/interactive_timeout(MySQL):空闲连接超时断开。默认 28800s(8 小时),调短(如 600-3600s)回收空闲连接。
  • idle_timeout(PG/PgBouncer):空闲连接回收。

查询超时

  • max_execution_time(MySQL 8.0):查询执行超时(毫秒)。
  • statement_timeout(PG):查询超时。
  • 设合理值——防慢查询拖垮,但别太短误杀长查询。

锁等待超时

  • innodb_lock_wait_timeout(MySQL):行锁等待超时(秒,默认 50)。
  • lock_timeout(PG):锁等待超时。
  • 调短——快速失败重试,避免长时间等待。

连接建立超时

  • connect_timeout:建立连接超时(秒)。
  • 调短——快速失败,避免堆积。

并发控制

innodb_thread_concurrency:InnoDB 内部并发线程数。

  • 0:不限(8.0 默认,靠 OS 调度)。
  • N:限并发,超则等待。
  • 通常设 0(默认),高并发可设核心数 × 2-8 测试。

innodb_concurrency_tickets:线程进入 InnoDB 后的"票数",用完才让其他。

  • 默认 5000,通常不动。

PG max_worker_processes:最大工作进程数。

  • 包括后台 worker(并行查询、autovacuum)。
  • 按核心数和并行需求调。

并发监控

  • 连接数:当前连接数 vs max_connections,接近上限要扩容或限流。
  • 等待连接:show processlist 中 Sleep 连接多——空闲多,调超时回收。
  • 线程创建:Threads_created 高——thread_cache 不够。
  • 锁等待:锁等待多——并发冲突,调隔离级别或优化查询。

⚠️ 常见误读:以为"连接越多越好"。每连接占内存,连接太多内存爆、上下文切换多、锁竞争。用连接池复用,DB 连接数适中(几百到几千),高并发靠连接池而非堆连接。

💡 关键直觉:连接管理——每连接占内存和线程,太多内存爆/上下文切换/锁竞争,太少请求等待。max_connections(MySQL 默认 151 调 500-5000,PG 默认 100 调 200-1000,每连接 1-10MB 算总内存)。连接池(应用 HikariCP/SQLAlchemy pool 复用避免创建开销,DB 层 PgBouncer PG 复用,大小 10-50 够多数按核心数×2+磁盘数算不是几百)。线程缓存(thread_cache_size 缓存空闲线程,监控 Threads_created 接近 0)。超时(wait_timeout 空闲 600-3600s 回收、max_execution_time/statement_timeout 查询超时防慢查询、innodb_lock_wait_timeout 锁等待调短快速失败、connect_timeout 建立超时调短)。并发控制(thread_concurrency 0 不限默认/max_worker_processes 按核心数)。监控连接数(接近上限扩容/限流)、Sleep 连接(调超时回收)、Threads_created(缓存不够)、锁等待(调隔离/优化查询)。

并发调优要点

  • 连接管理:每连接占内存和线程,太多内存爆/上下文切换/锁竞争,太少请求等待。目标足够连接、不超承载、连接复用。
  • max_connections:MySQL 默认 151 调 500-5000,PG 默认 100 调 200-1000。每连接 1-10MB,5000 连接占 5-50GB。设太高内存爆,太低请求等待。配合应用连接池,DB 略高于应用池总和。
  • 连接池:应用层(HikariCP/SQLAlchemy pool/DBCP 复用避免 TCP+认证开销,配置最小空闲/最大/超时/回收),DB 层(PgBouncer PG 复用 DB 连接少,ProxySQL MySQL,Oracle Shared Server)。大小估算(核心数×2+磁盘数,或并发×耗时,通常 10-50 够不是几百)。
  • 线程缓存:thread_cache_size 缓存空闲线程复用,监控 Threads_created 接近 0(高则缓存不够)。PG 无线程缓存用 PgBouncer。
  • 超时参数:wait_timeout/interactive_timeout 空闲超时(默认 8 小时调 600-3600s 回收)、max_execution_time/statement_timeout 查询超时防慢查询拖垮、innodb_lock_wait_timeout/lock_timeout 锁等待调短快速失败重试、connect_timeout 建立超时调短避免堆积。
  • 并发控制:innodb_thread_concurrency(0 不限 8.0 默认/N 限并发)、innodb_concurrency_tickets(5000 默认)、PG max_worker_processes(按核心数和并行)。
  • 监控:连接数(接近 max 扩容/限流)、Sleep 连接多(调超时回收)、Threads_created 高(thread_cache 不够)、锁等待多(调隔离/优化查询)。

连接数调优的排队论直觉

连接与并发参数的调优,底层是排队论直觉:数据库的有效并发度由 CPU 核数与 IO 并行度决定(通常就是"核数的两倍上下"这个量级),超出部分的连接不会增加吞吐,只会增加排队与上下文切换。由此得出一个反直觉的结论:连接上限不是越大越好——两千个连接抢十六个核,每个查询的等待时间暴涨,表现为"全员都慢";把连接上限压到一百,反而"排队的有先来后到、执行的不互相踩踏",P99 时延通常显著下降。这个现象的工程版本就是连接池的"小雨伞悖论":把伞收小一点,淋雨的人反而干得快。调优动作因此很清晰:压测找出吞吐拐点的并发数,把应用侧连接池上限设为拐点附近,数据库侧的总连接配额设为各池之和加管理预留;同时在数据库层开启资源队列或语句超时,防止慢查询占着连接堵塞全局。连接治理是投入产出比最高的参数调优之一,因为它不需要任何硬件投入,只需要对抗"多留些连接总没错"的直觉。

语句超时与资源队列的分层防线

连接治理之外,并发控制还有两道分层防线值得建立。防线一,语句超时:给每类语句设分级超时(在线查询五秒、后台任务五分钟),超时快速失败——它的价值不在"杀掉慢查询"而在"阻止慢查询的连锁伤害"(占连接、堵锁、拖垮全家);超时值要与重试策略配套(幂等查询可自动重试一次,写操作转人工确认)。防线二,资源队列(或资源组):把不同业务的工作负载分池管理——在线查询池保底资源、报表池限额排队、批处理池错峰运行;负载隔离让"报表拖垮交易"的经典事故从物理上不可能。两道防线的组合达成一个理想的稳态:任何一类负载的失控都被限制在自己的配额内烧,系统的其余部分照常服务——这是并发调优的终极目标,"让风暴过境时只有风暴区下雨"。

并发压测的阶梯协议

连接与并发参数的校准有个标准协议——阶梯压测。协议设计:并发数从连接上限的五分之一起步,每级增加四分之一,每级稳定运行十分钟以上(跳过预热期再取数),记录吞吐、P99、错误率三线。曲线解读:吞吐随并发上升至某点后走平(拐点),P99 在拐点后开始爬升(排队显现),错误率若在拐点前就出现说明有资源外的瓶颈(锁等待超时、应用线程不足)——三线的拐点就是系统的健康并发上限。参数落地:连接池上限设在拐点的九成,数据库总连接配额覆盖各池之和加管理余量;语句超时按 P99 的三到五倍设置(低于它误杀正常请求,高于它失去保护意义)。复测节奏:每次大版本、大流量结构变化后重跑——并发上限是活的数据,不是刻在石头上的配置。这套协议两小时跑完,是并发参数从"听说的值"变成"自己的值"的唯一路径。

连接治理的三个现场数字

并发章收官给三个现场数字的解读心法。数字一,等待连接数(排队等池的请求数):常态非零且平稳=池略小但健康;持续增长=池或库到瓶颈,结合第 4 章拐点判断是扩池还是治慢查询——扩池前先杀慢,否则扩的是拥堵路段的入口。数字二,活跃连接的运行时长分布:长尾(活跃超过十秒的连接数)非零=慢查询在占座,是语句层的病人;平均运行时长稳定=系统健康。数字三,连接风暴的峰值速率(每秒新建连接数):周期性尖峰=应用的重连风暴(超时后无退避的集体重连),配指数退避比扩任何参数都有效。三个数字五分钟一屏看完,连接层的健康度尽收眼底——监控不是越多越好,是每个指标都要配"看到什么做什么"的解读卡,这三张卡先立起来。

最后补一句与超时的联动:连接治理做完后,把应用侧的请求超时、重试退避与数据库侧的语句超时做一次对齐(三层超时的数值关系要成体系:请求超时大于语句超时、重试有指数退避)——三层各设各的是多数事故的温床,一次对齐会,全年安稳。

补一个多应用共享库的治理要点:不同应用混用一个库时,连接配额要按应用分账(每应用一个池、总配额封顶),并给关键应用保底配额——没有分账的共享库里,一个应用的连接风暴会淹没全部租户;分账后风暴至少只烧自己的配额。再配一个"配额使用率"的按应用视图,容量谈判与异常定位都有了数据基础。这是并发治理在多租户场景的自然延伸,也是很多"共享库为什么总出事"的根因所在——不是数据库不行,是没有人管秩序。

最后补一个容量视角:连接数的长期趋势也要进容量规划——应用每加一个模块、每个模块各带一个池,总连接就悄悄上涨;半年回顾一次"连接数增长与实例资源"的匹配度,防止"每个池都不大、加起来撑爆库"的温水事故。连接是数据库最便宜的资源和最容易被忽视的资源之间的那个交集,管它的诀窍就是记总账。

最后留一道思考题:如果你的系统明早流量涨五倍,连接层会先在哪里断裂——池上限、库的总配额、还是应用线程数?三个候选答案对应三个不同的扩容准备;现在就把答案写进容量档案,涨潮那天你就不用现场推导。并发管理的成熟度,最终就体现在这些提前写好的答案里。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U