MySQL 5.7 并行复制

1.MySQL 并行复制原理

MySQL 并行复制(Enhanced Multi-Threaded Slave 简称:MTS )
MySQL 5.6 并行复制架构
MySQL 从 5.6 开始引入了多库并行主从复制,可以并发还原数据。但是其并行只是基于 Schema 的,也就是基于库的。如果用户的 MySQL 数据库实例中存在多个 Schema,对于从机复制的速度的确可以有比较大的帮助。MySQL 5.6 并行复制的架构如下所示:
MySQL 5.7 并行复制

在上图的红色框框部分就是实现并行复制的关键所在。在 MySQL 5.6 版本之前,Slave 服务器上有两个线程 I/O 线程和 SQL 线程。I/O 线程负责接收二进制日志(更准确的说是二进制日志的 event ),SQL 线程进行回放二进制日志。如果在 MySQL 5.6 版本开启并行复制功能,那么 SQL 线程就变为了 Coordinator 线程,Coordinator 线程主要负责以前两部分的内容:

  • 若判断可以并行执行,那么选择 Worker 线程执行事务的二进制日志;
  • 若判断不可以并行执行,如该操作是 DDL,亦或者是事务 Schema 操作,则等待所有的 Worker 线程执行完成之后,再执行当前的日志。

这意味着 Coordinator 线程并不是仅将日志发送给 Worker 线程,自己也可以回放日志,但是所有可以并行的操作交付由 Worker线程完成。Coordinator 线程与 Worker 是典型的生产者与消费者模型。

上述机制实现的基于 Schema 的并行复制存在两个问题,首先是 Crash Safe 功能不好做,因为可能之后执行的事务由于并行复制的关系先完成执行,那么当发生 Crash 的时候,这部分的处理逻辑是比较复杂的。从代码上看,5.6 这里引入了 Low-Water-Mark 标记来解决该问题,从设计上看,其是希望借助于日志的幂等性来解决该问题,不过 5.6 的二进制日志回放还不能实现幂等性。另一个最为关键的问题是这样设计的并行复制效果并不高,如果用户实例仅有一个库,那么就无法实现并行回放,甚至性能会比原来的单线程更差。而单库多表是比多库多表更为常见的一种情形。

MySQL 5.6 中,设置参数 slave_parallel_workers = 4(>1),即可有 4 个 SQL Thread(coordinator 线程)来进行并行复制,其状态为:Waiting for an evant from Coordinator。

但是其并行只是基于 Schema 的,也就是基于库的。如果数据库实例中存在多个 Schema,这样设置对于 Slave 复制的速度可以有比较大的提升。通常情况下单库多表是更常见的一种情形,那基于库的并发就没有卵用。其核心思想是:不同 schema 下的表并发提交时的数据不会相互影响,即 slave 节点可以用对 relay log 中不同的 schema 各分配一个类似 SQL 功能的线程,来重放 relay log 中主库已经提交的事务,保持数据与主库一致。

MySQL 5.7 并行复制原理
MySQL 5.7 是基于组提交的并行复制。MySQL 5.7 才可称为真正的并行复制,这其中最为主要的原因就是 Slave 服务器的回放与主机是一致的,即 Master 服务器上是怎么并行执行的 Slave 上就怎样进行并行回放。不再有库的并行复制限制,对于二进制日志格式也无特殊的要求(基于库的并行复制也没有要求)。

从 MySQL 官方来看,其并行复制的原本计划是支持表级的并行复制和行级的并行复制,行级的并行复制通过解析 ROW 格式的二进制日志的方式来完成。但是最终出现的是在开发计划中称为:MTS: Prepared transactions slave parallel applier。

该并行复制的思想最早是由 MariaDB 的 Kristain 提出,并已在 MariaDB 10 中出现,MySQL 5.7 并行复制的思想简单易懂,一言以蔽之:一个组提交的事务都是可以并行回放,因为这些事务都已进入到事务的 Prepare 阶段,则说明事务之间没有任何冲突(否则就不可能提交)。

在 MySQL 5.7 中,引入了基于组提交的并行复制(Enhanced Multi-threaded Slaves),设置参数slave_parallel_workers>0并且global.slave_parallel_type=‘LOGICAL_CLOCK’,即可支持一个 schema 下,slave_parallel_workers个的 worker 线程并发执行 relay log 中主库提交的事务。其核心思想:一个组提交的事务都是可以并行回放(配合 binary log group commit);
slave 机器的 relay log 中 last_committed 相同的事务(sequence_num 不同)可以并发执行。
为了兼容 MySQL 5.6 基于库的并行复制,5.7 引入了新的变量 slave-parallel-type,其可以配置的值有:

  • DATABASE:默认值,基于库的并行复制方式。
  • LOGICAL_CLOCK:基于组提交的并行复制方式。

