21.Mysql Server优化

21.优化Mysql Server
21.1 Mysql体系结构概览
Mysql由Mysql Server层和存储引擎层组成。
Mysql实例由一组后台进程、一写内存块和若干服务线程组成。
Mysql后台进程分为8类,1个主线程、4组IO线程、1个锁线程、1个错误监控线程、1个purge线程。
主线程master thread:负责将脏缓存页刷新到数据文件,执行purge操作,触发检查点,合并插入缓冲区等。
insert buffer thread:负责插入缓冲区的合并操作。
read threa d:负责数据库读取操作,可配置多个读线程。
write thread:负责数据库写操作,可配置多个写线程。
log thread:负责将重做日志刷新到logfile中。
锁线程lock thrad:负责锁控制和死锁检测等。
错误监控线程:负责监控和错误处理。
purge thread:执行purge操作。
查看线程状态命令:show engine innodb status;
Mysql内存块包括:innodb_buffer_pool、innodb_log_buffer、Addional_buffer_pool、query_cache、thread_cache。
innodb_buffer_pool内包含:locks、insert_buffer、undo、page_cache、adaptive_hash_index。
thread_cachel内包含单个线程占用的buffer:read_buffer_size、sort_buffer_size、join_buffer_size、read_rnd_buffer_size、thread_stacd。
存储引擎层由系统表空间、用户表空间、日志文件组成。
系统表空间包含:innodb_dictionary数据字典、rollback segment回滚段、insert buffer、double writer buffer。
用户表空间包含表和索引的数据。
日志文件分为:(redo log和undo log?)错误日志、二进制日志(binlog)、查询日志、慢查询日志。

21.2 Mysql内存管理及优化
21.2.1 内存优化原则
将物理内存的60%分配给Mysql的innodb_buffer_pool;
最大连接数*每个会话的专用内存(read_buffer_size+sort_buffer_size+join_buffer_size+read_rnd_buffer_size)=20%的物理内存;
Mysql内存使用率整体控制在80%左右,服务器内存使用率整体控制在90%。

21.2.2 MyISAM内存优化
MyISAM存储引擎使用key buffer索引缓存块,以加速MyISAM索引的读写速度。
对于MyISAM表的数据块,Mysql没有进行缓存,完全依赖操作系统的IO缓存。
1.key buffer索引缓存
通过参数key_buffer_size设置,建议设置为物理内存的1/4。
key buffer使用率计算公式:1-((key_blocks_unused*key_cache_block_size)/key_buffer_size)
key buffer使用率在80%较为合适,如果小于60%可认为key_buffer_size设置过大(浪费内存);如果大于90%可认为key_buffer_size设置过小(影响系统性能)。
key buffer效率通过索引块物理读写比率判断,
索引块物理读比率=key_reads/key_read_requests,应小于1%,否则应加大key_buffer_size的设置;
索引块物理写比率=key_writes/key_write_requests,接近1说明系统存在大量的单行随机写操作,接近0说明系统以批量DML操作为主。
2.使用多个索引缓存
多个session并发时会争用key buffer,创建多个key buffer可以减少争用及争用产生的等待。
创建key buffer:
set global hot_cache.key_buffer_size=128*1024;
说明:
hot_cache 指索引缓存名;
global 指该索引缓存对任何新的连接都有效。
128*1024 指该索引缓存大小为128K。
也可在my.cnf文件中设置 hot_cache.key_buffer_size=2G;
删除key buffer
set global hot_cache.key_buffer_size=0;
说明:
将key_buffer_size指设为0,即删除。
只能删除创建的(带名字的)索引缓存,不能删除默认的索引缓存。
为表指定索引缓存:
cache index 表名1,... in 索引缓存名;
或者mysqld_init.sql中增加:
cache index 表名1,... in 索引缓存名;
load index into cache 表名1,...;
3.索引缓存区淘汰策略
3.1 LRU(Least Recently Used) 最近最后一次使用策略
通过链表保存最近使用的索引,最后一次用到的索引保存在链表的头部,当空间不足时从链表尾部开始淘汰。
基于最近使用的索引很可能别下次重复使用的原则。
分析:第一次从磁盘将索引读入内存时没有产生性能优化,下次使用该索引时,从内存直接读取,不用去读磁盘,产生性能优化。
缺点:最近读取的索引不一定是使用最频繁的索引。
3.2 中点插入策略(Midpoint Insert Strategy)
将LRU链表分为两部分:hot子表和warm子表,两个子表方向相反,尾部在中间;
当索引读入内存时,先被放在LRU链表的中点,即warm子表的尾部;
当该索引达到一定的命中次数后,该索引块被晋升到hot子表的尾部;
此后,该数据块在hot子表流转,如果其到达hot子表的头部并超过了一定时间,将有hot子表头部降级到warm子表头部;
当需要淘汰索引块时,缓存管理块优先选择淘汰warm子表头部的内存块。
系统参数:
key_cache_division_limit=[1-100] 控制warm子表占索引缓存区的比率,默认为100,即不使用hot子表,建议设置为70;
key_cache_age_threshold=N 控制索引块从hot子表头部降级到warm子表头部的时间,值越小降级越快。
该索引的块数量N*key_cache_age_threshold/100=该索引多少次未被命中将被降级。
4.线程独占缓冲区
read_buffer_size 用于保存顺序扫描MyISAM表的数据。
read_rnd_buffer_size 用于MyISAM表数据的排序操作。

