服务器与大带宽专家 · 持牌IDC/CDN/ISP服务商
简米科技官网JIANMI TECH
资讯 2026-08-30 更新于 2026-08-30 简米科技 4,156 字 10 分钟阅读

在线事务写放大与存储块大小有何关系?底层存储参数调优

导读块越大,小写入的放大效应越明显,而OLTP场景恰恰以大量小写入为主,在线事务处理,也就是常说的OLTP,它的写特征非常鲜明:高频、小粒度、随机,比如一条订单更新、一次账户扣款,实际落盘的数据可能只有几百字节,但存储设备并不是按“字节”工作的,它有自己的物理块大小,比如4KB、8KB甚至更大,这就产生了一个矛盾……

块越大,小写入的放大效应越明显,而OLTP场景恰恰以大量小写入为主。

在线事务处理,也就是常说的OLTP,它的写特征非常鲜明:高频、小粒度、随机,比如一条订单更新、一次账户扣款,实际落盘的数据可能只有几百字节,但存储设备并不是按“字节”工作的,它有自己的物理块大小,比如4KB、8KB甚至更大,这就产生了一个矛盾你只想改一条记录,存储却必须把包含这条记录的整个块重新写一遍,块越大,额外重写的无效数据就越多,写放大系数自然就上去了。

块大小如何精准“放大”你的每次写入

写放大不是一个抽象概念,它有明确的数学含义,业内共识认为,写放大系数等于实际写入存储介质的物理数据量,除以应用程序请求的逻辑数据量,在线事务里,这个系数经常能到几十甚至上百,根源就在于块大小和请求粒度的错配。

一个典型的在线事务写入路径

以MySQL InnoDB为例,一条UPDATE语句要走完整个链路:

  • 先更新缓冲池中的数据页,标记为脏页
  • redo log顺序写入日志文件(这块通常较小,但也要刷盘)
  • 后台线程将脏页刷盘,刷盘单位是数据页,默认16KB
  • 存储引擎又把这些数据页拆分成块,交给文件系统和SSD控制器

问题出在最后两步,InnoDB的页是16KB,但底层SSD的物理页常见的是4KB或8KB,文件系统块可能是4KB,如果你只改了16KB页里的几百字节,刷盘时整个16KB页都得写,而SSD内部因为要维护映射关系,擦写单元又是更大的块(常见数百KB到数MB),于是16KB又会被放大到更大的物理写,这就是在线事务写放大为什么难以压低的直接原因。

分场景对比:块大小对不同写模式的影响

场景 逻辑写入量 块大小4KB 块大小16KB 块大小64KB
单条记录更新(200B) 2KB 放大20倍 放大80倍 放大320倍
批量插入(每行1KB,连续) 10KB 放大2.5倍 放大1.6倍 放大1.25倍
日志追加写(顺序) 100KB 接近1倍 接近1倍 接近1倍

从上表能看出,顺序写几乎不放大,随机小写则块越大越吃亏,在线事务绝大多数都是随机小写,这就是为什么OLTP数据库存储性能优化必须盯着块大小。

在线事务写放大和块大小有什么关系?实战层面更复杂

在线事务写放大与存储块大小有何关系?底层存储参数调优

很多人在讨论“在线事务写放大和块大小有什么关系”时,只盯着SSD的物理页,但真实的存储栈里一共有三层块大小在叠加:数据库页大小、文件系统块大小、SSD物理页/擦除块。

三层块大小协同不当的放大案例

假设你有一个PostgreSQL数据库,默认页面大小是8KB,文件系统用ext4,默认块大小也是4KB,SSD的物理页是8KB,但擦除块是2MB,那么一次逻辑写入8KB页:

  • 存储引擎把8KB页传给文件系统
  • 文件系统将其切分为两个4KB块,但因为是随机写,可能分布在不同的SSD页上
  • SSD控制器要把两个4KB逻辑块分别映射到两个物理页,但物理页的最小操作单位是8KB,于是每个4KB都要写一个完整的8KB物理页
  • 最终实际写了16KB,写放大已经到2倍,再加上垃圾回收时的搬移,放大进一步恶化

这个例子说明,只降低某一层块大小并不能根治问题,MySQL数据库块大小怎么选,必须同时考虑文件系统和对齐方式。

实操:检查当前环境的块大小对齐情况

你可以通过以下命令查看关键参数:

# 查看文件系统块大小
stat -f /var/lib/mysql
# 查看SSD物理扇区大小(很多SSD是4K扇区)
cat /sys/block/sda/queue/hw_sector_size
# 查看MD RAID条带大小(如果有做阵列)
cat /sys/block/md0/queue/md/stripe_size
# 查看io_uring或者libaio的对齐限制
blockdev --getiomaxsz /dev/sda

对齐的核心原则是:文件系统块大小和SSD物理页大小取交集,数据库页大小最好是文件系统块大小的整数倍,并且起始偏移要落在SSD物理页边界上,实操中,很多人在创建分区时没有使用parted的align-check,导致数据库数据文件起始位置没有对齐,每次写入都会跨两个物理页,写放大直接翻倍。

在线事务场景下如何合理选择存储块大小

选择块大小不是越大越好,也不是越小越好,在线事务追求低延迟和高并发,需要在写放大和空间利用率之间做平衡。