2.如何确定事务是否在一组中

如何知道事务是否在一组中,又是一个问题,因为原版的 MySQL 并没有提供这样的信息。在 MySQL 5.7 版本中,其设计方式是将组提交的信息存放在 GTID 中。那么如果用户没有开启 GTID 功能,即将参数 gtid_mode 设置为 OFF 呢?故 MySQL 5.7 又引入了称之为 Anonymous_Gtid 的二进制日志 event 类型,如:

root@localhost [unixfbi]>SHOW BINLOG EVENTS in 'mysql-bin.000014';
+------------------+-----+----------------+-----------+-------------+-------------------------------------------+
| Log_name         | Pos | Event_type     | Server_id | End_log_pos | Info                                      |
+------------------+-----+----------------+-----------+-------------+-------------------------------------------+
| mysql-bin.000014 |   4 | Format_desc    |   2303306 |         123 | Server ver: 5.7.18-log, Binlog ver: 4     |
| mysql-bin.000014 | 123 | Previous_gtids |   2303306 |         194 | b5a3240c-8946-11e7-bf07-d067e528dfb8:1-20 |
| mysql-bin.000014 | 194 | Anonymous_Gtid |   2303306 |         259 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'      |
| mysql-bin.000014 | 259 | Query          |   2303306 |         334 | BEGIN                                     |
| mysql-bin.000014 | 334 | Table_map      |   2303306 |         383 | table_id: 219 (unixfbi.tst)               |
| mysql-bin.000014 | 383 | Write_rows     |   2303306 |         423 | table_id: 219 flags: STMT_END_F           |
| mysql-bin.000014 | 423 | Xid            |   2303306 |         454 | COMMIT /* xid=18 */                       |
| mysql-bin.000014 | 454 | Rotate         |   2303306 |         501 | mysql-bin.000015;pos=4                    |
+------------------+-----+----------------+-----------+-------------+-------------------------------------------+
8 rows in set (0.00 sec)

这意味着在 MySQL 5.7 版本中即使不开启 GTID ,每个事务开始前也是会存在一个 Anonymous_Gtid ,而这 GTID 中就存在着组提交的信息。

3.组提交到底是怎么回事?

组提交是个比较好玩的方式,MySQL 5.7 默认就开启了组提交模式。我们根据 MySQL 的 binlog 可以发现较之原来的二进制日志内容多了 last_committed 和 sequence_number 。
如果我们在 MySQL 5.6 版本数据库的 binlog 日志中执行 mysqlbinlog mysql-bin.000168 |grep last_committed 发现什么也没有找到。但是在 MySQL5.7 中就会获得 mysqlbinlog mysql-bin.000168 |grep last_committed
未开启组提交日志信息:

# mysqlbinlog mysql-bin.000018  |grep last_committed  
#171221 16:30:37 server id 2303306  end_log_pos 259 CRC32 0x64718fca  GTID  last_committed=0   sequence_number=1
#171221 16:30:37 server id 2303306  end_log_pos 537 CRC32 0xea91ca1f  GTID  last_committed=1   sequence_number=2
#171221 16:31:18 server id 2303306  end_log_pos 815 CRC32 0x87ef0663  GTID  last_committed=2   sequence_number=3
#171221 16:31:18 server id 2303306  end_log_pos 1093 CRC32 0xd2ea6ced  GTID  last_committed=3   sequence_number=4
#171221 16:31:18 server id 2303306  end_log_pos 1371 CRC32 0xf9edc446  GTID  last_committed=4   sequence_number=5
#171221 16:31:18 server id 2303306  end_log_pos 1649 CRC32 0xc108c255  GTID  last_committed=5   sequence_number=6
#171221 16:31:18 server id 2303306  end_log_pos 1927 CRC32 0x66bfc187  GTID  last_committed=6   sequence_number=7
#171221 16:31:18 server id 2303306  end_log_pos 2205 CRC32 0xb3ee1340  GTID  last_committed=7   sequence_number=8
#171221 16:31:18 server id 2303306  end_log_pos 2483 CRC32 0x5dff6762  GTID  last_committed=8   sequence_number=9
#171221 16:31:18 server id 2303306  end_log_pos 2761 CRC32 0x6464a37a  GTID  last_committed=9   sequence_number=10
#171221 16:31:18 server id 2303306  end_log_pos 3039 CRC32 0xadac27f7  GTID  last_committed=10  sequence_number=11

