业务高峰性能时的紧急处理
-
问题一:短链接风暴。mysql
-
数据库处理得慢一些,链接数就会暴涨。max_connections参数,用来控制一个MySQL实例同时存在的链接数的上限,超过这个值,系统就会拒绝接下来的链接请求,并报错提示“Too many connections”。对于被拒绝链接的请求来讲,从业务角度看就是数据库不可用。sql
-
方法一:先处理掉占着链接却不工做的线程。数据库
- max_connections的计算,不是看谁在running,是只要连着就占用一个计数位置。对于那些不须要保持的链接,咱们能够经过kill connection主动踢掉。这个行为跟事先设置wait_timeout的效果是同样的。设置wait_timeout参数表示的是,一个线程空闲wait_timeout这么多秒以后,就会被MySQL直接断开链接。
- 注意:应该先断开那些非提交事物的链接,由于若是事物还未提交,断开会执行回滚。所以,若是是链接数过多,你能够优先断开事务外空闲过久的链接;若是这样还不够,再考虑断开事务内空闲过久的链接。
-
方法二:减小链接过程的消耗。并发
- 有的业务代码会在短期内先大量申请数据库链接作备用,若是如今数据库确认是被链接行为打挂了,那么一种可能的作法,是让数据库跳过权限验证阶段。跳过权限验证的方法是:重启数据库,并使用–skip-grant-tables参数启动。这样,整个MySQL会跳过全部的权限验证阶段,包括链接过程和语句执行过程在内。(风险极高)
-
-
问题二:慢查询性能问题函数
-
索引没有设计好:性能
- Online DDL,对于那种高峰期数据库已经被这个语句打挂了的状况,最高效的作法就是直接执行alter table 语句。
- 比较理想的是可以在备库先执行。假设你如今的服务是一主一备,主库A、备库B,这个方案的大体流程是这样的:
- 在备库B上执行 set sql_log_bin=off,也就是不写binlog,而后执行alter table 语句加上索引;
- 执行主备切换;
- 这时候主库是B,备库是A。在A上执行 set sql_log_bin=off,而后执行alter table 语句加上索引。
-
sql语句没写好:spa
- 检查sql语句,字符集是否同样,查询字段的数据类型和数据库存储的数据类型是否同样,有没有隐式使用了函数致使没有走索引。
-
mysql选错了索引:线程
- 这时候,应急方案就是给这个语句加上force index。
-
mysql是怎么保证事物不丢的
- binlog的写入机制:事物执行过程当中,先把日志写到binlog cache,事务提交的时候,再把binlog cache写道binlog文件中。
- 一个事物的binlog是不能被拆开的,所以不管这个事物多大,也要确保一次性写入,系统给binlog cache分配了一片内存,每一个线程一个,参数binlog_cache_size用于控制单个线程内binlog cache所占内存的大小,若是超过了,就要暂存到磁盘。
- 事物提交的时候,执行器把binlog cache里的完整事物写入到binlog中,并清空binlog cache。
每一个线程有本身的binlog cache,可是共用一份binlog。设计
- 图中的write,指的就是指把日志写入到文件系统的page cache,并无把数据持久化到磁盘,因此速度比较快。
- 图中的fsync,才是将数据持久化到磁盘的操做。通常状况下,咱们认为fsync才占磁盘的IOPS。
write 和fsync的时机,是由参数sync_binlog控制的:日志
-
sync_binlog=0的时候,表示每次提交事务都只write,不fsync;
-
sync_binlog=1的时候,表示每次提交事务都会执行fsync;
-
sync_binlog=N(N>1)的时候,表示每次提交事务都write,但累积N个事务后才fsync。
所以,在出现IO瓶颈的场景里,将sync_binlog设置成一个比较大的值,能够提高性能。在实际的业务场景中,考虑到丢失日志量的可控性,通常不建议将这个参数设成0,比较常见的是将其设置为100~1000中的某个数值。
可是,将sync_binlog设置为N,对应的风险是:若是主机发生异常重启,会丢失最近N个事务的binlog日志。
redo log的写入机制
-
事务还没提交的时候,redo log buffer中的部分日志有没有可能被持久化到磁盘呢?
-
确实会有,redo log可能存在在的三种状态。
-
存在redo log buffer中,物理上是在MySQL进程内存中,就是图中的红色部分;
-
写到磁盘(write),可是没有持久化(fsync),物理上是在文件系统的page cache里面,也就是图中的黄色部分;
-
持久化到磁盘,对应的是hard disk,也就是图中的绿色部分。
-
-
日志写到redo log buffer是很快的,wirte到page cache也差不多,可是持久化到磁盘的速度就慢多了。为了控制redo log的写入策略,InnoDB提供了innodb_flush_log_at_trx_commit参数,它有三种可能取值:
- 设置为0的时候,表示每次事务提交时都只是把redo log留在redo log buffer中;
- 设置为1的时候,表示每次事务提交时都将redo log直接持久化到磁盘;
- 设置为2的时候,表示每次事务提交时都只是把redo log写到page cache。
- InnoDB有一个后台线程,每隔1秒,就会把redo log buffer中的日志,调用write写到文件系统的page cache,而后调用fsync持久化到磁盘。
- 注意,事务执行中间过程的redo log也是直接写在redo log buffer中的,这些redo log也会被后台线程一块儿持久化到磁盘。也就是说,一个没有提交的事务的redo log,也是可能已经持久化到磁盘的。
组提交机制
- 日志逻辑序列号(log sequence number)LSN,LSN是单调递增的,用来对用redo log的一个个写入点,每次写入长度为length的redo log,LSN的值就会加上length。
- 例子:如图,三个并发事物(trx1,trx2,trx3)在prepare阶段,都写完redo log buffer,持久化到磁盘的过程,对应的LSN是50,120,160
如图:
1. trx1是第一个到达的,会被选为这组的 leader; 2. 等trx1要开始写盘的时候,这个组里面已经有了三个事务,这时候LSN也变成了160; 3. trx1去写盘的时候,带的就是LSN=160,所以等trx1返回时,全部LSN小于等于160的redolog,都已经被持久化到磁盘; 4. 这时候trx2和trx3就能够直接返回了。
- 因此,一次组提交里面,组员越多,节约磁盘IOPS的效果越好。
两阶段提交回顾
- 写binlog,先把binlog从binlog cache中写道磁盘上的binlog文件中
- 调用fsync持久化 MySQL为了让组提交的效果更好,把redo log作fsync的时间拖到了步骤1以后。也就是说,上面的图变成了这样:
- 这么一来,binlog也能够组提交了。在执行图中第4步把binlog fsync到磁盘时,若是有多个事务的binlog已经写完了,也是一块儿持久化的,这样也能够减小IOPS的消耗。
- WAL机制是减小磁盘写,但是每次提交事务都要写redo log和binlog,这磁盘读写次数也没变少呀?
- redo log 和 binlog都是顺序写,磁盘的顺序写比随机写速度要快;
- 组提交机制,能够大幅度下降磁盘的IOPS消耗。
若是你的MySQL如今出现了性能瓶颈,并且瓶颈在IO上,能够经过哪些方法来提高性能呢?
- 设置 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count参数,减小binlog的写盘次数。这个方法是基于“额外的故意等待”来实现的,所以可能会增长语句的响应时间,但没有丢失数据的风险。
- 将sync_binlog 设置为大于1的值(比较常见是100~1000)。这样作的风险是,主机掉电时会丢binlog日志。