21.2.3 InnoDB内存优化
1.InnoDB缓存机制
InnoDB缓存池innodb_buffer_pool_size可以缓存索引和数据。
innodb_buffer_pool_size逻辑上分为free list、flush list和LRU list。
free list 指:空闲缓存块列表。
flush list指:需要刷新到磁盘的缓存块列表。
LRU list 指:正在使用的缓存块列表。
InnoDB的LRU算法:
将LRU List分为young sublist和old sublist(方向一致);
当从磁盘读取数据时,数据被插入到LRU的中点,即old sublist的头部;
经过一定时间的访问(由参数innodb_old_blocks_time决定),该数据库块将会有old sublist转移到young sublist的头部,即整个LRU list的头部;
随着时间的推移,young sublist和old sublist中较少被访问的索引块将从各自链表的头部向尾部移动;
需要淘汰数据块时,优先从链表尾部淘汰;
每次淘汰的页数由参数innodb_lru_scan_depth参数决定(默认1024页),被淘汰的数据页将立刻放入到free list中。
脏页指的时已经被修改的数据块原始的数据仍存在内存中。
flush list和LRU list中均可能存在脏页,脏页将被直接刷新。
可以通过调整innodb_buffer_pool_size的改小、改变young sublist和old sublist的比例、控制脏页的刷新、使用多个缓冲池等方法来优化Innodb的性能。

2.innodb_buffer_pool_size设置
innodb_buffer_pool_size决定表和索引数据缓冲池的大小,值越大命中率越高,从而磁盘IO越少,性能越高。
专用服务器应将80%的物理内存分配给innodb_buffer_pool_size。
注意:应避免产生swap交换。
查看buffer pool的使用情况命令:mysqladmin -s /tmp/mysql.sock ext|grep -i innodb_buffer_pool
计算innodb缓冲池命中率公式:(1-innodb_buffer_pool_reads/innodb_buffer_pool_read_request)*100
如果命中率小于95%,应考虑扩充内存,增加innodb_buffer_pool_size的值。

3.innodb_old_blocks_pct设置
参数innodb_old_blocks_pct控制old sublist大小占LUR List的比率,取值范围[5~95],默认37%。
查看命令:show global variables like '%innodb_old_blocks_pct%';
在没有较大的表扫描或索引扫描时,如果young/s的值很低,就需要增加innodb_old_blocks_pct或减小innodb_old_blocks_time。