上面是没有开启组提交的一个日志,我们可以看得到 binlog 当中有两个参数 last_committed 和 sequence_number,我们可以看到,下一个事务在主库配置好组提交以后,last_committed 永远都和上一个事务的 sequence_number 是相等的。这也很容易理解,因为事务是顺序提交的。

开启组提交日志信息:

#171221 18:36:54 server id 2303306  end_log_pos 120704 CRC32 0x8e60a535  GTID  last_committed=35  sequence_number=36
#171221 18:36:54 server id 2303306  end_log_pos 123182 CRC32 0x6c16858f  GTID  last_committed=36  sequence_number=37
#171221 18:36:54 server id 2303306  end_log_pos 125266 CRC32 0x9e88615a  GTID  last_committed=37  sequence_number=38
#171221 18:36:54 server id 2303306  end_log_pos 133978 CRC32 0xaeb62771  GTID  last_committed=38  sequence_number=39
#171221 18:36:54 server id 2303306  end_log_pos 148044 CRC32 0x932fbf2c  GTID  last_committed=39  sequence_number=40
#171221 18:36:54 server id 2303306  end_log_pos 155911 CRC32 0x918a518f  GTID  last_committed=40  sequence_number=41
#171221 18:36:54 server id 2303306  end_log_pos 165482 CRC32 0x1fec4183  GTID  last_committed=41  sequence_number=42
#171221 18:36:54 server id 2303306  end_log_pos 167664 CRC32 0x7282f870  GTID  last_committed=41  sequence_number=43
#171221 18:36:54 server id 2303306  end_log_pos 169678 CRC32 0x6747bad1  GTID  last_committed=41  sequence_number=44
#171221 18:36:54 server id 2303306  end_log_pos 171838 CRC32 0x99b63093  GTID  last_committed=41  sequence_number=45
#171221 18:36:54 server id 2303306  end_log_pos 173767 CRC32 0xdd25ecb3  GTID  last_committed=41  sequence_number=46
#171221 18:36:54 server id 2303306  end_log_pos 175867 CRC32 0x3f12bb9e  GTID  last_committed=41  sequence_number=47
#171221 18:36:54 server id 2303306  end_log_pos 177915 CRC32 0xa4dd09b9  GTID  last_committed=41  sequence_number=48
#171221 18:36:54 server id 2303306  end_log_pos 180220 CRC32 0xe9ba43f2  GTID  last_committed=41  sequence_number=49
#171221 18:36:54 server id 2303306  end_log_pos 182414 CRC32 0xd1da0264  GTID  last_committed=41  sequence_number=50
#171221 18:36:54 server id 2303306  end_log_pos 184391 CRC32 0xf3f5511f  GTID  last_committed=42  sequence_number=51
#171221 18:36:54 server id 2303306  end_log_pos 195840 CRC32 0x437a04c3  GTID  last_committed=42  sequence_number=52
#171221 18:36:54 server id 2303306  end_log_pos 198542 CRC32 0x2db053d9  GTID  last_committed=42  sequence_number=53
#171221 18:36:54 server id 2303306  end_log_pos 209046 CRC32 0x6ba08ecf  GTID  last_committed=42  sequence_number=54
#171221 18:36:55 server id 2303306  end_log_pos 211435 CRC32 0x8d159d7b  GTID  last_committed=54  sequence_number=55
#171221 18:36:55 server id 2303306  end_log_pos 213700 CRC32 0x426d6ad6  GTID  last_committed=55  sequence_number=56
#171221 18:36:56 server id 2303306  end_log_pos 224170 CRC32 0x8d0498bb  GTID  last_committed=56  sequence_number=57
#171221 18:36:56 server id 2303306  end_log_pos 226226 CRC32 0x1f03e7c6  GTID  last_committed=57  sequence_number=58

我们可以看到日志中有几个事务的 last_committed 是相同的,这意味着这几个事务是作为一个组提交的,这几个事务在 Perpare 阶段获取相同的 last_committed 而且相互不影响,最终是会作为一个组进行提交。这就是所谓的组提交。组提交的事务是可以在从机进行并行回放的。

上述的 last_committed 和 sequence_number 代表的就是所谓的 LOGICAL_CLOCK 。
关于 MySQL 5.7 的组提交,我们可以设置以下参数:

root@localhost [tpcc]>show global variables like '%group_commit%';
+-----------------------------------------+-------+
| Variable_name                           | Value |
+-----------------------------------------+-------+
| binlog_group_commit_sync_delay          | 0  |
| binlog_group_commit_sync_no_delay_count | 0    |
+-----------------------------------------+-------+
2 rows in set (0.00 sec)

4.为什么要用并行复制?