从工作负载特征出发

  • 只读和读多写少:块大有利于顺序预读,放大问题不突出,但写放大依然存在,只是频率低,影响小。
  • 纯写入型(日志、监控):本来就是顺序追加,块大反而有利,因为减少了元数据开销。
  • 典型的在线事务(订单、支付、库存):随机小写占比高,块越小放大越低,但块太小会导致映射表过大和IOPS浪费,实测经验是SSD物理页4KB时,数据库页8KB或16KB都算合理。
  • 在线事务写放大与存储块大小有何关系?底层存储参数调优

数据库层面的调整建议

多数数据库不允许随意修改页大小,比如MySQL InnoDB默认16KB,但你可以通过配置来减少写放大:

  • 调整innodb_page_size(仅初始化时生效),OLTP场景可设为8KB,配合4KB SSD物理页,写放大能下降不少,但要注意,页变小会让B+树层级变高,可能增加查询IO次数。
  • 把redo log放在独立的、块大小更小的存储上(比如单条SSD分区单独格式化),避免和数据文件共享块。
  • 调整innodb_flush_neighbors为0,避免因为相邻脏页导致整块刷写,这在SSD上尤其重要,因为机械盘时代为了减少寻道才喜欢连带刷邻页。

如果你正在纠结“在线事务数据库块大小选择”,可以遵循以下决策路径:

  • 先看存储器的物理页大小,通过nvme id-ns /dev/nvme0n1查看
  • 再决定文件系统块大小,格式化为与物理页一致或整数倍
  • 最后确认数据库页大小与文件系统块大小的关系,避免页被切成不完整的块

测试验证:如何量化写放大改善

修改配置前,建议用iostatperf做基线记录:

# 采集写入字节数
iostat -xk 1 | awk '{print $7}' | tail -n +3
# 使用blktrace跟踪写请求大小分布
blktrace -d /dev/sda -o - | blkparse -i -

跑一个标准OLTP负载(比如sysbench的oltp_update_non_index),记录每秒实际物理写入量除以数据库逻辑写入量,对比调整前后的比值,多数情况下,把文件系统块从4KB换到8KB并让InnoDB页对齐,写放大系数能下降30%-50%(基于常见SSD环境的公开测试经验,非精确数字)。

纠偏:别让“块越大性能越好”的说法误导你

有一种流行观点认为,SSD的块越大,顺序写入吞吐越高,所以应该用大块,这句话在纯顺序写场景是对的,但放在在线事务里就是灾难,因为在线事务的日志也是顺序写,但数据文件是随机写,你需要把两者分开看。

日志和数据文件的差异

  • 日志(redo log、binlog、WAL):天然顺序追加,块大有利于减少元数据更新,写放大接近1,所以可以放在大块分区。
  • 数据文件:随机小写为主,块小才是解药,有经验的DBA会把日志和数据文件放在不同的磁盘或分区上,并且分别设置块大小。

这个思路在很多云数据库实例上也能看到:通用型实例使用常规4KB格式化,高IO型实例会专门优化对齐,如果你在做存储选型,问一下云厂商“底层SSD物理页多大,文件系统块多大”,这比只看IOPS数字更有意义。

在线事务写放大与存储块大小有何关系?底层存储参数调优

关于压缩和块大小的关系

还有一层需要提:在线事务数据若启用透明压缩(如MySQL的页压缩、文件系统压缩),块大小的影响会进一步变化,压缩后的数据块实际落盘变小,但存储的最小操作单位不变,比如你压缩后一个页只剩2KB,但SSD物理页是4KB,依然要写4KB,放大依然存在,所以块大小的最优解必须结合压缩率来评估,压缩率高的场景可适当增大块大小,减少映射开销。

常见问答:在线事务写放大与块大小的定量理解

在线事务写放大和块大小有什么关系,能不能一概而论?

不能,关系必须分三层看:数据库页、文件系统块、SSD物理页,一个80字节的更新,如果三层大小全部完美对齐(比如数据库页4KB、文件系统块4KB、SSD物理页4KB),写放大是1;如果数据库页16KB、文件系统块4KB、SSD物理页16KB,放大可能到4倍甚至更高,关键不在于哪一层单独多大,而在于它们之间的整除和对齐关系。

MySQL数据库块大小怎么选才算合理?

先确定底层存储的物理页大小,现在主流企业级SSD的物理页多为4KB,建议文件系统块设为4KB或8KB,InnoDB页面保持默认16KB即可,但必须确保分区起始位置对齐,如果你的负载有大量小于2KB的点更新,且存储支持4KB页,可考虑初始化数据库时将innodb_page_size设为8KB,配合4KB文件系统块,注意修改页大小要重建实例,务必提前做全量备份。

用了高性价比的SATA SSD,需要降低文件系统块大小吗?

SATA SSD的物理页同样常见4KB,但无缓存写入敏感性高,降低块大小有助于减少写放大,但同时会增加IOPS压力,如果SSD的随机写IOPS本身不高(比如入门级产品),更建议用8KB块合并部分小写,靠驱动层的间接缓冲来换取吞吐,真正的瓶颈往往在队列深度不足,调整块大小不如适当增加nr_requestsio scheduler参数。

回到根本,在线事务的写放大不是某个组件单独造成的,而是整个存储栈的“块契约”不匹配,写放大无处不在,但你可以通过控制每一层块大小的关系,把放大幅度压到最低,记住一句话:块大小对齐,写放大归位;块大小错配,性能白费。 实际操作中,先用命令查清三层大小,再做一次调整前后的对比测试,比任何理论都更有说服力。

分享本文
本文为 简米科技官网 原创,已由运维技术专家审核。转载请注明来源:原文链接
售前咨询 服务热线 售后 邮箱