MySQL的缓存
InnoDB Buffer Pool
一些重要的参数
|
|
注意
innodb_buffer_pool_size 必须是 innodb_buffer_pool_instances * innodb_buffer_pool_chunk_size 的整数倍,或者相等
否则系统会自动调整值的
采用 LRU的方式将buffer pool 中的page组织起来
分为 young区 和 old两个区域
一开始先加入到 old 区的开头,如果超过了一定的阈值,则放到 young区
整个buffer pool 按照实例个数分为若干个
每个实例又包含 N个 chunk,这其中包含多个链表
- free链表
- flush链表
- LRU链表
- 其他链表
每个链表包含一个 list node base,执行控制块的头、尾部
控制块包含 表空间信息、page信息
这样可以通过 hash方式快速定位到具体的page
其他一些参数
- innodb_old_blocks_time,默认1000ms, 从old区到 young的等待时间,也就是old区过了1秒后才能到 young区
- innodb_old_blocks_pct, 默认37 ,表示old区占用 37%,剩下的63% 是young
- innodb_read_ahead_threshold,顺序访问一个extent,会异步读取默认 56个page
- innodb_random_read_ahead,默认关闭,这是随机预读取
- innodb_lru_scan_depth,定期从链表尾部扫描 N个page,如果有脏页则刷磁盘
- innodb_flush_neighbors,是否刷新邻居page
- innodb_io_capacity_max,每秒后台刷新的脏页
- innodb_adaptive_flushing,刷新脏页的自适应模式
- innodb_max_dirty_pages_pct,当系统的脏页超过一定比例后,就开始刷新
|
|
字段解释
Name | Descption |
---|---|
Total large memory allocated | 分配给InnoDB Buffer Pool的总内存(字节) |
Dictionary memory allocated | 分配给InnoDB数据字典的内存(字节) |
Buffer pool size | buffer pool的page个数 |
Free buffers | Buffer Pool Free List page总数 |
Database pages | Buffer Pool LRU List page总数 |
Old database pages | IBP old LRU 总大小,单位pages(冷端) |
Modified db pages | 当前IBP中脏页的数量,单位pages |
Pending reads | 等待读入IBP的页数量,单位pages |
Pending writes: LRU, flush list, single page | 从LRU、flush等链表中刷磁盘的page数 |
Pages made young,not young | LRU中被made young的页面数(LRU列表中页移动到前端的次数);not young,LRU中保持在old 子列表中的页面数(没被移动到前端,因innodb_old_blocks_time设置。) |
youngs/s,non-youngs/s | 每秒从old区到young的节点数量, non-young表示不能从old区移动的数量 |
Pages read,created,written | 读取、创建、写入了多少page |
reads/s,creates/s,writes/s | 平均每秒读的页数,创建的页数,写的页数 |
Buffer pool hit rate, young-making rate | 过去某段时间内评估1000次访问又多少被缓存到buffer pool,有多少页面移动到young区 |
Pages read ahead,evicted without access,Random read | 每秒平均预读操作次数;每秒因未被访问而被逐出ibp的页数;每秒平均随机预读次数 |
LRU len,unzip_LRU len | BP中LRU列表包含页面的总数(Database pages),压缩页的unzip_LRU列表包含页面的总数 |
I/O sum,cur, unzip sum:cur | 最近50秒读取磁盘page总数,现在正在读取的磁盘page数;最近50秒解压的page数,正在解压的pae数 |
Doublewrite Buffer
|
|
8.0 将双写缓冲区单独拿了出来
操作系统的默认Page大小是 4K
|
|
MySQL的默认page是 16K
|
|
数据库的page大小比 OS的要大,所以无法保证原子性
1个数据库page对应4个OSpage,如果数据库的page写一半宕机了,对于OS层来说只写了两个page
对于数据库来说这个page相当于不完整,后面都没法恢复
因为各种MySQL的各种类型page都是 16K的
Doublewrite Buffer工作流程
执行过程:
1、页数据先memcopy到DWB的内存里
2、DWB的内存里的数据页,会先刷到DWB的磁盘上
3、DWB的内存里的数据页,再刷到数据磁盘存储.ibd文件上
因为要写两次,第一次是内存写到磁盘 DWB磁盘上,这是顺序写
第二次是从内存写到 ibd 文件,这是随机写
按照官网的说法,虽然是写了两次,但并不是两倍的 I/O开销,因为写入到 DWB磁盘上的是大量的顺序I/O效率很高
|
|
MySQL 8.x 相关的参数
|
|
name | value |
---|---|
innodb_doublewrite_batch_size | 批量写入的双写页数,默认为0,最大256 |
innodb_doublewrite_dir | 双写文件的自定义目录,默认为数据目录,应放在最快存储介质上 |
innodb_doublewrite_files | 双写文件的数量 |
默认有两个双写文件
- 刷新列表双写文件的默认大小是InnoDB页面大小 * 双写页面字节
- LRU列表双写文件用于从缓冲池LRU列表中刷新的页面。它还包含用于单页刷新的插槽。LRU列表双写文件的默认大小是InnoDB页面大小 *(双写页面 +(512 缓冲池实例数)
Doublewrite文件名具有以下格式:
以下双写文件是为页面大小为16KB和单个缓冲池的MySQL实例创建的:
|
|
Log Buffer
这里存储的是 redo log 的缓存
redo log 默认是两个文件,按照环形的方式组织
一些重要的参数
name | value |
---|---|
innodb_log_buffer_size | 用于写入磁盘上的日志文件的缓冲区的大小 |
innodb_log_checksums | 启用或禁用重做日志页面的校验和 |
innodb_log_file_size | 日志组每个Redo Log文件的大小 |
innodb_log_files_in_group | 日志组文件的数量 |
- InnoDB一项很重要的内存结构(In-Memory Structure),即我们的Log Buffer(日志缓冲区),这一层,是MySQL应用程序用户态控制。
- 操作系统文件系统的缓冲区(FS Page Cache),这一层,是操作系统OS内核态控制。
- 落盘的物理日志文件
-
策略一:最佳性能(innodb_flush_log_at_trx_commit=0)
处理过程:每隔一秒,才将Log Buffer中的数据批量write入FS Page Cache,同时MySQL主动fsync
缺点:这种策略,如果数据库奔溃,有一秒的数据丢失 -
策略二:强一致(innodb_flush_log_at_trx_commit=1)
处理过程:每次事务提交,都将Log Buffer中的数据write入FS Page Cache,同时MySQL主动fsync。这种策略,是InnoDB的默认配置,为的是保证事务ACID特性
缺点:这种策略,性能较其余两种策略较差 -
策略三:折衷(innodb_flush_log_at_trx_commit=2)
处理过程:每次事务提交,都将Log Buffer中的数据write入FS Page Cache;每隔一秒,MySQL主动将FS Page Cache中的数据批量fsync
缺点:这种策略,如果操作系统奔溃,最多有一秒的数据丢失。(因为OS也会fsync,MySQL主动fsync的周期是一秒,所以最多丢一秒数据。磁盘IO次数不确定,因为操作系统的fsync频率并不是MySQL能控制的)
Adaptive Hash Index
建立一个表
|
|
相关参数
|
|
variable_name | value |
---|---|
innodb_adaptive_flushing | on |
innodb_adaptive_flushing_lwm | 10 |
innodb_adaptive_hash_index | on |
innodb_adaptive_hash_index_parts | 8 |
innodb_adaptive_max_sleep_delay | 150000 |
解释
- innodb_adaptive_hash_index,是否启用或禁用InnoDB 自适应哈希索引
- innodb_adaptive_flushing,指定是否动态调整冲洗速度 脏页在 InnoDB 缓冲池中,根据工作负载。动态调整刷新率旨在避免I/O活动的爆发。默认情况下启用此设置
- innodb_adaptive_flushing_lwm,定义表示启用自适应刷新的重做日志容量百分比的低水位线。(默认值10,最小值0,最大值70)
- innodb_adaptive_hash_index_parts,对自适应哈希索引搜索系统进行分区
- innodb_adaptive_max_sleep_delay,允许根据当前工作量InnoDB自动调整innodb_thread_sleep_delay up或down的值。任何非零值都可以自动、动态地调整innodb_thread_sleep_delay值,直至达到innodb_adaptive_max_sleep_delay选项中指定的最大值。该值表示微秒数。此选项在具有16个以上InnoDB线程的繁忙系统中很有用
自适应 hash索引的状态
|
|
Adaptive Hash Index限制
- 只能用于等值比较,例如=、<=>、IN、AND等
- 无法用于排序
- 有冲突可能
- MySQL自动(“自适应”)管理,人为无法干预
Change Buffer
InnoDB的整体架构图,内存和磁盘都有
对于不在buffer pool中的page,如果是非唯一索引,可以不用将其从磁盘上读出来
而是在内存中生成一个临时page,用作记录,然后将 redo log顺序写入磁盘
这样本来的随机I/O 就被转为顺序I/O 了
两种情况
- 如果要访问的page正好在buffer pool中
- 如果不在buffer pool中
对于第一种情况,直接更新buffer pool就可以了,再加上一次redo log顺序写操作
但对于非唯一索引,其实可以不用读磁盘
而仅仅记录缓冲变更(Buffer Changes),等未来数据被读取时
再将数据合并(Merge)恢复到缓冲池中的技术。写缓冲的目的是降低写操作的磁盘IO,提升数据库性能
加入优化后的效果
- 在写缓冲中记录这个操作,一次内存操作
- 写入redo log,一次磁盘顺序写操作
Change Buffer触发时机
- 有一个后台线程,会认为数据库空闲时;
- 数据库缓冲池不够用时;
- 数据库正常关闭时;
- redo log写满时
Change Buffer 不适用场景
- 数据库都是唯一索引
- 写入一个数据后,会立刻读取它
Change Buffer适用场景
- 数据库大部分是非唯一索引
- 业务是写多读少,或者不是写后立刻读取
Change Buffer的重要的参数
- innodb_change_buffer_max_size,配置写缓冲的大小,占整个缓冲池的比例,默认值是25%,最大值是50%
- innodb_change_buffering,配置哪些写操作启用写缓冲,可以设置成all/none/inserts/deletes等
InnoDB 参数汇总
Variable_name | Value |
---|---|
ignore_builtin_innodb | OFF |
innodb_adaptive_flushing | ON |
innodb_adaptive_flushing_lwm | 10 |
innodb_adaptive_hash_index | ON |
innodb_adaptive_hash_index_parts | 8 |
innodb_adaptive_max_sleep_delay | 150000 |
innodb_api_bk_commit_interval | 5 |
innodb_api_disable_rowlock | OFF |
innodb_api_enable_binlog | OFF |
innodb_api_enable_mdl | OFF |
innodb_api_trx_level | 0 |
innodb_autoextend_increment | 64 |
innodb_autoinc_lock_mode | 1 |
innodb_buffer_pool_chunk_size | 134217728 |
innodb_buffer_pool_dump_at_shutdown | ON |
innodb_buffer_pool_dump_now | OFF |
innodb_buffer_pool_dump_pct | 25 |
innodb_buffer_pool_filename | ib_buffer_pool |
innodb_buffer_pool_instances | 1 |
innodb_buffer_pool_load_abort | OFF |
innodb_buffer_pool_load_at_startup | ON |
innodb_buffer_pool_load_now | OFF |
innodb_buffer_pool_size | 134217728 |
innodb_change_buffer_max_size | 25 |
innodb_change_buffering | all |
innodb_checksum_algorithm | crc32 |
innodb_checksums | ON |
innodb_cmp_per_index_enabled | OFF |
innodb_commit_concurrency | 0 |
innodb_compression_failure_threshold_pct | 5 |
innodb_compression_level | 6 |
innodb_compression_pad_pct_max | 50 |
innodb_concurrency_tickets | 5000 |
innodb_data_file_path | ibdata1:12M:autoextend |
innodb_data_home_dir | |
innodb_deadlock_detect | ON |
innodb_default_row_format | dynamic |
innodb_disable_sort_file_cache | OFF |
innodb_doublewrite | ON |
innodb_fast_shutdown | 1 |
innodb_file_format | Barracuda |
innodb_file_format_check | ON |
innodb_file_format_max | Barracuda |
innodb_file_per_table | ON |
innodb_fill_factor | 100 |
innodb_flush_log_at_timeout | 1 |
innodb_flush_log_at_trx_commit | 1 |
innodb_flush_method | |
innodb_flush_neighbors | 1 |
innodb_flush_sync | ON |
innodb_flushing_avg_loops | 30 |
innodb_force_load_corrupted | OFF |
innodb_force_recovery | 0 |
innodb_ft_aux_table | |
innodb_ft_cache_size | 8000000 |
innodb_ft_enable_diag_print | OFF |
innodb_ft_enable_stopword | ON |
innodb_ft_max_token_size | 84 |
innodb_ft_min_token_size | 3 |
innodb_ft_num_word_optimize | 2000 |
innodb_ft_result_cache_limit | 2000000000 |
innodb_ft_server_stopword_table | |
innodb_ft_sort_pll_degree | 2 |
innodb_ft_total_cache_size | 640000000 |
innodb_ft_user_stopword_table | |
innodb_io_capacity | 200 |
innodb_io_capacity_max | 2000 |
innodb_large_prefix | ON |
innodb_lock_wait_timeout | 50 |
innodb_locks_unsafe_for_binlog | OFF |
innodb_log_buffer_size | 16777216 |
innodb_log_checksums | ON |
innodb_log_compressed_pages | ON |
innodb_log_file_size | 50331648 |
innodb_log_files_in_group | 2 |
innodb_log_group_home_dir | ./ |
innodb_log_write_ahead_size | 8192 |
innodb_lru_scan_depth | 1024 |
innodb_max_dirty_pages_pct | 75.000000 |
innodb_max_dirty_pages_pct_lwm | 0.000000 |
innodb_max_purge_lag | 0 |
innodb_max_purge_lag_delay | 0 |
innodb_max_undo_log_size | 1073741824 |
innodb_monitor_disable | |
innodb_monitor_enable | |
innodb_monitor_reset | |
innodb_monitor_reset_all | |
innodb_numa_interleave | OFF |
innodb_old_blocks_pct | 37 |
innodb_old_blocks_time | 1000 |
innodb_online_alter_log_max_size | 134217728 |
innodb_open_files | 2000 |
innodb_optimize_fulltext_only | OFF |
innodb_page_cleaners | 1 |
innodb_page_size | 16384 |
innodb_print_all_deadlocks | OFF |
innodb_purge_batch_size | 300 |
innodb_purge_rseg_truncate_frequency | 128 |
innodb_purge_threads | 4 |
innodb_random_read_ahead | OFF |
innodb_read_ahead_threshold | 56 |
innodb_read_io_threads | 4 |
innodb_read_only | OFF |
innodb_replication_delay | 0 |
innodb_rollback_on_timeout | OFF |
innodb_rollback_segments | 128 |
innodb_sort_buffer_size | 1048576 |
innodb_spin_wait_delay | 6 |
innodb_stats_auto_recalc | ON |
innodb_stats_include_delete_marked | OFF |
innodb_stats_method | nulls_equal |
innodb_stats_on_metadata | OFF |
innodb_stats_persistent | ON |
innodb_stats_persistent_sample_pages | 20 |
innodb_stats_sample_pages | 8 |
innodb_stats_transient_sample_pages | 8 |
innodb_status_output | OFF |
innodb_status_output_locks | OFF |
innodb_strict_mode | ON |
innodb_support_xa | ON |
innodb_sync_array_size | 1 |
innodb_sync_spin_loops | 30 |
innodb_table_locks | ON |
innodb_temp_data_file_path | ibtmp1:12M:autoextend |
innodb_thread_concurrency | 0 |
innodb_thread_sleep_delay | 10000 |
innodb_tmpdir | |
innodb_undo_directory | ./ |
innodb_undo_log_truncate | OFF |
innodb_undo_logs | 128 |
innodb_undo_tablespaces | 0 |
innodb_use_native_aio | ON |
innodb_version | 5.7.40 |
innodb_write_io_threads | 4 |
参考
- InnoDB Standard Monitor and Lock Monitor Output
- Buffer Pool
- 谨慎设置innodb_io_capacity_max
- InnoDB Buffer Pool详解
- InnoDB 中的缓冲池(Buffer Pool)
- InnoDB的杀手锏BufferPool
- show engine innodb status 输出结果解读
- Doublewrite Buffer
- MySQL各种“Buffer”之Doublewrite Buffer
- 详解MySQL InnoDB之UNDO Log
- MySQL各种“Buffer”之Adaptive Hash Index
- Adaptive Hash Index
- MySQL各种“Buffer”之Change Buffer