4. MySQL参数优化测试
mysqlslap --defaults-file=/etc/my.cnf \
--concurrency=100 --iterations=1 --create-schema='test' \
--query="select * from test.t100w where k2='FGCD'" engine=innodb \
--number-of-queries=2000 -uroot -p123 -verbose
5. 数据库实例层优化细节:
5.1 参数优化
Max_connections *****
(1)简介
Mysql的最大连接数,如果服务器的并发请求量比较大,可以调高这个值,当然这是要建立在机器能够支撑的情况下,因为如果连接数越来越多,mysql会为每个连接提供缓冲区,就会开销的越多的内存,所以需要适当的调整该值,不能随便去提高设值。
(2)判断依据
show variables like 'max_connections';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| max_connections | 151 |
+-----------------+-------+
show status like 'Max_used_connections';
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| Max_used_connections | 101 |
+----------------------+-------+
(3)修改方式举例
vim /etc/my.cnf
Max_connections=1024
补充:
1.开启数据库时,我们可以临时设置一个比较大的测试值
2.观察show status like 'Max_used_connections';变化
3.如果max_used_connections跟max_connections相同,
那么就是max_connections设置过低或者超过服务器的负载上限了,
低于10%则设置过大.
小问题:
配置修改为1000,但是最终生效的是214个Connections? 为啥?
/etc/security/limits.conf
nofile 文件句柄数放开限制 65535
http 409错误,达到连接数上限
mysqlslap: Error when connecting to server: 1040 Too many connections
select concat("kill ",id,";")
from processlist
where COMMAND='sleep'
into outfile '/tmp/kill.sql';
5.2 back_log ***
(1)简介
mysql能暂存的连接数量,当主要mysql线程在一个很短时间内得到非常多的连接请求时候它就会起作用,如果mysql的连接数据达到max_connections时候,新来的请求将会被存在堆栈中,等待某一连接释放资源,该推栈的数量及back_log,如果等待连接的数量超过back_log,将不被授予连接资源。
back_log值指出在mysql暂时停止回答新请求之前的短时间内有多少个请求可以被存在推栈中,只有如果期望在一个短时间内有很多连接的时候需要增加它
(2)判断依据
show full processlist
发现大量的待连接进程时,就需要加大back_log或者加大max_connections的值
(3)修改方式举例
vim /etc/my.cnf
back_log=100
5.3wait_timeout和interactive_timeout ****
(1)简介
wait_timeout:指的是mysql在关闭一个非交互的连接之前所要等待的秒数
interactive_timeout:指的是mysql在关闭一个交互的连接之前所需要等待的秒数,比如我们在终端上进行mysql管理,使用的即使交互的连接,这时候,如果没有操作的时间超过了interactive_time设置的时间就会自动的断开,默认的是28800,可调优为7200。
wait_timeout:如果设置太小,那么连接关闭的就很快,从而使一些持久的连接不起作用
(2)设置建议
如果设置太大,容易造成连接打开时间过长,在show processlist时候,能看到很多的连接 ,一般希望wait_timeout尽可能低
(3)修改方式举例
wait_timeout=60
interactive_timeout=1200
长连接的应用,为了不去反复的回收和分配资源,降低额外的开销。
一般我们会将wait_timeout设定比较小,interactive_timeout要和应用开发人员沟通长链接的应用是否很多。如果他需要长链接,那么这个值可以不需要调整。
另外还可以使用类外的参数弥补。
5.4 key_buffer_size *****
(1)简介
key_buffer_size指定索引缓冲区的大小,它决定索引处理的速度,尤其是索引读的速度
《1》此参数与myisam表的索引有关
《2》临时表的创建有关(多表链接、子查询中、union)
在有以上查询语句出现的时候,需要创建临时表,用完之后会被丢弃
临时表有两种创建方式:
内存中------->key_buffer_size
磁盘上------->ibdata1(5.6)
ibtmp1 (5.7)
(2)设置依据
可以使用检查状态值created_tmp_disk_tables得知:
mysql> show status like "created_tmp%";
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 0 |
| Created_tmp_files | 6 |
| Created_tmp_tables | 1 |
+-------------------------+-------+
公式:
Created_tmp_disk_tables/Created_tmp_disk_tables+ Created_tmp_tables <10%
看以下例子:
在调用mysqldump备份数据时,大概执行步骤如下:
180322 17:39:33 7 Connect root@localhost on
7 Query /*!40100 SET @@SQL_MODE='' */
7 Init DB guo
7 Query SHOW TABLES LIKE 'guo'
7 Query LOCK TABLES `guo` READ /*!32311 LOCAL */
7 Query SET OPTION SQL_QUOTE_SHOW_CREATE=1
7 Query show create table `guo`
7 Query show fields from `guo`
7 Query show table status like 'guo'
7 Query SELECT /*!40001 SQL_NO_CACHE */ * FROM `guo`
7 Query UNLOCK TABLES
7 Quit
其中,有一步是:show fields from `guo`。从slow query记录的执行计划中,可以知道它也产生了 Tmp_table_on_disk。
所以说,以上公式并不能真正反映到mysql里临时表的利用率,有些情况下产生的 Tmp_table_on_disk 我们完全不用担心,因此没必要过分关注 Created_tmp_disk_tables,但如果它的值大的离谱的话,那就好好查一下,你的服务器到底都在执行什么查询了。
(3)配置方法
key_buffer_size=4M
5.5 query_cache_size ***
(1)简介:
查询缓存简称QC,使用查询缓冲,mysql将查询结果存放在缓冲区中,今后对于同样的select语句(区分大小写),将直接从缓冲区中读取结果。
SQL: select * from t1 where id=10; ---> hash---> xxxxx
id zhangsan
select * from t1 where id=11; ---->hash ----->yyy
小例子:
由于分区表,开启了查询换存,并发查询能力降低.
分区表不走查询缓存,查询缓存越大,并发能力.
1000+ 降低到 400+
5.6 max_connect_errors ***
max_connect_errors是一个mysql中与安全有关的计数器值,它负责阻止过多尝试失败的客户端以防止暴力破解密码等情况,当超过指定次数,mysql服务器将禁止host的连接请求,直到mysql服务器重启或通过flush hosts命令清空此host的相关信息 max_connect_errors的值与性能并无太大关系。
修改/etc/my.cnf文件,在[mysqld]下面添加如下内容
max_connect_errors=2000
5.7 sort_buffer_size ***
(1)简介:
每个需要进行排序的线程分配该大小的一个缓冲区。增加这值加速
ORDER BY
GROUP BY
distinct
union
(2)配置依据
Sort_Buffer_Size并不是越大越好,由于是connection级的参数,过大的设置+高并发可能会耗尽系统内存资源。
列如:500个连接将会消耗500*sort_buffer_size(2M)=1G内存
(3)配置方法
修改/etc/my.cnf文件,在[mysqld]下面添加如下:
sort_buffer_size=1M
5.8 max_allowed_packet *****
(1)简介:
mysql根据配置文件会限制,server接受的数据包大小。
(2)配置依据:
有时候大的插入和更新会受max_allowed_packet参数限制,导致写入或者更新失败,更大值是1GB,必须设置1024的倍数
(3)配置方法:
max_allowed_packet=32M
5.9 join_buffer_size ****
select a.name,b.name from a join b on a.id=b.id where xxxx
用于表间关联缓存的大小,和sort_buffer_size一样,该参数对应的分配内存也是每个连接独享。
尽量在SQL与方面进行优化,效果较为明显。
优化的方法:在on条件列加索引,至少应当是有MUL索引
替代方案:
1. 选择结果集少的作为驱动表
2. 多表连接时,加入合适的where条件和索引
BNL BKA
a
id name aid
1 a 11
2 b 22
3 c 33
4 d 44
5 e 55
b
id addr tel
11 bj 110
22 sh 120
33 tj 119
44 cq 112
55 sz 114
5.10 thread_cache_size *****
(1)简介
服务器线程缓存,这个值表示可以重新利用保存在缓存中线程的数量,当断开连接时,那么客户端的线程将被放到缓存中以响应下一个客户而不是销毁(前提是缓存数未达上限),如果线程重新被请求,那么请求将从缓存中读取,如果缓存中是空的或者是新的请求,那么这个线程将被重新创建,如果有很多新的线程,增加这个值可以改善系统性能.
(2)配置依据
通过比较 Connections 和 Threads_created 状态的变量,可以看到这个变量的作用。
设置规则如下:1GB 内存配置为8,2GB配置为16,3GB配置为32,4GB或更高内存,可配置更大。
服务器处理此客户的线程将会缓存起来以响应下一个客户而不是销毁(前提是缓存数未达上限)
试图连接到MySQL(不管是否连接成功)的连接数
mysql> show status like 'threads_%';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Threads_cached | 8 |
| Threads_connected | 2 |
| Threads_created | 4783 |
| Threads_running | 1 |
+-------------------+-------+
4 rows in set (0.00 sec)
Threads_cached :代表当前此时此刻线程缓存中有多少空闲线程。
Threads_connected:代表当前已建立连接的数量,因为一个连接就需要一个线程,所以也可以看成当前被使用的线程数。
Threads_created:代表从最近一次服务启动,已创建线程的数量,如果发现Threads_created值过大的话,表明MySQL服务器一直在创建线程,这也是比较耗cpu SYS资源,可以适当增加配置文件中thread_cache_size值。
Threads_running :代表当前激活的(非睡眠状态)线程数。并不是代表正在使用的线程数,有时候连接已建立,但是连接处于sleep状态。
(3)配置方法:
thread_cache_size=32
整理:
Threads_created :一般在架构设计阶段,会设置一个测试值,做压力测试。
结合zabbix监控,看一段时间内此状态的变化。
如果在一段时间内,Threads_created趋于平稳,说明对应参数设定是OK。
如果一直陡峭的增长,或者出现大量峰值,那么继续增加此值的大小,在系统资源够用的情况下(内存)
5.11 innodb_buffer_pool_size *****
(1)简介
对于InnoDB表来说,innodb_buffer_pool_size的作用就相当于key_buffer_size对于MyISAM表的作用一样。
(2)配置依据:
InnoDB使用该参数指定大小的内存来缓冲数据和索引。
对于单独的MySQL数据库服务器,最大可以把该值设置成物理内存的80%,一般我们建议不要超过物理内存的70%。
(3)配置方法
innodb_buffer_pool_size=2048M
show engine innodb status \G
5.12 innodb_flush_log_at_trx_commit ******
(1)简介
主要控制了innodb将log buffer中的数据写入日志文件并flush磁盘的时间点,取值分别为0、1、2三个。
0,表示当事务提交时,不做日志写入操作,而是每秒钟将log buffer中的数据写入日志文件并flush磁盘一次;
1,
每次事务的提交都会引起redo日志文件写入、flush磁盘的操作,确保了事务的ACID;
2,每次事务提交引起写入日志文件的动作,但每秒钟完成一次flush磁盘操作。
(2)配置依据
实际测试发现,该值对插入数据的速度影响非常大,设置为2时插入10000条记录只需要2秒,设置为0时只需要1秒,而设置为1时则需要229秒。因此,MySQL手册也建议尽量将插入操作合并成一个事务,这样可以大幅提高速度。
根据MySQL官方文档,在允许丢失最近部分事务的危险的前提下,可以把该值设为0或2。
(3)配置方法
innodb_flush_log_at_trx_commit=1
双1标准中的一个1
5.13 innodb_thread_concurrency ***
(1)简介
此参数用来设置innodb线程的并发数量,默认值为0表示不限制。
(2)配置依据
在官方doc上,对于innodb_thread_concurrency的使用,也给出了一些建议,如下:
如果一个工作负载中,并发用户线程的数量小于64,建议设置innodb_thread_concurrency=0;
如果工作负载一直较为严重甚至偶尔达到顶峰,建议先设置innodb_thread_concurrency=128,
并通过不断的降低这个参数,96, 80, 64等等,直到发现能够提供最佳性能的线程数,
例如,假设系统通常有40到50个用户,但定期的数量增加至60,70,甚至200。你会发现,
性能在80个并发用户设置时表现稳定,如果高于这个数,性能反而下降。在这种情况下,
建议设置innodb_thread_concurrency参数为80,以避免影响性能。
如果你不希望InnoDB使用的虚拟CPU数量比用户线程使用的虚拟CPU更多(比如20个虚拟CPU),
建议通过设置innodb_thread_concurrency 参数为这个值(也可能更低,这取决于性能体现),
如果你的目标是将MySQL与其他应用隔离,你可以l考虑绑定mysqld进程到专有的虚拟CPU。
但是需 要注意的是,这种绑定,在myslqd进程一直不是很忙的情况下,可能会导致非最优的硬件使用率。在这种情况下,
你可能会设置mysqld进程绑定的虚拟 CPU,允许其他应用程序使用虚拟CPU的一部分或全部。
在某些情况下,最佳的innodb_thread_concurrency参数设置可以比虚拟CPU的数量小。
定期检测和分析系统,负载量、用户数或者工作环境的改变可能都需要对innodb_thread_concurrency参数的设置进行调整。
128 -----> top cpu
设置标准:
1、当前系统cpu使用情况,均不均匀
top
2、当前的连接数,有没有达到顶峰
show status like 'threads_%';
show processlist;
(3)配置方法:
innodb_thread_concurrency=8
方法:
1. 看top ,观察每个cpu的各自的负载情况
2. 发现不平均,先设置参数为cpu个数,然后不断增加(一倍)这个数值
3. 一直观察top状态,直到达到比较均匀时,说明已经到位了.
5.14 innodb_log_buffer_size
此参数确定些日志文件所用的内存大小,以M为单位。缓冲区更大能提高性能,对于较大的事务,可以增大缓存大小。
innodb_log_buffer_size=128M
设定依据:
1、大事务: 存储过程调用 CALL
2、多事务
5.15 innodb_log_file_size = 256M *****
设置 ib_logfile0 ib_logfile1
此参数确定数据日志文件的大小,以M为单位,更大的设置可以提高性能.
innodb_log_file_size = 256M
innodb_log_files_in_group = 3-5 *****
为提高性能,MySQL可以以循环方式将日志文件写到多个文件。推荐设置为3
read_buffer_size = 1M **
MySql读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySql会为它分配一段内存缓冲区。如果对表的顺序扫描请求非常频繁,并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能。和 sort_buffer_size一样,该参数对应的分配内存也是每个连接独享
read_rnd_buffer_size = 1M **
MySql的随机读(查询操作)缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,MySql会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要排序大量数据,可适当调高该值。但MySql会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大。
注:顺序读是指根据索引的叶节点数据就能顺序地读取所需要的行数据。随机读是指一般需要根据辅助索引叶节点中的主键寻找实际行数据,而辅助索引和主键所在的数据段不同,因此访问方式是随机的。
bulk_insert_buffer_size = 8M **
批量插入数据缓存大小,可以有效提高插入效率,默认为8M
change buffer
binary log *****
log-bin=/data/mysql-bin
binlog_cache_size = 2M
//为每个session 分配的内存,在事务过程中用来存储二进制日志的缓存, 提高记录bin-log的效率。没有什么大事务,dml也不是很频繁的情况下可以设置小一点,如果事务大而且多,dml操作也频繁,则可以适当的调大一点。前者建议是--1M,后者建议是:即 2--4M
max_binlog_cache_size = 8M
//表示的是binlog 能够使用的最大cache 内存大小
max_binlog_size= 512M
//指定binlog日志文件的大小,如果当前的日志大小达到max_binlog_size,还会自动创建新的二进制日志。你不能将该变量设置为大于1GB或小于4096字节。默认值是1GB。在导入大容量的sql文件时,建议关闭sql_log_bin,否则硬盘扛不住,而且建议定期做删除。
expire_logs_days = 7
//定义了mysql清除过期日志的时间。
二进制日志自动删除的天数。默认值为0,表示“没有自动删除”。
binlog_format=row
sync_binlog=1
双1标准(基于安全的控制):
sync_binlog=1
innodb_flush_log_at_trx_commit=1
set sql_log_bin=0;
show status like 'com_%';
安全参数 *****
Innodb_flush_method=(O_DIRECT, fsync)
1、fsync :
(1)在数据页需要持久化时,首先将数据写入OS buffer中,然后由os决定什么时候写入磁盘
(2)在redo buffuer需要持久化时,首先将数据写入OS buffer中,然后由os决定什么时候写入磁盘
但,如果innodb_flush_log_at_trx_commit=1的话,日志还是直接每次commit直接写入磁盘
2、 Innodb_flush_method=O_DIRECT
(1)在数据页需要持久化时,直接写入磁盘
(2)在redo buffuer需要持久化时,首先将数据写入OS buffer中,然后由os决定什么时候写入磁盘
但,如果innodb_flush_log_at_trx_commit=1的话,日志还是直接每次commit直接写入磁盘
一般情况下,我们更偏向于安全。
“双一标准”
innodb_flush_log_at_trx_commit=1
sync_binlog=1
innodb_flush_method=O_DIRECT
偏向性能
innodb_flush_log_at_trx_commit=0
sync_binlog=0
innodb_flush_method=fsync
6. 参数优化结果
[mysqld]
basedir=/data/mysql
datadir=/data/mysql/data
socket=/tmp/mysql.sock
log-error=/var/log/mysql.log
log_bin=/data/binlog/mysql-bin
binlog_format=row
skip-name-resolve
server-id=52
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
relay_log_purge=0
max_connections=1024
back_log=128
wait_timeout=60
interactive_timeout=7200
key_buffer_size=16M
query_cache_size=64M
query_cache_type=1
query_cache_limit=50M
max_connect_errors=20
sort_buffer_size=2M
max_allowed_packet=32M
join_buffer_size=2M
thread_cache_size=200
innodb_buffer_pool_size=1024M
innodb_flush_log_at_trx_commit=1
innodb_log_buffer_size=32M
innodb_log_file_size=128M
innodb_log_files_in_group=3
binlog_cache_size=2M
max_binlog_cache_size=8M
max_binlog_size=512M
expire_logs_days=7
read_buffer_size=2M
read_rnd_buffer_size=2M
bulk_insert_buffer_size=8M
[client]
socket=/tmp/mysql.sock
再次压力测试 :
mysqlslap --defaults-file=/etc/my.cnf \
--concurrency=100 --iterations=1 --create-schema='test' \
--query="select * from test.t100w where k2='FGCD'" engine=innodb \
--number-of-queries=2000 -uroot -p -verbose
7. 锁的监控及处理 ******
7.1 锁等待模拟
概念:
MDL : metadata lock
元数据,数据字典锁?
存储位置(5.7):
frm
ibdata1
mysql
p_s
sys
information_schema
什么时候触发?
DDL ----> MDL
备份 ----> FTWRL
手工触发 FTWRL
Table Lock
DDL 操作
lock table
Record Lock
update
delete
insert
select for update /lock in shared mode
GAP Lock
update t1 set salary=3000 where salary<3000;
1000
1999
1800
1500
insert into 1700
Next Lock
X
IX
S
IS
=============================================================
tx1:
USE oldboy
UPDATE t_100w SET k1='av' WHERE id=10;
tx2:
USE oldboy
UPDATE t_100w SET k1='az' WHERE id=10;
监控锁状态:
1. 看有没有锁等待
SHOW STATUS LIKE 'innodb_row_lock%';
2. 查看哪个事务在等待(被阻塞了)
USE information_schema
SELECT * FROM information_schema.INNODB_TRX WHERE trx_state='LOCK WAIT';
trx_id : 事务ID号
trx_state : 当前事务的状态
trx_mysql_thread_id:连接层的,连接线程ID(SHOW PROCESSLIST ===>Id或trx_id )
trx_query : 当前被阻塞的操作(一般是要丢给开发的)
7.3.查看锁源,谁锁的我!
SELECT * FROM sys.innodb_lock_waits; ## ====>被锁的和锁定它的之间关系
locked_table : 哪张表出现的等待
waiting_trx_id: 等待的事务(与上个视图trx_id 对应)
waiting_pid : 等待的线程号(与上个视图trx_mysql_thread_id)
blocking_trx_id : 锁源的事务ID
blocking_pid : 锁源的线程号
7.4. 找到锁源的thread_id
SELECT * FROM performance_schema.threads WHERE processlist_id=15;
====> 41
7.5. 找到锁源的SQL语句
-- 当前在执行的语句
SELECT * FROM performance_schema.`events_statements_current` WHERE thread_id=41;
-- 执行语句的历史
SELECT * FROM performance_schema.`events_statements_history` WHERE thread_id=41;
得出结果,丢给开发
表信息
被阻塞的
锁源SQL
7.6 优化项目:锁的监控及处理
1. 背景:
硬件环境: DELL R720,E系列16核,48G MEM,SAS*900G*6,RAID10
在例行巡检时,发现9-11点时间段的CPU压力非常高(80-90%)
2. 项目的职责
2.1 通过top详细排查,发现mysqld进程占比达到了700-800%
2.2 其中有量的CPU是被用作的SYS和WAIT,us处于正常
2.3 怀疑是MySQL 锁 或者SQL语句出了问题
2.4 经过排查slowlog及锁等待情况,发现有大量锁等待及少量慢语句
(1) pt-query-diagest 查看慢日志
(2) 锁等待有没有?
db03 [(none)]>show status like 'innodb_row_lock%';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| Innodb_row_lock_current_waits | 0 |
| Innodb_row_lock_time | 0 |
| Innodb_row_lock_time_avg | 0 |
| Innodb_row_lock_time_max | 0 |
| Innodb_row_lock_waits | 0 |
+-------------------------------+-------+
情况一:
有100多个current_waits,说明当前很多锁等待情况
情况二:
1000多个lock_waits,说明历史上发生过的锁等待很多
2.5 查看那个事务在等待(被阻塞了)
2.6 查看锁源事务信息(谁锁的我)
2.7 找到锁源的thread_id
2.8 找到锁源的SQL语句
3. 找到语句之后,和应用开发人员进行协商
(1)
开发人员描述,此语句是事务挂起导致
我们提出建议是临时kill 会话,最终解决问题
(2)
开发人员查看后,发现是业务逻辑问题导致的死锁,产生了大量锁等待
临时解决方案,将阻塞事务的会话kill掉.
最终解决方案,修改代码中的业务逻辑
项目结果:
经过排查处理,锁等待的个数减少80%.解决了CPU持续峰值的问题.
锁监控涉及到的命令:
show status like 'innodb_rows_lock%'
select * from information_schema.innodb_trx;
select * from sys.innodb_lock_waits;
select * from performance_schema.threads;
select * from performance_schema.events_statements_current;
select * from performance_schema.events_statements_history;
7.7 死锁监控
show engine innodb status\G ----> 最后一次放生的死锁信息.
show variables like '%deadlock%';
vim /etc/my.cnf
innodb_print_all_deadlocks = 1
主从延时?
1. 主库原因:
(1) binlog写入不及时.
sync_binlog=1?
IO太慢. ---> SSD
(2) 传统(无GTID)
传输日志binlog是串行工作的.
5.6 以后加入了GTID,并行传输.
(3) 其他原因
网络慢
主库压力大
从库太多
主从配置不一致
主从参数
主从版本
2. 从库原因:
SQL线程串行工作.
5.7 中加入Logical_clock 逻辑时钟,可以实现SQL线程并行回放relaylog
8. 主从优化:
5.7 从库多线程MTS
基本要求:
5.7以上的版本(忘记小版本)
必须开启GTID
binlog必须是row模式
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=16
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON
5.7 :
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=8
cpu核心数作为标准
CHANGE MASTER TO
MASTER_HOST='10.0.0.128',
MASTER_USER='repl',
MASTER_PASSWORD='123',
MASTER_PORT=3307,
MASTER_AUTO_POSITION=1;
start slave;
扩展PT工具的应用:
1. pt工具安装
[root@master ~]# yum install -y percona-toolkit-3.1.0-2.el7.x86_64.rpm
2. 常用工具使用介绍
2.1 pt-archiver 归档表
# 重要参数
--limit 100 每次取100行数据用pt-archive处理
--txn-size 100 设置100行为一个事务提交一次,
--where 'id<3000' 设置操作条件
--progress 5000 每处理5000行输出一次处理信息
--statistics 输出执行过程及最后的操作统计。(只要不加上--quiet,默认情况下pt- archive都会输出执行过程的)
--charset=UTF8 指定字符集为UTF8—这个最后加上不然可能出现乱码。
--bulk-delete 批量删除source上的旧数据(例如每次1000行的批量删除操作)
注意: 需要归档表中至少有一个索引,做好是where条件列有索引
使用案例:
1.归档到数据库
db01 [test]>create table test1 like t100w;
pt-archiver --source h=10.0.0.51,D=test,t=t100w,u=oldguo,p=123 --dest h=10.0.0.51,D=test,t=test1,u=oldguo,p=123 --where 'id<10000' --no-check-charset --no-delete --limit=1000 --commit-each --progress 1000 --statistics
2.只清理数据
pt-archiver --source h=10.0.0.51,D=test,t=t100w,u=oldguo,p=123 --where 'id<10000' --purge --limit=1 --no-check-charset
3.只把数据导出到外部文件,但是不删除源表里的数据
pt-archiver --source h=10.0.0.11,D=world,t=city,u=root,p=123 --where '1=1' --no-check-charset --no-delete --file="/tmp/archiver.dat"
2.2 pt-osc
pt-osc工作流程:
1、检查更改表是否有主键或唯一索引,是否有触发器
2、检查修改表的表结构,创建一个临时表,在新表上执行ALTER TABLE语句
create table bak like t1;
alter table bak add telnum char(11) not null;
3、在源表上创建三个触发器分别对于INSERT UPDATE DELETE操作
create trigger
a
b
c
4、从源表拷贝数据到临时表,在拷贝过程中,对源表的更新操作会写入到新建表中
insert into bak select * from t1
5、将临时表和源表rename(需要元数据修改锁,需要短时间锁表)
6、删除源表和触发器,完成表结构的修改。
pt-osc工具限制
1、源表必须有主键或唯一索引,如果没有工具将停止工作
2、如果线上的复制环境过滤器操作过于复杂,工具将无法工作
3、如果开启复制延迟检查,但主从延迟时,工具将暂停数据拷贝工作
4、如果开启主服务器负载检查,但主服务器负载较高时,工具将暂停操作
5、当表使用外键时,如果未使用--alter-foreign-keys-method参数,工具将无法执行
6、只支持Innodb存储引擎表,且要求服务器上有该表1倍以上的空闲空间。
pt-osc之alter语句限制
1、不需要包含alter table关键字,可以包含多个修改操作,使用逗号分开,如"drop clolumn c1, add column c2 int"
2、不支持rename语句来对表进行重命名操作
3、不支持对索引进行重命名操作
4、如果删除外键,需要对外键名加下划线,如删除外键fk_uid, 修改语句为"DROP FOREIGN KEY _fk_uid"
pt-osc之命令模板
## --execute表示执行
## --dry-run表示只进行模拟测试
## 表名只能使用参数t来设置,没有长参数
pt-online-schema-change \
--host="127.0.0.1" \
--port=3358 \
--user="root" \
--password="root@root" \
--charset="utf8" \
--max-lag=10 \
--check-salve-lag='xxx.xxx.xxx.xxx' \
--recursion-method="hosts" \
--check-interval=2 \
--database="testdb1" \
t="tb001" \
--alter="add column c4 int" \
--execute
例子:
pt-online-schema-change --user=oldguo --password=123 --host=10.0.0.51 --alter "add column age int default 0" D=test,t=t1 --print --execute
pt-online-schema-change --user=oldguo --password=123 --host=10.0.0.51 --alter "add index idx(name)" D=test,t=t1 --print --execute
2.3 pt-table-checksum
2.3.1 创建数据库
Create database pt CHARACTER SET utf8;
创建用户checksum并授权
GRANT ALL ON *.* TO 'checksum'@'10.0.0.%' IDENTIFIED BY 'checksum';
flush privileges;
2.3.2 参数:
--[no]check-replication-filters:是否检查复制的过滤器,默认是yes,建议启用不检查模式。
--databases | -d:指定需要被检查的数据库,多个库之间可以用逗号分隔。
--[no]check-binlog-format:是否检查binlog文件的格式,默认值yes。建议开启不检查。因为在默认的row格式下会出错。
--replicate`:把checksum的信息写入到指定表中。
--replicate-check-only:只显示不同步信息
pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate=pt.checksums --create-replicate-table --databases=test --tables=t1 h=10.0.0.51,u=checksum,p=checksum,P=3306
#!/bin/bash
date >> /root/db/checksum.log
pt-table-checksum --nocheck-binlog-format --nocheck-plan --nocheck-replication-filters --replicate=pt.checksums --set-vars innodb_lock_wait_timeout=120 --databases test --tables t1 -u'checksum' -p'checksum' -h'10.0.0.51' >> /tmp/checksum.log
date >> /root/db/checksum.log
2.4 pt-table-sync
主要参数介绍
--replicate :指定通过pt-table-checksum得到的表.
--databases : 指定执行同步的数据库。
--tables :指定执行同步的表,多个用逗号隔开。
--sync-to-master :指定一个DSN,即从的IP,他会通过show processlist或show slave status 去自动的找主。
h= :服务器地址,命令里有2个ip,第一次出现的是Master的地址,第2次是Slave的地址。
u= :帐号。
p= :密码。
--print :打印,但不执行命令。
--execute :执行命令。
pt-table-sync --replicate=pt.checksums --databases test --tables t1 h=10.0.0.51,u=checksum,p=checksum,P=3306 h=10.0.0.52,u=checksum,p=checksum,P=3306 --print
pt-table-sync --replicate=pt.checksums --databases test --tables t1 h=10.0.0.51,u=checksum,p=checksum,P=3306 h=10.0.0.52,u=checksum,p=checksum,P=3306 --execute
2.5 mysql死锁监测
pt-deadlock-logger h='127.0.0.1' --user=root --password=123456
2.6 主键冲突检查
pt-duplicate-key-checker --database=world h='127.0.0.1' --user=root --password=123456
2.7 pt-kill 语句
常用参数说明
--daemonize 放在后台以守护进程的形式运行;
--interval 多久运行一次,单位可以是s,m,h,d等默认是s –不加这个默认是5秒
--victims 默认是oldest,只杀最古老的查询。这是防止被查杀是不是真的长时间运行的查询,他们只是长期等待 这种种匹配按时间查询,杀死一个时间最高值。
--all 杀掉所有满足的线程
--kill-query 只杀掉连接执行的语句,但是线程不会被终止
--print 打印满足条件的语句
--busy-time 批次查询已运行的时间超过这个时间的线程;
--idle-time 杀掉sleep 空闲了多少时间的连接线程,必须在--match-command sleep时才有效—也就是匹配使用 -- –match-command 匹配相关的语句。
----ignore-command 忽略相关的匹配。 这两个搭配使用一定是ignore-commandd在前 match-command在后,
--match-db cdelzone 匹配哪个库
command有:Query、Sleep、Binlog Dump、Connect、Delayed insert、Execute、Fetch、Init DB、Kill、Prepare、Processlist、Quit、Reset stmt、Table Dump
例子:
### 杀掉空闲链接sleep 5秒的 SQL 并把日志放到/home/pt-kill.log文件中
/usr/bin/pt-kill --user=用户名 --password=密码 --match-command Sleep --idle-time 5 --victim all --interval 5 --kill --daemonize -S /tmp/mysql.sock --pid=/tmp/ptkill.pid --print --log=/tmp/pt-kill.log &
### 查询SELECT 超过1分钟
/usr/bin/pt-kill --user=用户名 --password=密码 --busy-time 60 --match-info "SELECT|select" --victim all --interval 5 --kill --daemonize -S -S /tmp/mysql.sock --pid=/tmp/ptkill.pid --print --log=/tmp/pt-kill.log &
### Kill掉 select IFNULl.*语句开头的SQL
pt-kill --user=用户名 --password=密码 --victims all --busy-time=0 --match-info="select IFNULl.*" --interval 1 -S /tmp/mysqld.sock --kill --daemonize --pid=/tmp/ptkill.pid --print --log=/tmp/pt-kill.log &
### kill掉state Locked
/usr/bin/pt-kill --user=用户名 --password=密码 --victims all --match-state='Locked' --victim all --interval 5 --kill --daemonize -S /tmp/mysqld.sock --pid=/tmp/ptkill.pid --print --log=/tmp/pt-kill.log &
### kill掉 a库,web为10.0.0.11的链接
pt-kill --user=用户名 --password=密码 --victims all --match-db='a' --match-host='10.0.0.11' --kill --daemonize --interval 10 -S /tmp/mysqld.sock --pid=/tmp/ptkill.pid --print-log=/tmp/pt-kill.log &
### 指定哪个用户kill
pt-kill --user=用户名 --password=密码 --victims all --match-user='root' --kill --daemonize --interval 10 -S /home/zb/data/my6006/socket/mysqld.sock --pid=/tmp/ptkill.pid --print --log=/home/pt-kill.log &
### 查询SELECT 超过1分钟路
pt-kill --user=用户名 --password=密码 --busy-time 60 --match-info "SELECT|select" --victim all --interval 5 --kill --daemonize -S /tmp/mysqld.sock --pid=/tmp/ptkill.pid --print --log=/tmp/pt-kill.log &
### kill掉 command query | Execute
pt-kill --user=用户名 --password=密码 --victims all --match-command= "query|Execute" --interval 5 --kill --daemonize -S /tmp/mysqld.sock --pid=/tmp/ptkill.pid --print --log=/home/pt-kill.log &
2.8 其他
pt-find ---找出几天之前建立的表
pt-slave-restart -----主从报错,跳过报错
pt-summary ---整个系统的的概述
pt-mysql-summary ---MySQL的表述,包括配置文件的描述
pt-duplicate-key-checker ---检查数据库重复索引