暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

change buffer(写缓冲)

原创 冯晓宇 2023-06-27
536

概念描述

change buffer 更改缓冲区是一种特殊的数据结构,当这些页面不在缓冲池中时,它会缓存对二级索引页面的更改。可能是有DML操作(INSER\UPDATE\DELETE)产生了缓冲更改,将在以后其他读取操作将页面加载到缓冲池中时合并。

1972780b58bade6a9156f76b5b65ddc.png


change buffer 原理

当执行写操作时,数据页存在于 Buffer Pool 中时,会直接修改数据页。如果数据页不存在于 Buffer Pool 中时,InooDB 会将这些更新操作缓存在 change buffer 中,这样就不需要从磁盘中读入这个数据页了。当下次访问到这条数据后,会把数据页加载到 buffer pool中,并且合并 change buffer 里面的变更。这样保证了数据的一致性,且批量写对性能影响不大。
将 change buffer 中的操作合并到原数据页,得到最新结果的过程称为 merge。

merge 触发的情况:

  • 访问该数据页;
  • 后台 master 线程会定期 merge;
  • 数据库缓冲池不够用时;
  • 数据库正常关闭时;
  • redo log 写满时;

change buffer 是可以持久化的数据

  • 当更新某个数据页时,该页在内存中,那么直接更新。
  • 如果该页不在内存中,那么先将更新操作记录在 change buffer 中,这时不需要从磁盘中读出数据页。
  • 将操作记录到 redo log 中,防止机器意外关闭导致数据丢失。(redo log 未commit的话,就要看 binlog 有无 commit 了,有 commit 的话就可以通过 binlog 恢复 redo log 再恢复 change buffer,未 commit 的话这部分数据可能会丢失)
  • 这时已经可以返回给客户端更新成功了,因为即使机器意外重启,也可以通过 redo log 找回数据。

change buffer 和 redo log 对于磁盘的随机IO影响

  • redo log 是减少随机写磁盘IO的消耗。每个操作先记录 redo log ,系统空闲时或 redo log 满时进行磁盘IO。
  • change buffer 是减少随机读磁盘IO的消耗。更新时如果内存中不存在该数据页,也不需要马上进行磁盘IO,而是先记录在 change buffer 中,之后再 merge。

change buffer 为什么针对非唯一普通索引页

使用唯一索引,所有的更新操作都要先判断这个操作是否违反唯一性约束。而这必须要将数据页读入内存才能判断。如果已经读入到内存了,那直接更新内存会更快,就没必要使用 change buffer,因此,唯一索引的更新就不能使用 change buffer,实际上也只有普通索引可以使用。

测试验证

change buffer 相关参数

  • 在InnoDB中,可以通过参数innodb_change_buffer_max_size变量允许将更改缓冲区的最大大小配置为缓冲池总大小的百分比,默认值是25,最大是50。例如当这个参数值是50 的时候,表示 change buffer 最多只能占用 buffer pool 的50%。

  • innodb_change_buffering 默认all表示所有的非唯一普通索引页写入都使用change buffer。

    • all #默认值:缓冲区插入、删除标记操作和清除。
    • none #关闭change buffer,不要缓冲任何操作。
    • inserts #缓冲插入操作
    • deletes #缓冲删除标记操作
    • changes #缓冲插入和删除标记操作
    • purges #缓冲在后台发生的物理删除操作

监视更改缓冲区

以下选项可用于更改缓冲区监视:

1. InnoDB 标准监视器输出包括更改缓冲区状态信息。要查看监视器数据,请发出该 SHOW ENGINE INNODB STATUS 语句。

mysql> SHOW ENGINE INNODB STATUS\G;

更改缓冲区状态信息位于 INSERT BUFFER AND ADAPTIVE HASH INDEX 标题下,类似于以下内容:

-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
insert 0, delete mark 0, delete 0
discarded operations:
insert 0, delete mark 0, delete 0
Hash table size 4425293, used cells 32, node heap has 1 buffer(s)
13577.57 hash searches/s, 202.47 non-hash searches/s
#size 1                      正在使用的 page
#free list len 0             空闲的 page
#seg size 2                  当前 change buffer 大小 2*16K
#0 merges                    合并的数目
#insert 0                    通过 change buffer 插入的数目
#delete mark 0               通过 change buffer 删除的数目
#delete 0                    通过 change buffer purge 的数目
#change buffer 的效果 = merges/(insert + delete mark + delete) 结果越小说明 change buffer 对性能提升越有利

2. Information Schema INNODB_METRICS 表提供了在 Standard Monitor 输出中找到的大部分数据点 InnoDB 以及其他数据点。 要查看更改缓冲区指标和每个指标的描述,请发出以下查询:

mysql> SELECT NAME, COMMENT FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME LIKE '%ibuf%'\G;
+-----------------------------------------+-------------------------------------------------------------+
| NAME                                    | COMMENT                                                     |
+-----------------------------------------+-------------------------------------------------------------+
| buffer_page_read_index_ibuf_leaf        | Number of Insert Buffer Index Leaf Pages read               |
| buffer_page_read_index_ibuf_non_leaf    | Number of Insert Buffer Index Non-Leaf Pages read           |
| buffer_page_read_ibuf_free_list         | Number of Insert Buffer Free List Pages read                |
| buffer_page_read_ibuf_bitmap            | Number of Insert Buffer Bitmap Pages read                   |
| buffer_page_written_index_ibuf_leaf     | Number of Insert Buffer Index Leaf Pages written            |
| buffer_page_written_index_ibuf_non_leaf | Number of Insert Buffer Index Non-Leaf Pages written        |
| buffer_page_written_ibuf_free_list      | Number of Insert Buffer Free List Pages written             |
| buffer_page_written_ibuf_bitmap         | Number of Insert Buffer Bitmap Pages written                |
| ibuf_merges_insert                      | Number of inserted records merged by change buffering       |
| ibuf_merges_delete_mark                 | Number of deleted records merged by change buffering        |
| ibuf_merges_delete                      | Number of purge records merged by change buffering          |
| ibuf_merges_discard_insert              | Number of insert merged operations discarded                |
| ibuf_merges_discard_delete_mark         | Number of deleted merged operations discarded               |
| ibuf_merges_discard_delete              | Number of purge merged operations discarded                 |
| ibuf_merges                             | Number of change buffer merges                              |
| ibuf_size                               | Change buffer size in pages                                 |
| innodb_ibuf_merge_usec                  | Time (in microseconds) spent to process change buffer merge |
+-----------------------------------------+-------------------------------------------------------------+

3. Information Schema INNODB_BUFFER_PAGE 表提供有关缓冲池中每个页面的元数据,包括更改缓冲区索引和更改缓冲区位图页面。 PAGE_TYPE 是更改缓冲区页面标识。 IBUF_INDEX 是更改缓冲区索引页面的页面类型,IBUF_BITMAP是更改缓冲区位图页面的页面类型,但是 INNODB_BUFFER_PAGE 表会带来显着的性能开销。为避免影响性能,请在测试实例上重现要调查的问题并在测试实例上运行查询。

例如,我们可以查询 INNODB_BUFFER_PAGE 表以确定页数 IBUF_INDEX 和 IBUF_BITMAP 页数占总缓冲池页数的百分比。

SELECT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE WHERE PAGE_TYPE LIKE 'IBUF%') AS change_buffer_pages, (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE) AS total_pages, (SELECT ((change_buffer_pages/total_pages)*100)) AS change_buffer_page_percentage;
+---------------------+-------------+-------------------------------+
| change_buffer_pages | total_pages | change_buffer_page_percentage |
+---------------------+-------------+-------------------------------+
|                   2 |       40957 |                        0.0049 |
+---------------------+-------------+-------------------------------+

4. Performance Schema 为高级性能监控提供更改缓冲区互斥等待检测。 要查看更改缓冲区检测,操作以下查询:

mysql> SELECT * FROM performance_schema.setup_instruments WHERE NAME LIKE '%wait/synch/mutex/innodb/ibuf%';
+-------------------------------------------------------+---------+-------+
| NAME                                                  | ENABLED | TIMED |
+-------------------------------------------------------+---------+-------+
| wait/synch/mutex/innodb/ibuf_bitmap_mutex             | YES     | YES   |
| wait/synch/mutex/innodb/ibuf_mutex                    | YES     | YES   |
| wait/synch/mutex/innodb/ibuf_pessimistic_insert_mutex | YES     | YES   |
+-------------------------------------------------------+---------+-------+

局限性

更改缓冲区占用了缓冲池的一部分,减少了可用于缓存数据页的内存。如果工作集几乎适合缓冲池,或者如果您的表的二级索引相对较少,则禁用更改缓冲可能会有用。如果工作数据集完全适合缓冲池,则更改缓冲不会造成额外开销,因为它仅适用于不在缓冲池中的页面。

知识总结

change buffer 适合写多读少的业务场景(账单、日志类系统),因为即使更新语句使用了 change buffer 机制,但是如果该业务查询场景很多,亦或者需要更新完立刻查询的话。这样会马上触发 merge 操作,这样随机访问IO的次数不仅不会减少,反而增加了 change buffer 的维护成本。

参考文档

https://dev.mysql.com/doc/refman/5.7/en/innodb-change-buffer.html

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论