传统复制的瓶颈点?
sql_thread 在 5.7 之前是单线程的,而 master 上是多线程并发写的,所以在主从同步时 sql_thread 就会成为 主从复制的瓶颈。就会出现主从同步延迟问题。

解决方法:
把 mysql 升级到 5.7。先把 binlog group commit 启用上,再把并行复制开起来,然后把这个参数设置上 slave_paralle_type="LOCAL_CLOCK"

启用并行复制
MySQL 5.6 引入了基于库的并行复制;
MySQL 5.7 引入了基于事务的并行复制(Binary Group Commit)

5.MySQL 5.7 如何开启并行复制

MySQL 5.7 开启 Enhanced Multi-Threaded Slave 配置:需要在 master 和 slave 都要做配置
master 配置:
可以设置以下两个参数:

root@localhost [tpcc]>show global variables like '%group_commit%';
+-----------------------------------------+-------+
| Variable_name                           | Value |
+-----------------------------------------+-------+
| binlog_group_commit_sync_delay          | 1000  |
| binlog_group_commit_sync_no_delay_count | 20    |
+-----------------------------------------+-------+
2 rows in set (0.00 sec)

要开启 MySQL 5.7 并行复制需要以下二步,首先在主库设置 binlog_group_commit_sync_delay 的值大于 0 。

root@localhost [tpcc]>set global binlog_group_commit_sync_delay=1000;

binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count 参数含义:

  • binlog_group_commit_sync_delay
    全局动态变量,单位微妙,默认为 0,范围:0~1000000(1 秒)
    建议配置成 20-30 微妙。 被认为是同一时间的操作,时长到达 2-30 微妙了就发车提交了。

表示 binlog 提交后等待延迟多少时间再同步到磁盘,默认 0 ,不延迟。当设置为 0 以上的时候,就允许多个事务的日志同时一起提交,也就是我们说的组提交。组提交是并行复制的基础,我们设置这个值的大于 0 就代表打开了组提交的功能。

  • binlog_group_commit_sync_no_delay_count
    全局动态变量,单位个数,默认 0,范围:0~1000000。
    建议配置成 20。假如没有到 20-30 微妙,但是达到了 20 个事务,就发车提交,不用等待了。
    表示等待延迟提交的最大事务数,如果上面参数的时间没到,但事务数到了,则直接同步到磁盘。若 binlog_group_commit_sync_delay 没有开启,则该参数也不会开启。

slave 配置:

# slave
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=4    
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON

过多的线程会增加线程间同步的开销,最多等于 cpu core 数量;建议设置成 cpu core 的 1/2;
也可以直接在线启用上面的参数:

root@localhost [(none)]>stop slave;
Query OK, 0 rows affected (0.10 sec)

root@localhost [(none)]>show variables like 'slave_parallel_%';
+------------------------+----------+
| Variable_name          | Value    |
+------------------------+----------+
| slave_parallel_type    | DATABASE |
| slave_parallel_workers | 0        |
+------------------------+----------+
2 rows in set (0.03 sec)

root@localhost [(none)]>set global slave_parallel_type='LOGICAL_CLOCK';
Query OK, 0 rows affected (0.00 sec)

root@localhost [(none)]>set global slave_parallel_workers=4;
Query OK, 0 rows affected (0.00 sec)

root@localhost [(none)]>start slave;
Query OK, 0 rows affected (0.16 sec)

root@localhost [(none)]>show variables like 'slave_parallel_%';
+------------------------+---------------+
| Variable_name          | Value         |
+------------------------+---------------+
| slave_parallel_type    | LOGICAL_CLOCK |
| slave_parallel_workers | 4             |
+------------------------+---------------+
2 rows in set (0.00 sec)

6.并行复制配置与调优

开启 MTS 功能后,务必将参数 master-info-repository 设置为 TABLE ,这样性能可以有 50%~80% 的提升。这是因为并行复制开启后对于 master.info 这个文件的更新将会大幅提升,资源的竞争也会变大。

在 MySQL 5.7 中,推荐将 master-info-repository 和 relay-log-info-repository 设置为 TABLE ,来减小这部分的开销。
所以 slave 上还需要配置上如下参数

# Slave
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON

二、配置 MySQL 5.7 并行复制

1.环境信息

主机名IPserver-id角色
db-node1 192.168.199.230 2303306 Master
db-node3 192.168.199.131 1313306 Slave

软件版本:

软件名称版本
系统版本 CentOS Linux release 7.2.1511 (Core)
MySQL mysql-5.7.18-linux-glibc2.5-x86_64

2.安装 MySQL

