本节摘要:高并发下连接和线程管理决定吞吐。本节讲清楚最大连接数、连接池、线程缓存、超时参数,让数据库扛住并发。
每个数据库连接占用内存和线程。连接太多——内存爆、上下文切换多、锁竞争。连接太少——请求排队等待。
调优目标:
MySQL max_connections:
PostgreSQL max_connections:
原则:DB 连接数不要太高(几百到几千),高并发用连接池复用。每连接占内存,连接数 × 每连接内存 < 物理内存。
应用层连接池:
数据库层连接池:
连接池大小估算:
MySQL thread_cache_size:
PostgreSQL:
连接超时:
查询超时:
锁等待超时:
连接建立超时:
innodb_thread_concurrency:InnoDB 内部并发线程数。
innodb_concurrency_tickets:线程进入 InnoDB 后的"票数",用完才让其他。
PG max_worker_processes:最大工作进程数。
⚠️ 常见误读:以为"连接越多越好"。每连接占内存,连接太多内存爆、上下文切换多、锁竞争。用连接池复用,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(缓存不够)、锁等待(调隔离/优化查询)。
连接与并发参数的调优,底层是排队论直觉:数据库的有效并发度由 CPU 核数与 IO 并行度决定(通常就是"核数的两倍上下"这个量级),超出部分的连接不会增加吞吐,只会增加排队与上下文切换。由此得出一个反直觉的结论:连接上限不是越大越好——两千个连接抢十六个核,每个查询的等待时间暴涨,表现为"全员都慢";把连接上限压到一百,反而"排队的有先来后到、执行的不互相踩踏",P99 时延通常显著下降。这个现象的工程版本就是连接池的"小雨伞悖论":把伞收小一点,淋雨的人反而干得快。调优动作因此很清晰:压测找出吞吐拐点的并发数,把应用侧连接池上限设为拐点附近,数据库侧的总连接配额设为各池之和加管理预留;同时在数据库层开启资源队列或语句超时,防止慢查询占着连接堵塞全局。连接治理是投入产出比最高的参数调优之一,因为它不需要任何硬件投入,只需要对抗"多留些连接总没错"的直觉。
连接治理之外,并发控制还有两道分层防线值得建立。防线一,语句超时:给每类语句设分级超时(在线查询五秒、后台任务五分钟),超时快速失败——它的价值不在"杀掉慢查询"而在"阻止慢查询的连锁伤害"(占连接、堵锁、拖垮全家);超时值要与重试策略配套(幂等查询可自动重试一次,写操作转人工确认)。防线二,资源队列(或资源组):把不同业务的工作负载分池管理——在线查询池保底资源、报表池限额排队、批处理池错峰运行;负载隔离让"报表拖垮交易"的经典事故从物理上不可能。两道防线的组合达成一个理想的稳态:任何一类负载的失控都被限制在自己的配额内烧,系统的其余部分照常服务——这是并发调优的终极目标,"让风暴过境时只有风暴区下雨"。
连接与并发参数的校准有个标准协议——阶梯压测。协议设计:并发数从连接上限的五分之一起步,每级增加四分之一,每级稳定运行十分钟以上(跳过预热期再取数),记录吞吐、P99、错误率三线。曲线解读:吞吐随并发上升至某点后走平(拐点),P99 在拐点后开始爬升(排队显现),错误率若在拐点前就出现说明有资源外的瓶颈(锁等待超时、应用线程不足)——三线的拐点就是系统的健康并发上限。参数落地:连接池上限设在拐点的九成,数据库总连接配额覆盖各池之和加管理余量;语句超时按 P99 的三到五倍设置(低于它误杀正常请求,高于它失去保护意义)。复测节奏:每次大版本、大流量结构变化后重跑——并发上限是活的数据,不是刻在石头上的配置。这套协议两小时跑完,是并发参数从"听说的值"变成"自己的值"的唯一路径。
并发章收官给三个现场数字的解读心法。数字一,等待连接数(排队等池的请求数):常态非零且平稳=池略小但健康;持续增长=池或库到瓶颈,结合第 4 章拐点判断是扩池还是治慢查询——扩池前先杀慢,否则扩的是拥堵路段的入口。数字二,活跃连接的运行时长分布:长尾(活跃超过十秒的连接数)非零=慢查询在占座,是语句层的病人;平均运行时长稳定=系统健康。数字三,连接风暴的峰值速率(每秒新建连接数):周期性尖峰=应用的重连风暴(超时后无退避的集体重连),配指数退避比扩任何参数都有效。三个数字五分钟一屏看完,连接层的健康度尽收眼底——监控不是越多越好,是每个指标都要配"看到什么做什么"的解读卡,这三张卡先立起来。
最后补一句与超时的联动:连接治理做完后,把应用侧的请求超时、重试退避与数据库侧的语句超时做一次对齐(三层超时的数值关系要成体系:请求超时大于语句超时、重试有指数退避)——三层各设各的是多数事故的温床,一次对齐会,全年安稳。
补一个多应用共享库的治理要点:不同应用混用一个库时,连接配额要按应用分账(每应用一个池、总配额封顶),并给关键应用保底配额——没有分账的共享库里,一个应用的连接风暴会淹没全部租户;分账后风暴至少只烧自己的配额。再配一个"配额使用率"的按应用视图,容量谈判与异常定位都有了数据基础。这是并发治理在多租户场景的自然延伸,也是很多"共享库为什么总出事"的根因所在——不是数据库不行,是没有人管秩序。
最后补一个容量视角:连接数的长期趋势也要进容量规划——应用每加一个模块、每个模块各带一个池,总连接就悄悄上涨;半年回顾一次"连接数增长与实例资源"的匹配度,防止"每个池都不大、加起来撑爆库"的温水事故。连接是数据库最便宜的资源和最容易被忽视的资源之间的那个交集,管它的诀窍就是记总账。
最后留一道思考题:如果你的系统明早流量涨五倍,连接层会先在哪里断裂——池上限、库的总配额、还是应用线程数?三个候选答案对应三个不同的扩容准备;现在就把答案写进容量档案,涨潮那天你就不用现场推导。并发管理的成熟度,最终就体现在这些提前写好的答案里。