硬件优化
2022-08-27
1.1 关闭 numa
a.在bios层面,关闭numa;无论os层面的numa是否打开,都不会影响性能;
numactl --hardware
available: 1 nodes (0) 如果是2或者多个nodes就说明没有关闭numa
b.os grub 级别
vim /boot/grub2/grub.cfg
c.数据库级别
show variables like '%numa%';
或者:
vim /etc/init.d/mysqld
1.2 开启cpu高性能模式
1.3 阵列卡配置建议
raid10(推荐)
ssd 或者 pci-e 或者flash
强制回写(force writeback)
bbu 电池:如果没点会有较大性能影响、定期充放电,如果ups、多电路、发电机。可以关闭。
关闭预读
又肯呢个的话,开启cache(如果ups、多路电源、发电机)
1.4 关闭THP
vim /etc/rc.local
[root@master ~] cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]
[root@master ~] cat /sys/kernel/mm/transparent_hugepage/defrag
always madvise [never]
1.5 网卡绑定
bonding技术
建议使用主备模式
1.6 存储多路径
使用独立存储设备的话,需要配置多路径
linux自带:multipath
厂商提供
系统层面优化
a. 更改文件句柄和进程数
内核优化 /etc/sysctl.conf
vm.swappiness = 5 # swarp 使用
vm.dirty_ratio = 20
vm.dirty_background_ratio = 10
net.ipv4.tcp_max_syn_backlog = 819200
net.core.netdev_max_backlog = 400000
net.core.somaxconn = 4096
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 0
补充:
vm.dirty_ratio=20 -- 阻塞式刷新,强制刷新
vm.dirty_background_ratio = 10 -- 异步刷新,等待业务低谷时刷新
内存脏页/系统可用内存(free+BUF/ CACHE)
百分比达到比例,会刷脏页到磁盘。
=========================. 生产案例==========
监控显示内存 95%+
MySQL 实例:session mem (sort join read read rnd key heap table..) + shard mem (buffer pool \log buffer)
文件系统缓存---> binlog redo--> flush os cache---> sync
应急处理:
1. 文件系统:buff/ cache 20g ---> vm.dirty_ratio
2. 数据库:top 70g --- ckpt?
Innodb FLUSH METHOD = O_Direct
P_S 开的项目太低,会导致内存泄漏
=========================================
b. 防火墙
禁用 selinux: /etc/sysconfig/selinux 更改 SELINUX=disabled.
Iptables 如果不使用可以关闭。可是需要打开 MySQL 需要的端口号
c. 文件系统优化推荐使用 XFS 文件系统
MySQL数据分区独立,例如挂载点为:/data
mount 参数 defaults, noatime, nodiratime, nobarrier 如/etc/fstab:
/dev/sdb /data xfs defaults,noatime,nodiratime,nobarrier 1 2 # 这里不推荐检查磁盘,1 2 可以直接设置为 0 0
d. 不用lvm
e. io调用
SAS:deadline
SSD&PCI-E: noop
centos7 默认是 deadline
cat /sys/block/sda/queue/scheduler
#临时修改为 deadline (centos6)
echo deadline>/sys/block/sda/queue/scheduler
vi /boot/grub/grub.conf 更改到如下内容:
kernel /boot/vmlinuz-2.6.18-8.e15 ro root=LABEL=/ elevator=deadline rhgb quiet
补充:系统资源诊断 top
# 首先查看 mysql 的进程id;1380
[root@centos7 ~]# netstat -lnpt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 980/sshd
tcp6 0 0 :::3306 :::* LISTEN 1380/mysqld
# 使用top查看mysql具体哪个线程占用的cpu高
[root@centos7 ~]# top -Hp 1380
top - 15:01:52 up 1 day, 6 min, 1 user, load average: 0.04, 0.07, 0.01
Threads: 28 total, 0 running, 28 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 727160 total, 72620 free, 385308 used, 269232 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 238396 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1380 mysql 20 0 1550516 185648 4752 S 0.0 25.5 0:00.17 mysqld
1381 mysql 20 0 1550516 185648 4752 S 0.0 25.5 0:00.00 mysqld
1382 mysql 20 0 1550516 185648 4752 S 0.0 25.5 0:00.00 mysqld
1383 mysql 20 0 1550516 185648 4752 S 0.0 25.5 0:00.00 mysqld
1384 mysql 20 0 1550516 185648 4752 S 0.0 25.5 0:00.00 mysqld
1385 mysql 20 0 1550516 185648 4752 S 0.0 25.5 0:00.00 mysqld
1386 mysql 20 0 1550516 185648 4752 S 0.0 25.5 0:00.00 mysqld
1387 mysql 20 0 1550516 185648 4752 S 0.0 25.5 0:00.00 mysqld
1388 mysql 20 0 1550516 185648 4752 S 0.0 25.5 0:00.00 mysqld
# 这里假设是 1382 占用的cpu高,
# 接下来就去mysql内部查看该线程在做什么
[root@centos7 ~]# mysql -u root -ppassword -S /mysql/3306/mysql.sock
# 进入虚拟库
mysql> use performance_schema;
# 查看具体该线程是干啥的;
mysql> select NAME,TYPE,THREAD_OS_ID from threads where THREAD_OS_ID=1382;
+------------------------------+------------+--------------+
| NAME | TYPE | THREAD_OS_ID |
+------------------------------+------------+--------------+
| thread/innodb/io_ibuf_thread | BACKGROUND | 1382 |
+------------------------------+------------+--------------+
1 row in set (0.00 sec)
# 然后根据该线程来进行优化mysql;
2、如果是系统的io占用高;
mysql> use sys;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+-----------------------------------------------+
| Tables_in_sys |
+-----------------------------------------------+
| ... |
| io_by_thread_by_latency |
| io_global_by_file_by_bytes |
| io_global_by_file_by_latency |
| io_global_by_wait_by_bytes |
| io_global_by_wait_by_latency |
| ... |
# 这是 io 对应的表
# 查看 io 占用比较多的表的排名
mysql> select * from io_global_by_file_by_bytes;
+---------------------------------------------------------------------------------------+------------+------------+------------+-------------+---------------+------------+------------+-----------+
| file | count_read | total_read | avg_read | count_write | total_written | avg_write | total | write_pct |
+---------------------------------------------------------------------------------------+------------+------------+------------+-------------+---------------+------------+------------+-----------+
| @@datadir/ibtmp1 | 0 | 0 bytes | 0 bytes | 54 | 12.66 MiB | 240.00 KiB | 12.66 MiB | 100.00 |
| @@datadir/ibdata1 | 155 | 4.44 MiB | 29.32 KiB | 3 | 64.00 KiB | 21.33 KiB | 4.50 MiB | 1.39 |
| @@datadir/mysql/help_topic.ibd | 11 | 176.00 KiB | 16.00 KiB | 0 | 0 bytes | 0 bytes | 176.00 KiB | 0.00 |
| @@datadir/mysql/help_category.ibd | 5 | 80.00 KiB | 16.00 KiB | 0 | 0 bytes | 0 bytes | 80.00 KiB | 0.00 |
| @@datadir/sys/sys_config.ibd | 5 | 80.00 KiB | 16.00 KiB | 0 | 0 bytes | 0 bytes | 80.00 KiB | 0.00 |
| @@basedir/share/english/errmsg.sys | 3 | 76.58 KiB | 25.53 KiB | 0 | 0 bytes | 0 bytes | 76.58 KiB | 0.00 |
CPU 高怎么排查:
常规方法:
TOP -- PID---> 10
top -Hp 10 ---> TID -->110
select * from performance_ schema.threads where thread_os_id=110; --》thread_id 999,processlist id;
select * from per formance_schema.events_statements_history where thread_id=999;
经验方法:
show processlist; --- processist_id
select * from information_schema.processlist;
select * from performance_schema.threads where processist_id = 110;
select * from performance_schema.events_statements_history where thread_id=999;
内存:
RSS anno page cache buffer (mysql + fs cache)
3.数据库版本选择
基本上只调整内存参数,mysql8.0 会比 mysq 5.7 高个 2.5 倍以上
建议使用最新的版本;但是开发可能不太想用,可能需要优化一个
1、稳定版:选择开源的社区版的稳定版 GA 版本。
2、选择 mysq1 数据库 GA 版本发布后 6 个月-12 个月的 GA 双数版本,大约在 15-20 个小版本左右。
3、要选择前后几个月没有大的 BUG 修复的版本,而不是大量修复 BUG 的集中版本。
4、要考虑开发人员开发程序使用的版本是否兼容你选的版本。
5、作为内部开发测试数据库环境,跑大概 3-6 个月的时间。
6、优先企业非核心业务采用新版本的数据库 GA 版本软件。
7、向 BA 高手请教,或者在技术氛围好的群里和大家一起交流,使用真正的高手们用过的好用的 GA 版本产品。
最终建议:8.0.24 是一个不错的版本选择。向后可以选择双数版。
4.数据库三层结构及核心参数优化
4.1连接层
max_connections=1000 # 最大连接数,并发连接,不算本地连接;
max_connect_errors=999999 # 最大失败计数器;到了该数就不让连接了
wait_timeout=600 # 超时
interactive_wait_timeout=3600 #
net_read_timeout = 120 # 网络数据包延迟,
net_write_timeout = 120 #
max_allowed_packet= 32M # 最大数据包大小;备份的时候可能需要配置;
4.2 Server 层
sql_safe_updates =1 #
slow_query_log =ON
slow_query_log_file = /data/3307/slow.log
long_query_time =1
log_queries_not_using_indexes =ON
log_throttle_queries_not_using_indexes = 10
sort_buffer = 8M
join_buffer = 8M
read_buffer = 1M
read_rnd_buffer = 32M
tmp_table = 16M
heap_table = 16M
max_execution_time =28800 # mysql 8.0 默认已经不限制了;可以不用调整;
lock_wait_timeout =3600
lower_case_table_names =1 # 忽略大小写;
thread_cache_size =64
log_timestamps =SYSTEM
init_connect ="set names utf8mb4"
event_scheduler =OFF # 事件调度器
binlog_expire_logs_seconds =10 # binlog 保存时间,尽量保存一轮的全备周期
sync_binlog =1 # 刷新
log-bin =/data/3307/mysql-bin
log-bin-index =/data/3307/mysql-bin.index
max_binlog_size =500M
binlog_format =ROW
4.3 存储引擎层
Transaction-isolation ="READ-COMMITTED"
innodb_data_home_dir =/xxx
innodb_log_group_home_dir =/xxx
innodb_log_file_size =2048M # redo 日志
innodb_log_files_in_group =3 # 3 组 redo 日志
innodb_flush_log_at_trx_commit =2
innodb_flush_method =O_DIRECT # 对于数据刷新,是直接刷新到磁盘的;对于redo日志要先刷到缓存,再刷到磁盘;
innodb_io_capacity =1000 # ssd 盘,可以调整高一些;
innodb_io_capacity_max =4000 #
innodb_buffer_pool_size =64G # 一般50%
innodb_buffer_pool_instances =4 #
innodb_log_buffer_size =1024M # 根据日志文件配置
innodb_max_dirty_pages_pct =85
innodb_lock_wait_timeout =10 # 行锁
innodb_open_files =63000
innodb_page_cleaners =4
innodb_sort_buffer_size =64M # 排序缓冲区
innodb_print_all_deadlocks =1 # 死锁检测,一般打开
innodbrollback_on_timeout =ON # 8.0 默认打开
innodb_deadlock_detect =ON # 8.0 默认打开
4.4 复制
# 指定relay log 日志路径就是为了将 io 分开;数据文件存一个盘,relay log 存一个盘;
relay_log = /opt/log/mysql/blog/relay
relay_log_index = /opt/log/mysql/blog/relay.index
max_relay_log_size = 500M
relay_log_recovery = ON
rpl_semi_sync_master_enabled =ON
rpl_semi_sync_master_timeout =1000
rpl_semi_sync_master_trace_level =32
rpl_semi_sync_master_wait_forIslave_count =1
rpl_semi_sync_master_wait_no_slave =ON
rpl_semi_sync_master_wait_point =AFTER_SYNC # 启用 伴读 复制,5.7 增加的功能
rpl_semi_sync_slave_enabled =ON
rpl_semi_sync_slave_trace_level =32
binlog_group_commit_sync_delay = 1 # 每 1s 做一次批量的 gc
binlog_group_commit_sync_no_delay_count =1000 # 达到1000个也做gc,为了缓解单线程的问题
gtid_mode =ON
enforce_gtid_consistency =ON
skip-slave-start =1
#read_only =ON
#super_read_only =ON
log_slave_updates =ON
server_id =2330602
report_host =XXXX
report-port =3306
slave_parallel_type =LOGICAL_CLOCK # 多线程回放
slave_parallel_workers =4
master_info_repository =TABLE
relay_log_info_repository =TABLE
4.5 其他
客户端配置:
[mysq1]
no-auto-rehash # 客户端登录 每次 不扫描 文件,对文件句柄有缓解;加快登录速度
5.开发人员规范(优化人)
5.1字段规范
1. 每个表建议在 30 个字段以内。
2. 需要存储 emoji:字符的,则选择 utf8mb4 字符集。
3. 机密数据,加密后存储。 # 默认数据库也会有一个加密的功能,它是在引擎层次做的;
4. 整型数据,默认加上 UNSIGNED。
5. 存储 IPV4 地址建议用 INT UNSIGNE,查询时再利用 INET_ ATONO、INET_ NTOAO 函数转换。
6. 如果遇到 BLOB、TEXT 大字段单独存储表或者附件形式存储。
7 选择尽可能小的数据类型,用于节省磁盘和内存空间。
8 存储浮点数,可以放大倍数存储。 # 整数的过滤性能,比小数的过滤性能高很多;
9. 每个表必须有主键,INT/ BIGINT 并且自增做为主键,分布式架构使用 sequence,序列生成器保存。
10. 每个列使用 not nu11, 或增加默认值。
5.2 SQL 语句规范
参考:
https://dev.Mysql.com/doc/refman/8.0/en/optimization.html
### 1. 去掉不必要的括号
如: ((a AND b) AND c OR (((a AND b) AND (c AND d))))
修改成 (a AND b AND c) OR (a AND b AND c AND d)
###2. 去掉重叠条件
如: (a <b AND b=c) AND a=5
修改成 b>5 AND b=c AND a=5
如: (B> =5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6)
修改成 B=5 OR B=6
###3. 避免使用 not in、not exists、<>、1ike %%
select a.id, a.name
from
a where a.id not in (select b.id from b where b.coll='xx')
select a.id, a.name from a
left join b on a.id=b.id
where b.id is null and b.col1='xx';
### 4. 多表连接,小表驱动大表
### 5. 减少临时表应用,优化 order by、group by、union、distinct、join 等
### 6. 减少语句查询范围,精确查询条件
### 7. 多条件,符合联合索引最左原则
### 8. 查询条件减少使用函数、拼接字符等条件、条件隐式转换
### 9. Union a11 替代 union
### 10. 减少 having 子句使用
### 11. 如非必须不使用 for update 语句
### 12. Update 和 delete,开启安全更新参数
### 13. 减少 inset... Se1ect 语句应用
### 14. 使用 1oad 替代 insert 录入大数据
### 15. 导入大量数据时,可以禁用索引、增大缓冲区、增大 redo 文件和 buffer、关闭 autocommit、RC 级别可以提高效率
### 16. 优化 1imit,最好业务逻辑中先获取主键 ID,再基于 ID 进行查询
limit 5000000,10
### 17.DDL 执行前要审核
### 18. 多表连接语句执行前要看执行计划
6. 索引优化
1. 非唯一索引按照“_字段名称_字段名称【_字段名】”进行命名。
2. 唯一索引按照“u_字段名称_字段名称【_字段名】”进行命名。
3. 索引名称使用小写。
4. 索引中的字段数不超过 5 个。
5. 唯一键由 3 个以下字段组成,并且字段都是整形时,使用唯一键作为主键。
6. 没有唯一键或者唯一键不符合 5 中的条件时,使用自增 id 作为主键。7. 唯一键不和主键重复。
8. 索引选择度高的列作为联合索引最左条件
9. ORDER BY, GROUP BY, DISTINCT 的字段需要添加在索引的后面。
10. 单张表的索引数量控制在 5 个以内,若单张表多个字段在查询需求上都要单独用到索引,需要经过 BA 评估。查询性能问
题无法解决的,应从产品设计上进行重构。
11. 使用 EXPLAIN 判断 sQL 语句是否合理使用索引,尽量避免 extra 列出现:Using Fi e Sort, Using Temporary。12. UPDATE、DELETE 语句需要根据 WHERE 条件添加索引。
12, UPDATE、DELETE 语句需要根据 WHERE 条件添加索引。
13. 对长度大于 50 的 VARCHAR 字段 建立索引时,按需求恰当的使用前缀索引,或使用其他方法。
14. 下面的表增加一列 ur1_crc32, 然后对 ur1_crc32 建立索引,减少索引字段的长度,提高效率。
CREATE TABLE all_url(ID INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
url VARCHAR(255) NOT NULL DEFAULT 0,
url_crc32 INT UNSIGNED NOT NULL DEFAULT 0,
index idx_url(url_crc32));
15. 合理创建联合索引(避免元余),(a, b, c)相当于(a)、(a, b)、(a, b, c)。
具体可以查看sys库中的表;哪个表暂时忘了
16. 合理利用覆盖索引,减少回表。
17. 减少冗余索引和使用率较低的索引:sys 库
7. 锁优化
7.1 latch 闩锁(shuan suo)
A。介绍
latch 用于管理对共享内存资源的并发访问,例如,操作缓冲池汇总的 LRU 列表,删除、添加、移动 LRU 列表中的元素,为了保证一致性,必须有锁的介入,这就是 latch 锁。
b. latch 和 lock 的区别

