块越大,小写入的放大效应越明显,而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查看 - 再决定文件系统块大小,格式化为与物理页一致或整数倍
- 最后确认数据库页大小与文件系统块大小的关系,避免页被切成不完整的块
测试验证:如何量化写放大改善
修改配置前,建议用iostat和perf做基线记录:
# 采集写入字节数
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_requests和io scheduler参数。
回到根本,在线事务的写放大不是某个组件单独造成的,而是整个存储栈的“块契约”不匹配,写放大无处不在,但你可以通过控制每一层块大小的关系,把放大幅度压到最低,记住一句话:块大小对齐,写放大归位;块大小错配,性能白费。 实际操作中,先用命令查清三层大小,再做一次调整前后的对比测试,比任何理论都更有说服力。