Linux 下数据库服务器的内核参数调优
Linux 下数据库服务器的内核参数调优一、具体的问题
很多 DBA 把数据库装好、参数配完,一压测或一上量就出问题:连接数一高客户端报"连接超时 / connection reset",监控里看到数据库进程被系统杀掉(OOM),或者写入跑一会儿就变卡。这些问题往往不在数据库本身,而在宿主 Linux 的内核参数还停留在发行版默认值——那是给桌面或通用服务器准备的,根本没为"大内存、高并发、长连接"的数据库场景优化。本文聚焦三个最常被忽略、也最致命的点:内存交换、TCP 积压队列、文件句柄上限,把它们一次调对。
二、核心原理
1. 交换(swap)不是数据库的 friend
Linux 默认 vm.swappiness=60,意思是内存用到 40% 就可能开始把页换到磁盘。对数据库而言,一旦热点数据页被换出去,一次查询就可能从内存变成磁盘 IO,延迟从微秒级飙到毫秒级。更要命的是,数据库自己有 buffer pool / SGA 做缓存,操作系统再缓存一份纯属浪费,还会增加被 OOM killer 选中的风险。所以专用数据库机通常把 swappiness 调到 1~10,或干脆 1(保留最小交换能力用于应急,而不是拿来当缓存)。
2. TCP 全连接队列太短,高并发直接丢连接
数据库监听端口(如 3306 / 5432 / 1521)的"全连接队列"长度由 net.core.somaxconn 和数据库自身 backlog 共同决定,取两者较小值。很多发行版 somaxconn 默认只有 128,瞬时建连稍多,队列溢出,客户端就收到 connection reset。同理 net.ipv4.tcp_max_syn_backlog 控制半连接队列,也需要调大。
3. 文件句柄耗尽,连接 / 日志全开不了
一个连接、一个数据文件、一个日志文件都占一个 fd。高并发下默认 ulimit -n(常 1024)很快用光,报错 "Too many open files"。需要同时调系统级 fs.file-max 和进程级 nofile。Oracle 这类还额外吃信号量(kernel.sem),漏了会在启动时报错。
4. 脏页回写策略影响写入抖动
vm.dirty_ratio / dirty_background_ratio 决定多少脏数据堆在内存里才触发回写。默认值偏大,会造成"平时不写、攒一波集中刷盘"的写入尖刺。把 dirty_background_ratio 调小(如 5)、dirty_ratio 调小(如 10),让回写更平滑,避免批量落盘时把前台查询拖垮。
三、实例参考(动手步骤)
下面以一台 64G 内存、跑 PostgreSQL 的 CentOS 为例,给出可照做的调优与前后对比。
1) 先看清当前值:
sysctl vm.swappiness net.core.somaxconn net.ipv4.tcp_max_syn_backlog fs.file-max
ulimit -n
2) 写入 /etc/sysctl.d/99-db.conf:
vm.swappiness = 1
vm.dirty_background_ratio = 5
vm.dirty_ratio = 10
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
fs.file-max = 1000000
执行 sysctl -p 使生效(无需重启)。
3) 进程级句柄上限,改 /etc/security/limits.conf 给数据库运行用户加:
postgres soft nofile 65535
postgres hard nofile 65535
改完需重新登录 / 重启服务才生效,用 su - postgres -c 'ulimit -n' 验证已变成 65535。
4) 前后对比:调优前用 pgbench 跑 200 并发连接,连接失败率约 6%、P99 延迟 800ms 且有尖刺;调优后失败率 0%、P99 降到 120ms,且 grep -i oom /var/log/messages 不再出现数据库进程被杀记录。可用 sar -B 1 观察 pgpgin/pgpgout(换页)几乎归零,证明 swappiness 生效。
四、实操检查清单
[*]专用数据库机是否把 vm.swappiness 降到 1~10,避免热点数据被换到磁盘?
[*]net.core.somaxconn 与 tcp_max_syn_backlog 是否调到 65535 量级,覆盖峰值建连?
[*]系统 fs.file-max 与数据库运行用户的 nofile(soft / hard)是否都放宽到 65535 以上?
[*]vm.dirty_background_ratio / dirty_ratio 是否调小,写入回写是否更平滑、无尖刺?
[*]Oracle 等是否额外调了 kernel.sem(信号量),启动有无报错?
[*]每次改动后是否用 sysctl -p 即时生效,并重开会话验证 ulimit -n 已更新?
[*]调优前后是否用压测工具对比过连接失败率与 P99 延迟,确认确有改善?
[*]是否把这些参数固化进配置文件(sysctl.d / limits.conf),避免重启后回退?
页:
[1]