4.innodb_old_blocks_time设置
参数innodb_old_blocks_time控制从old sublist转移到young sublist的时间,单位是毫秒。
但innodb_old_blocks_time设置过大时,数据块可能在未满足要求的时间时就被淘汰了。
当进行表扫描时,如果non-young/s很高,young/s很低时,可以调大innodb_old_blocks_time参数。
进行大表扫描时,innodb_old_blocks_time参数临时调整。

5.innodb_buffer_pool_instances设置
参数innodb_buffer_pool_instances控制缓冲池个数,默认1个。
当innodb_buffer_pool_size比较大时,可以通过设置innodb_buffer_pool_instances参数将一个大的缓冲池平均拆分为多个小的缓冲池。
多个缓冲池可以减少并发进程对缓存池的争用。

6.innodb_max_dirty_pages_pct和innodb_io_capacity调整
控制innodb buffer刷新,延长数据缓存时间,减缓磁盘IO
参数innodb_max_dirty_pages_pct控制缓存池中脏页的最大比例,默认值为75%。
当脏页比例达到或超过该参数阈值时,InnoDB写线程开始缓存刷新。
参数innodb_io_capacity代表磁盘系统的IO能力(IOPS),决定了一次刷新脏页的数量,默认值为200。
对于低速(7200RPM)磁盘应将innodb_io_capacity降低到100,对于SSD或磁盘阵列可适当增大该参数。
参数innodb_adaptive_flushing=true时,InnoDB将根据buf_flush_get_desired_flush_rate返回的重做日志产生的速度确定要刷新的脏页数。
在合并插入缓存时,Innodb每次合并的页数是innodb_io_capacity*0.05。
状态变量innodb_buffer_pool_wait_free值增长较快说明Innodb经常在等空闲的缓存页,则应该调小innodb_max_dirty_pages_pct或增加innodb_io_capacity。

7.Innodb doublewrite双写策略。
原因:Mysql的数据页为16KB,操作系统IO数据页为4KB,无法保证InnoDB的缓存页被完整一致的刷新到磁盘,
而redo log只记录了数据改变的部分而非整页数据,当发生部分写或断裂写时,数据页可能无法恢复,所以引入了双写策略。
双写策略:在系统表空间中使用连续磁盘空间(100个连续数据页,大小为2MB)作为doublewrite buffer;
先将脏页写到doublewrite buffer中,然后调用fsync()刷新操作系统IO缓存,确保数据真正写入磁盘;
最后InnoDB后台IO线程将脏页刷新到磁盘数据文件中。
在数据恢复时,如果发现不一致页,InnoDB会使用doublewrite buffer中的数据来恢复。
参数innodb_doublewrite=[1|0] 1开启双写,0关闭双写。
doublewrite buffer是连续磁盘空间,批量写入速度是随机写入速度的百倍,开启双写对性能影响很小。

21.2.4 sort_buffer_size和join_buffer_size设置
参数sort_buffer_size 控制每个进程的排序缓冲区大小,以改善order by子句和group by子句的性能。
当状态参数sort_merge_passes值比较大时可以考虑增加sort_buffer_size的值。
参数join_buffer_size 控制每个进程的连接缓冲区大小,会给多表连接中每个表分配一个连接缓冲区。
当出现全表扫描时,应加大join_buffer_size参数。

21.3 InnoDB Log机制及优化
redo log机制用来保证事务更新的一致性和持久性。
21.3.1 InnoDB重做日志
更新数据时InnoDB的工作流程:
将数据读入InnoDB buffer pool,并对相关记录加独占锁;
将undo信息写入undo表空间的回滚段中;
更改缓存页中的数据,并将更新记录写入redo buffer中;
提交时,根据参数innodb_flush_log_at_trx_commit的设置,用不同方式将redo buffer中的更新记录刷新到Innodb redo log file中,并释放独占锁;
参数innodb_flush_log_at_trx_commit=[0|1|2] 0 每秒写回日志和数据,1 立即写回日志和数据,2 立即写回日志每秒写回数据;
最后,脏页刷新机制和双写机制将缓存中修改后的数据刷新到磁盘数据文件中。
查看当前日志写入情况:show engine innodb status;
Log sequence number xxx 上次数据页的修改还没有刷新到日志文件的lsn号
Log flu shed up to xxx 上次操作成功,已经刷新到日志文件中的lsn号
Last checkpoint at xxx 上次检查点成功完成时的lsn号,意味着恢复的起点
日志序列号LSN(Log sequence number)对应日志文件的偏移量,
公式:新的LSN=旧的LSN+写入日志大小