c. 查看latch 争用的类型
mysql> show engine innodb mutex;
可以在 latch 争用较为严重情况下,定位到源码的位置点,从而获得到底什么原因导致争用。
也可以在此时通过以下工具分析堆栈信息:找堆栈中堵塞的函数;
pstack -p `pidof mysqld` >/tmp/aa.txt
pt-pmp /tmp/aa.txt | more
d. 什么时候发生争用
1) a 访问 x 内存链表
2) b 排队等待 x 解锁,占了 cpu,但是 cpu 发现你在等待,所以 cpu 将 b 踢出
3) 访问锁链的时间,就是找数据的时间。
4) b 知道很 a 快所以,b 不去排队,这时去 spin 也就是空转 cpu,然后再去看一下内存数据结构,a 是否已解锁
5) b 转了一圈后,在 b spin 的时间段的时间中,c 进来了,连续多次的 spin 后,产生了 os waits
6) 操作系统将 b 从 cpu 中踢出
latch 争用的表面现象:latch 争用会表现为 cpu 繁忙,Io 很闲,没有做实际的事情。
sys us 高,然后 Io 低
e. 如何监控是否latach争用较为严重
SEMAPHORES
OS WAIT ARRAY INFO: reservation count 13
OS WAIT ARRAY INFO: signal count 13
RW-shared spins 0, rounds 0, os waits 0
RW-excl spins 2, rounds 60, oS waits 2
RW-sx spins 2, rounds 60, oS waits 2
Spin rounds per wait: 0.00 RW-shared, 30.00 RW-excl, 30.00 RW-sx
rounds: 意思是每次询问旋转的次数
os waits: 表示 sleep,当突然增长比较快的时候,说明 1atch 争用比较严重
rw-shared spin 的次数
rw-excl spin 的次数
waits/rounds 超过 5%,要重视一下了。
诊断方法:
show engine innodb mutex; --》找源码
pstack -p `pidof mysqld` > /tmp/aa.txt
pt-pmp /tmp/aa.txt | more
f. latch 争用发生的原因
1、内存访问太频繁(不停地找)
2、1ist 链太长(链上挂 10000 个快,被持有的几率太大)
g. 如何降低latch 争用
如果出现 latch 争用比较严重
1. 优化大 sql, 降低对内存读的数量--效果比较明显
2. 增加 instances 的数量
7.2 全局锁(GRL global read lock)
a. 介绍
全局读锁。
加锁方法:FTWRL, flush tables with read lock。
解锁方法:unlock tables;
出现场景:
mysqldump --master-data=2
1. 记录 binlog--》不让所有事务提交
2. FTWRL ---》不让新的修改进入 --- show create database show create tables
3. Unlock tables
4. Snapshot innodb (-- single- transaction) ---》可以允许所有 DML,但是不允许 DDL
xtrabackup (8.0 之前早期版本)等备份时。
备份非 InnoDB:表数据时,FTWRL, unlock tables
备份 InnoDB 时,会 checkpoint 备份数据页。并记录 redo 变化,可以允许 DML,不允许 DDL
属于类型:MDL (matedatalock)层面锁
影响情况:加锁期间,阻塞所有事务写入,阻塞所有已有事务 commit。
MDL,等待时间受 lock_wait_timeout=31536000
b. 检测方法
UPDATE per formance_schema.setup_instruments
SET ENABLED='YES', TIMED ='YES'
WHERE NAME ='wait/lock/metadata/sq1/mdl';
mysql> select from per formance_schema.metadata_locks;
mysql> select OBJECT_SCHEMA, OBJECT_NAME LOCK_TYPE, LOCK_DURATION, LOCK_STATUS OWNER_THREAD_ID, OWNER_EVENT_ID from performance_schema.metadata_locks;
5.7 版本:
mysql> show processlist;
mysql> select from sys.schema_table_lock_waits;
c. 一个经典故障:5.7 xtrabackup/ mysqldump 备份时数据库出现 hang 状态,所有查询都不能进行
Session1: 模拟一个大的查询或事务
mysql> select *,sleep(100) from city where id <10 for update;
session2: 模拟备份时的 FTWRL
mysql> flush tables with read lock; -一此时发现命令被阻塞
session3: 发起正常查询,发现被阻塞
mysql> select from wor ld.city where id=1 for update;
结论:备份时,一定要选择业务不繁忙期间,否则有可能会阻塞正常业务。
案例 2:
5.7 innobackupex 备份全库,进程死了,mysql 里就是全库读锁,后边 insert 全阻塞了
7.3 Table lock
a. 介绍
表锁。
加锁方式:
lock table t1read。所有会话只读。属于 MDL 锁。
lock table write。当前持有会话可以 RW,其他会被阻塞。属于 MDL 锁
select for update
select for share
解锁方式:
unlock tables;
b. 检测方式
[mysqld]
performance-schema-instrument='wait/lock/metadata/sq1/mdl=ON'
mysql> select * from per formance_schema.metadata_locks;
mysql> select * from per formance_schema.threads;
7.4 MDL 锁
a. 介绍
Matedata lock 元数据锁。
作用范围:global、commit、tablespace、schema、table 等
默认 timeout 时间:1ock_wait_timeout
mysql> select @@lock_wait_timeout;
b. 监控
[mysqld]
performance-schema-instrument='wait/lock/metadata/sq1/mdl=ON'
mysql> select * from performance_schema.metadata_locks;
找到
OWNER_THREAD_ID: 62
mysql> select * from threads where thread_id='62'\G
PROCESSLIST_ID: 21
ki11 21;
7.5 autoinc_lock
自增锁。
通过参:innodb_autoinc_lock_mode=0,1
0: 表锁,每次插入都请求表锁,效率低。
1: mutex 方式,预计插入多少行,预申请自增序列。如果出现 load 或者 insert select 方式会退化为 0.
2: 强制使用 mutex 方式。并发插入可以更高效。
作用:
The default innodb_autoinc_lock_mode setting is now 2 (inter leaved). Inter leaved lock mode permits the execution of multi-row inserts in parallel, which improves concurrency and scalability.
7.6 innodb row lock
a. 介绍
record lock gap, next lock
都是基于索引加锁,与事务隔离级别有关。
b. 监控及分析
show status like 'innodb_row_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;
c. 优化方向
1. 优化索引
2. 减少事务的更新范围
3. RC
4. 拆分语句:
例如: update t1 set numa=num+10 where k1 < 100; k1 是辅助索引,record lock gap next
改为:
select id from t1 where k1 <100; ---> id: 20,30, 50
update t1 set num=num+10 where id in (20,30, 50);
7.7 死锁
a. 介绍
dead lock 多个并发事务之间发生交叉资源依赖时,会出现。
b. 监控及分析
show engine innodb status\G;
innodb_print_all_deadlocks =1 ---》将死锁记录到错误日志
c. 经典死锁案例延时及解析