请参考 我的另一篇文章:
Centos7 安装 MySQL5.7

3.启用 MySQL 并行复制

MySQL 5.7 的并行复制建立在组提交的基础上,所有在主库上能够完成 Prepared 的语句表示没有数据冲突,就可以在 Slave 节点并行复制。

Master:

root@localhost [tpcc]>set global binlog_group_commit_sync_delay=10;

root@localhost [tpcc]>show global variables like '%group_commit%';
+-----------------------------------------+-------+
| Variable_name                           | Value |
+-----------------------------------------+-------+
| binlog_group_commit_sync_delay          | 0  |
| binlog_group_commit_sync_no_delay_count | 10    |
+-----------------------------------------+-------+
2 rows in set (0.00 sec)

Slave:
在配置文件中添加:

# slave
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=4
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON

确认配置:

root@localhost [(none)]>show variables like 'slave_parallel_%';
+------------------------+---------------+
| Variable_name          | Value         |
+------------------------+---------------+
| slave_parallel_type    | LOGICAL_CLOCK |
| slave_parallel_workers | 4             |
+------------------------+---------------+
2 rows in set (0.00 sec)

4.配置主从复制关系

master:

# mysqldump -A -B -uroot -p > /tmp/230.sql 

slave:

$ mysql -uroot -p < /tmp/230.sql 
root@localhost [(none)]>CHANGE MASTER TO 
   MASTER_HOST='192.168.199.230',
   MASTER_USER='repl',
   MASTER_PASSWORD='unixfbi',
   MASTER_PORT=3306,
   MASTER_AUTO_POSITION=1;

start slave;Query OK, 0 rows affected, 2 warnings (0.49 sec)

root@localhost [(none)]>
root@localhost [(none)]>start slave;

查看复制状态:

root@localhost [(none)]>show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.199.230
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 154
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 367
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 154
              Relay_Log_Space: 568
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 2303306
                  Master_UUID: b5a3240c-8946-11e7-bf07-d067e528dfb8
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

5.检查 Worker 线程的状态

当前的 Slave 的 SQL 线程为 Coordinator(协调器),执行 Relay log 日志的线程为 Worker(当前的 SQL 线程不仅起到协调器的作用,同时也可以重放 Relay log 中主库提交的事务)。

我们上面设置的线程数是 4 ,从库就能看到 4 个 Coordinator(协调器)进程。

root@localhost [(none)]>show processlist;
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
| Id | User        | Host      | db   | Command | Time | State                                                  | Info             |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
| 20 | root        | localhost | NULL | Query   |    0 | starting                                               | show processlist |
| 21 | system user |           | NULL | Connect |   19 | Waiting for master to send event                       | NULL             |
| 22 | system user |           | NULL | Connect |   19 | Slave has read all relay log; waiting for more updates | NULL             |
| 23 | system user |           | NULL | Connect |   19 | Waiting for an event from Coordinator                  | NULL             |
| 24 | system user |           | NULL | Connect |   19 | Waiting for an event from Coordinator                  | NULL             |
| 25 | system user |           | NULL | Connect |   19 | Waiting for an event from Coordinator                  | NULL             |
| 26 | system user |           | NULL | Connect |   19 | Waiting for an event from Coordinator                  | NULL             |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
7 rows in set (0.00 sec)

6.MySQL 并行复制监控

复制的监控依然可以通过SHOW SLAVE STATUS\G ,但是 MySQL 5.7 在performance_schema 架构下多了以下这些元数据表,用户可以更细力度的进行监控:

root@localhost [(none)]>use performance_schema;
Database changed
root@localhost [performance_schema]>show tables like 'replication%';
+---------------------------------------------+
| Tables_in_performance_schema (replication%) |
+---------------------------------------------+
| replication_applier_configuration           |
| replication_applier_status                  |
| replication_applier_status_by_coordinator   |
| replication_applier_status_by_worker        |
| replication_connection_configuration        |
| replication_connection_status               |
| replication_group_member_stats              |
| replication_group_members                   |
+---------------------------------------------+
8 rows in set (0.00 sec)

参考文档

https://www.cnblogs.com/shengdimaya/p/6972278.html
http://www.cnblogs.com/langdashu/p/6125621.html
https://dev.mysql.com/doc/refman/5.7/en/replication-options-slave.html
http://www.ttlsa.com/mysql/mysql-5-7-enhanced-multi-thread-salve/
https://yq.aliyun.com/articles/3022
https://www.hi-linux.com/posts/9892.html
https://www.cnblogs.com/zhoujinyi/p/5704567.html

posted @ 2018-12-20 17:17  workdsz  阅读(561)  评论(0)    收藏  举报