21.3.2 innodb_flush_log_at_trx_commit的设置
参数innodb_flush_log_at_trx_commit=[0|1|2] 控制将redo buffer中更新记录写入到日志文件及将日志文件数据刷新到磁盘的的操作时机。
innodb_flush_log_at_trx_commit=0 每秒触发一次缓存日志写回磁盘操作,并调用操作系统fsync刷新IO缓存;
innodb_flush_log_at_trx_commit=1 在事务提交时立即将缓存日志写回磁盘操作,并调用操作系统fsync刷新IO缓存;
innodb_flush_log_at_trx_commit=2 在事务提交时立即将缓存日志写回磁盘操作,每秒调用操作系统fsync刷新IO缓存。
默认值为1,完全满足事务持久化要求,在数据库崩溃时不会丢失数据,但对性能有影响。
设置为0时,效率最高,但数据库崩溃时会丢失最后1秒的数据。
设置为2时,性能介于2者之间,数据库崩溃时操作系统不崩溃则数据不丢,操作系统崩溃丢失最后1秒的数据。

21.3.3 innodb_log_file_size设置
参数innodb_log_file_size控制日志文件大小,默认50MB。
当一个日志文件满后,会自动切换到另一个日志文件,两个日志文件循环使用。
切换时会触发检查点(checkpoint),checkpoint又会触发缓存脏页刷新。
查看LSN:select variable_value from information_schema.global_status where variable_name='innodb_os_log_written';
状态参数:select @@innodb_log_files_in_group;

21.3.4 innodb_log_buffer_size设置
参数innodb_log_buffer_size控制Innodb重做日志缓冲池大小,默认8MB。
对于大量DML操作事务,应增加innodb_log_buffer_size大小,避免在事务内多次刷新innodb_log_buffer到innodb_log_file。

21.4 调整Mysql并发相关参数
21.3.1 调整max_connections提高并发连接
参数max_connections控制允许连接到Mysql的最大的连接数量,默认值151。
状态变量connection_errors_max_connections记录着因超出max_connections阈值的连接错误次数。
当connection_errors_max_connections不为0,且持续增长时,应增大max_connections参数设置。
Linux平台支持500~1000个Mysql连接,内存足够,不考虑响应时间,可支持上万个连接。
Windows平台最大支持open connections<2048-(open tables *2)。

21.3.2 调整back_log
参数back_log控制Mysql监听TCP端口时设置的积压请求栈大小,默认50+max_connections/5,最大不能超过900。
短时间处理大量连接请求时可增大back_log。

21.3.3 调整table_open_cache
参数table_open_cache控制所有SQL可打开的表缓存的数量。
状态变量opened_tables值较大时,应增加table_open_cache参数的设置,可以是max_connections的N倍。

21.3.4 调整thread_cache_size
参数thread_cache_size控制Mysql缓存的客户服务进程数量,不能大于max_connections参数,缓存进程可加快连接速度。
线程cache的失效率=threads_created/connections,失效率接近0,说明线程缓冲池命中率高,参数thread_cache_size设置合理;失效率接近1时应,应增大参数thread_cache_size。

21.3.5 innodb_lock_wait_timeout的设置
参数innodb_lock_wait_timeout控制事务等待行锁的时间,默认值50ms,等待超过该阈值时将提示锁等待超时。
调小该参数可避免进程因锁等待长时间被挂起,但可能导致部分事务因锁等待超时被回退;
调大该参数可避免大事务被回退。

21.5 小结

猜你喜欢

转载自www.cnblogs.com/BradMiller/p/10123407.html