8. 架构方面的优化
高可用架构:
keepalived+双主+GTID+增强半同步 # 增强半同步不可靠,需要对业务有一定容忍度;双主一般请款下只写一个主,有问题另一个主替换
MHA + ProxySQL+GTID+增强半同步 # 可以进行读写分离(proxysql),在主库宕机,从库顶上
xenon # 生成要提改 MHA;依赖 GTID + 增强半同步
orch+MHA
consul+zk..
RM
PXC # 可以达到 5个9 ,金融公司一般使用
MGR\InnoDB Cluster # 可以达到5个9,
读写分离:
ProxysQL, MySQL-router
分布式架构:
shardingsphere === sharding-jdbc proxy...
NoSQL: # 百万、千万级别的 流量进来;mysql 什么样的架构都吃力;借助 redis 分摊读压力
Redis+sentinel, Redis Cluster # 历史类的数据,查询比较多的,可以使用 mongo、es 来放数据,避免浪费mysql
MongoDB RS/MongoDB SHARDING Cluster
ES
第三代:new sql
NewSQL:
Pingcap TIDB (TUG)
TDSQL
PolarDB
OceanBase
第四代:HTAP
HTAP
9. 安全优化
1、使用普通 nologin 用户管理 MySQL
2、合理授权用户、密码复杂度及最小权限、系统表保证只有管理员用户可访问。
3、删除数据库匿名用户(5.6 及之前版本)
4、锁定非活动用户
5、MySQL 尽量不暴露互联网,需要暴露互联网,用户需要设置明确白名单、替换 MySQL 默认端口号、使用 ss1 连接
6、优化业务代码,防止 SQL 注入。
7、备份
8、sql 审核 --- 》 爱可生 在 1024 开源了产品
9、高可用及容灾
10. 常用工具介绍
一、PT (percona-toolkits)工具的应用:
pt-archiver
gh-ost
pt-table-checksum/sync
pt-kil1
pt-heartbeat
pt-show-grants
pt-query-digest
pt-summary
pt-pmp
1.pt工具安装
# [root@master ~] yum install -y percona-toolkit-3.1.0-2.el7.x86_64.rpm
# 官网地址 https://www.percona.com/downloads/percona-toolkit/LATEST/
# 安装 yum 仓库
yum install https://repo.percona.com/yum/percona-release-latest.noarch.rpm
# 安装
yum install percona-toolkit -y
2. 常用工具使用介绍
2.1 pt-archiver 归档表
场景:
需求:面试题:亿级的大表,delete:批量删除 100w 左右数据。 使用 pt-archiver 把这任务拆分;对业务影响最小;
面试题:定期按照时间范围,进行归档表。
#重要参数
--limit 100 每次取 1000 行数据用 pt- archiver:处理
--txn-size 100 设置 1000 行为一个事务提交一次
--where 'id <3000' 设置操作条件
--progress 5000 每处理 5000 行输出一次处理信息
--statistics 输出执行过程及最后的操作统计。(只要不加上-- quiet,默认情况下 pt- ar chiver 都会输出执行过程的)
--charset=UTF8 指定字符集为 UTF8-这个最后加上不然可能出现乱码。--bulk-delete 批量删除 source。上的旧数据(例如每次 1000 行的批量删除操作)
注意:需要归档表中至少有一个索引,做好是 where 条件列有索引
使用案例:1. 归档到数据库
db01 [test]> create table test1 like t100w;
# 从一个库归档表到另外一个库;不删除源数据, limit 1000 每次1000行,每1000行打印一次;
# 要求,原表要有索引,并且目标数据库中要有 该表;表结构相同;
# 该工具不能提高归档的速度,由于它可以拆分事务,可以给数据库不带来那么大的压力;10000 拆分为 10 x 1000
# --progress 1000 --statistics 每1000条显示一次
pt-archiver --source h=10.0.0.51,P=3307,D=test,t=t100w,u=root,p=123 --dest
h=10.0.0.51,P=3307,D=test,t=test1,u=root,p=123 --where 'id<10000' --no-check-charset --no-delete --limit=1000 --commit-each --progress 1000 --statistics
2. 只清理数据;--purge 删除符合条件的数据;limit 100 ,每100行切一次
# 删除也不会加快速度,由于拆分了,可以减少业务的影响;
pt-archiver --source h=10.0.0. 51,P=3307,D=test,t=t100w,u=root,p=123 --where 'id <10000' --purge --limit=100 --no-check-charset --progress 1000 --statistics
3, 只把数据导出到外部文件,但是不删除源表里的据
# --where '1=1' 为全表导出
pt-archiver --source h=10.0.0.51, D=world,t=city,u=root,p=123 --where '1=1' --no-check-charset --no-delete --file="/tmp/archiver.csv"
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 之 alteri 语句限制
1、不需要包含 alter table 关键字,可以包含多个修改操作,使用逗号分开,如 "drop clolumn c1, add column c2 int"
2、不支持 renamei 语句来对表进行重命名操作
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='xx.xx.xx.xx'\
--recursion-method="hosts" \
--check-interval=2 \
--database="testdb1" \
t="tb001"\
--alter="add column c4 int"\
--execute
例子:
# 该功能不支持 mysql 8.0 版本的操作;
# 表需要有唯一主键并且不为空;
pt-online-schema-change --user=root --password=123 --host=10.0.0.51 --port=3307 --alter
"add column state int not null default 1" D=test,t=tes1 --print --execute
pt-online-schema-change --user=oldguo --password=123 --host=10.0.0.51 --alter "add index idx(num)" D=test,t=t100w --print --execute
2.3 pt-table-checksum
场景:校验主从数据一致性
条件:需要从库的io线程是好的;
过程:会先拿到主库的信息,然后去从库拿;都拿到之后,再做校验;
2.3.1 预备环境配置;他会把检验信息存储到 pt 库中(可以自定定义),所以先创建该库;
create database pt CHARACTER SET utf8:
创建用户 checksum 并授权
create user 'checksum'@'10.0.0. %' IDENTIFIED with mysql_native_password BY 'checksum';
GRANT ALL ON * TO 'checksum'@'10.0.0. %';
flush privileges;
从库设定 report 信息;修改mysql配置文件,在[mysqld]下增加report_host=10.0.0.51;report-por=3309
# 然后重启数据库,再登录查看
mysql> select @@report_host;
@@report_host
10.0.0.51
1 row in set (0.00 sec)
mysql> select @@report-port;
@@report_port
3309
1 row in set (0.00 sec)
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,P=3307,u=checksum,p=checksum
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 次是 s1ave 的地址。
u=:帐号。
p=:密码。
--print:打印,但不执行命令。
--execute:执行命令。
# 打印修复命令
pt-table-sync --replicate=pt.checksums --databases test --tables t1
h=10.0.0.51,u=checksum,p=checksum,P=3307 h=10.0.0.51,u=checksum,p=checksum,P=3309 --print
# 执行修复命令
pt-table-sync --replicate=pt.checksums --databases test --tables t1
h=10.0.0.51,u=checksum,p=checksum,P=3307 h=10.0.0.51,u=checksum,p=checksum,P=3309 --execute
2.5 pt-duplicate-key-checker
# 检查有没有重复索引,新版本 mysql8.0 sys 数据库帮我们做了
pt-duplicate-key-checker --database=test h='10.0.0.51' --user=oldguo --password=123
2.6 pt-ki11 语句
场景:无法正常 k11 的连接。
常用参数说明
--daemonize 放在后台以守护进程的形式运行;
--interval 多久运行一次,单位可以是 s, m, h, d 等默认是 s-不加这个黑认是 5 秒
--victims 默认是 oldest,只杀最古老的查询。这是防止被查杀是不是真的长时间运行的查询,他们只是长期等待这种和匹配按时间查询,杀死一个时间最高值。
--all 杀掉所有满足的线程
--kill-query 只杀掉连接执行的语句,但是线程不会被终止
--print 打印满足条件的语句
--busy-time 批次查询已运行的时间超过这个时间的线程;
--idle-time 杀掉 sleep 空闲了多少时间的连接线程,必须在 --match-command sleepl 时才有效-也就是匹配使用
--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
例子:
##杀掉空闲链接s1eep5秒的sQL并把日志放到/home/pt-ki11,1og文件中
/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 /tmp/mysql.sock --pid=/tmp/ptkill.pid --print --log=/tmp/pt-kill.log
# Kill 掉 select IFNUL. 语句开头的 SQL
pt-kill-user=用户名 --password=密码 --victims all-busy-time=0 --match-info="select IFNUL1.*" --interval 1 -S /tmp/mysqld.sock --kill --daemonize --pid=/tmp/ptkill.pid --print --log=/tmp/pt-kil1. Log
###kill 掉 state Locked
/usr/bin/pt-kil1--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 al1 --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 al1 --match-user='root' --kill --daemonize --interval 10 -S /home/zb/data/my6006/socket/mysqld.sock --pid=/tmp/ptki11.pid --print --log=/home/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

