change buffer 是什么:写多读少场景的免费午餐
接手了一套埋点日志库,写入量每天 2 亿条,表上有十几个二级索引,磁盘 IO 长期高位。查了一圈资料,把目光落在 change buffer 上——一个很多人听过名字但说不清原理的机制。调大它之后写入吞吐提升了 25%,没改一行业务代码。
原理拆开讲不复杂。InnoDB 写入时要维护所有索引,如果目标二级索引页恰好在 buffer pool 里,直接改内存完事;但如果页不在内存(大表随机写时很常见),默认做法是从磁盘把页读进来再改,一次随机读就这样产生了。change buffer 的思路是:先把这笔修改记在 change buffer 里就返回,等将来这个页因为查询被读进内存、或者后台线程合并时,再把攒下的修改一次性应用。写的时候跳过了磁盘读,等于把随机读 IO 延后并合并了。
它有几个明确的边界。第一,只对非唯一的二级索引生效,唯一索引插入前必须读页判重,绕不开那次读。第二,收益取决于"写了但不马上读"的比例,埋点、日志这类 append 多、查询少的场景收益最大;如果写完马上要读,change buffer 里攒的修改立刻要合并,反而多一跳。第三,它占用 buffer pool 的空间,上限由 innodb_change_buffer_max_size 控制,默认 25%,我们调到了 50%。
判断生效程度看两个地方:SHOW ENGINE INNODB STATUS 里 INSERT BUFFER AND ADAPTIVE HASH INDEX 一节,有 merges、merged operations 的累计值,IOPS 高压时段 merged operations 持续增长说明在干活;也可以观察 information_schema.innodb_buffer_page 里 IBUF 类型的页占比。
最后给个判断口诀:SHOW ENGINE INNODB STATUS 里 merged operations 的增长速度,除以同期的二级索引写次数,就是 change buffer 的实际吸收率。我们那套日志库吸收率 62%,意思是近三分之二的二级索引写没触发磁盘读。低于 20% 就别调了,说明你的负载是读密集型,change buffer 帮不上忙。
这次调优后我重新审视了索引设计:那十几个二级索引里有三个是唯一索引,吃不到 change buffer 红利还贡献了最多的读放大,跟业务确认唯一性约束其实可以由上游保证,删掉之后写入延迟进一步下降。change buffer 不是万能药,但它提醒我们:写多读少的库,索引数量和唯一性设计本身就是性能参数。
- 点赞
- 收藏
- 关注作者
评论(0)