7. 显示主从结构:pt-slave--find
[root@db01 tmp] # pt-slave-find -h10.0.0.51 -P3307 -uchecksum -pchecksum
# 会打印主从的结构信息;
8. 监控主从延时
#pt-heartbeat
主库:主库会创建一个表,不断的往表里写数据,
pt-heartbeat --user=root --ask-pass --host=10.0.0.51 --port=3307 --create-table -D test --interval=1 --update --replace --daemonize
从库:从库会同步该表,并且检测同步的时间;延迟打印出来;
pt-heartbeat --user=root --ask-pass --host=10.0.0.51 --port=3309 -D test table=heartbeat --monitor
9. # pt-show-grants
作用:用户和权限信息迁移。比较好用,会把全新什么的都转换为sql语句。跨版本比较好用;
pt-show-grants -h10.0.0.51 -P3307 -uchecksum -pchecksum
# 自己扩展
pt-query-digest
pt-summary # 会采集系统信息;包括 top io 网卡信息都会采集出来,可以很好的帮助分析系统瓶颈
pt-pmp #
11. 压测
11.1 目的
a. 上线之前压测烤机,对硬件测试;cpu、io、网络、mem
b. 基准的获取:tps qps rt
c. 性能对比(参数、配置)
11.2 关注指标
cpu: user sys wait
mem: total freee used av buffer cache
IO :
await: 每次设备io操作的等待时间(毫秒)
svatm:平均的服务时间
%util:在1秒内用户io操作的时间百分比
DB:
TPS
QPS