MySQL 5.7新特性:在線開啓和關閉基於GTID的複製

1、前言

MySQL在5.6版本以前複製一直是基於二進制日誌的複製,到了MySQL5.6時開始支持基於事務(GTIDs)的複製,而且開始支持多線程複製;但MySQL5.6版本的多線程只能基於多庫。這就牽扯到了一個應用場景,就是從基於日誌的複製在線變動到基於事務的複製,在MySQL5.6版本時這一動做只能重啓主服務器才能夠作到。可是到了MySQL 5.7版本時已經能夠支持在線變動複製類型了,也就是在線從基於二進制日誌的複製變動爲基於事務的複製。固然MySQL5.7在複製方面的改進不止這一點,還作到了基於表的多線程複製,以及多源複製。這篇文章只針對在線把基於日誌的複製變動爲基於事務的複製,其餘方面的改進,如多線程複製和多源複製能夠看其餘文章。mysql

2、安裝MySQL 5.7.16

詳情可看:MySQL 5.7多方式安裝sql

首先從MySQL官方網站下載YUM源,地址:http://dev.mysql.com/doc/mysql-yum-repo-quick-guide/en/bash

這裏我選擇MySQL 5.7的源進行安裝MySQL 5.7,手動添加一個YUM源。服務器

$ cat /etc/yum.repos.d/mysql.repo
# Enable to use MySQL 5.7

[mysql57-community]

name=MySQL 5.7 Community Server

baseurl=http://repo.mysql.com/yum/mysql-5.7-community/el/6/$basearch/

enabled=1

gpgcheck=0

gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql

檢查一下mysql repo微信

$ yum repolist enabled | grep mysql

mysql57-community               MySQL 5.7 Community Server                146

安裝啓動配置MySQLsession

$ yum install mysql-community-server-5.7.16 mysql-community-devel-5.7.16 mysql-community-client-5.7.16 mysql-community-common-5.7.16

MySQL 5.7以及安裝完成了,爲了簡便,我這裏使用多實例的方式進行測試在線變動複製類型,開兩個端口3306和3307。多線程

首先建立一些標準目錄。socket

$ mkdir /data/mysql/3306/{conf,data,log,tmp} -p

$ mkdir /data/mysql/3306/log/{binlog,relaylog,slowlog} -p

$ mkdir /data/mysql/3307/{conf,data,log,tmp} -p

$ mkdir /data/mysql/3307/log/{binlog,relaylog,slowlog} -p

$ chown mysql.mysql -R /data/mysql

下面開始進行初始化操做。tcp

$ mysqld --initialize-insecure --user=mysql --datadir=/data/mysql/3306/data

$ mysqld --initialize-insecure --user=mysql --datadir=/data/mysql/3307/data

看一下初始化後的目錄文件,以下:ide

$ ll /data/mysql/3306/data/

total 122908

-rw-r-----   1 mysql    mysql          56 Nov 21 10:43 auto.cnf

-rw-r-----   1 mysql    mysql         260 Nov 21 11:58 ib_buffer_pool

-rw-r-----   1 mysql    mysql    50331648 Nov 21 11:58 ib_logfile0

-rw-r-----   1 mysql    mysql    50331648 Nov 21 10:43 ib_logfile1

-rw-r-----   1 mysql    mysql    12582912 Nov 21 11:58 ibdata1

-rw-r-----   1 mysql    mysql    12582912 Nov 21 11:58 ibtmp1

drwxr-x---   2 mysql    mysql        4096 Nov 21 10:43 mysql

drwxr-x---   2 mysql    mysql        4096 Nov 21 10:43 performance_schema

drwxr-x---   2 mysql    mysql       12288 Nov 21 10:43 sys

 

3、啓動多實例

 

1)給每一個實例提供配置文件

給3306(master)實例提供一份配置文,以下:

$ cat /data/mysql/3306/conf/my.cnf

[mysqld]

############################basic settings#################

port=3306

bind-address=0.0.0.0

datadir=/data/mysql/3306/data

socket=/data/mysql/3306/mysql.sock

pid-file=/data/mysql/3306/mysql.pid

user=mysql

server-id = 10

character_set_server = utf8mb4

skip_name_resolve = 1

max_allowed_packet = 16777216

max_connections = 800

max_connect_errors = 1000

tmpdir = /data/mysql/3306/tmp

tmp_table_size = 67108864

explicit_defaults_for_timestamp = 1

join_buffer_size = 134217728

interactive_timeout = 1800

wait_timeout = 1800

read_buffer_size = 16777216

read_rnd_buffer_size = 33554432

sort_buffer_size = 33554432

key_buffer_size = 256M

thread_cache_size = 8

transaction_isolation = READ-COMMITTED



###########################log settings#####################

log-bin = /data/mysql/3306/log/binlog/mysql-bin

log_bin_index = /data/mysql/3306/log/binlog/mysql-bin.index

expire_logs_days = 30

binlog_format = ROW

log_error = /data/mysql/3306/log/error.log

slow_query_log = 1

long_query_time = 2

log_slow_admin_statements = 1

log_slow_slave_statements = 1

slow_query_log_file = /data/mysql/3306/log/slowlog/slow.log

min_examined_row_limit = 100

binlog-rows-query-log_events = 1



##########################innodb settings###################

innodb_buffer_pool_size = 512m

innodb_sort_buffer_size = 27108864

innodb_buffer_pool_load_at_startup = 1

innodb_buffer_pool_dump_at_shutdown = 1

innodb_lock_wait_timeout = 5

innodb_flush_method = O_DIRECT

innodb_file_format = Barracuda

innodb_file_format_max = Barracuda

innodb_thread_concurrency = 24

innodb_flush_neighbors = 1

innodb_purge_threads = 4

innodb_large_prefix = 1

innodb_print_all_deadlocks = 1

innodb_strict_mode = 1

innodb_file_per_table = ON

innodb_flush_log_at_trx_commit=2



##########################start gtid###########################

#gtid-mode = on

#enforce-gtid-consistency = true

#master-info-repository = table

#relay-log-info-repository = table

#log-slave-updates = true

#binlog-checksum = CRC32

#master-verify-checksum = 1

#slave-sql-verify-checksum = 1

#slave_allow_batching = 1

給3307(slave)實例提供一份配置文件,以下:

$ cat /data/mysql/3307/conf/my.cnf

[mysqld]

############################basic settings#################

port=3307

bind-address=0.0.0.0

datadir=/data/mysql/3307/data

socket=/data/mysql/3307/mysql.sock

pid-file=/data/mysql/3307/mysql.pid

user=mysql

server-id = 20

character_set_server = utf8mb4

skip_name_resolve = 1

max_allowed_packet = 16777216

max_connections = 800

max_connect_errors = 1000

tmpdir = /data/mysql/3307/tmp

tmp_table_size = 67108864

explicit_defaults_for_timestamp = 1

join_buffer_size = 134217728

interactive_timeout = 1800

wait_timeout = 1800

read_buffer_size = 16777216

read_rnd_buffer_size = 33554432

sort_buffer_size = 33554432

key_buffer_size = 256M

thread_cache_size = 8

transaction_isolation = READ-COMMITTED



###########################log settings#####################

#log-bin = /data/mysql/3307/log/binlog/mysql-bin

#log_bin_index = /data/mysql/3307/log/binlog/mysql-bin.index

#expire_logs_days = 30

#binlog_format = ROW

log_error = /data/mysql/3307/log/error.log

#slow_query_log = 1

#long_query_time = 2

#log_slow_admin_statements = 1

#log_slow_slave_statements = 1

#slow_query_log_file = /data/mysql/3307/log/slowlog/slow.log

#min_examined_row_limit = 100



##########################innodb settings###################

innodb_buffer_pool_size = 512m

innodb_sort_buffer_size = 27108864

innodb_buffer_pool_load_at_startup = 1

innodb_buffer_pool_dump_at_shutdown = 1

innodb_lock_wait_timeout = 5

innodb_flush_method = O_DIRECT

innodb_file_format = Barracuda

innodb_file_format_max = Barracuda

innodb_thread_concurrency = 24

innodb_flush_neighbors = 1

innodb_purge_threads = 4

innodb_large_prefix = 1

innodb_print_all_deadlocks = 1

innodb_strict_mode = 1

innodb_file_per_table = ON

innodb_flush_log_at_trx_commit=2



#########################replication#########################

relay-log = /data/mysql/3307/log/relaylog/relay-log

skip-slave-start = true



#####################start gtid##############################

#gtid-mode = on

#enforce-gtid-consistency = true

#slave-parallel-workers = 1

#binlog-checksum=CRC32

#master-verify-checksum = 1

#slave-sql-verify-checksum = 1

#slave_allow_batching = 1

#relay_log_purge = 1

#relay_log_recovery = 1

#master-info-repository = table

#relay-log-info-repository = table

#report-port = 3308

#report-host = 10.0.60.143

PS:配置文件很清楚,若是想使用GTID,開啓對應的參數便可。

從新賦予一下權限

$ chown mysql.mysql -R /data/mysql


4、基於日誌作主從複製配置

MySQL基於日誌點作主從複製(二)

1)啓動兩個實例

$ nohup mysqld --defaults-file=/data/mysql/3306/conf/my.cnf &

$ nohup mysqld --defaults-file=/data/mysql/3307/conf/my.cnf &
$ netstat -nplt | grep mysqld

tcp        0      0 10.0.60.143:3306            0.0.0.0:*                   LISTEN      39854/mysqld        

tcp        0      0 10.0.60.143:3307            0.0.0.0:*                   LISTEN      40256/mysqld

PS:進入MySQL須要使用-S指定各自的mysql.sock文件。

2)Master(3306)建立具備複製權限的用戶

mysql> grant replication slave on *.* to 'mysql_slave'@'%' identified by '123456';

mysql> flush privileges;

3)Slave(3307)鏈接至主庫(3306)

mysql> reset slave all;

mysql> change master to master_host='10.0.60.143',master_user='mysql_slave',master_password='123456',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=1;
master_host               #主服務器地址;

master_port               #主服務器端口(不要指定雙引號);

master_log_file           #指定從主服務器哪一個二進制日誌文件開始複製;

master_log_pos            #指定從主服務器哪一個二進制日誌文件的位置開始複製(不須要雙引號);

master_user               #鏈接到主服務器的用戶;

master_password           #鏈接到主服務器的用戶密碼;

4)啓動Slave

mysql> start slave;
mysql> show slave status\G

*************************** 1. row ***************************

               Slave_IO_State: Waiting for master to send event

                  Master_Host: 10.0.60.143

                  Master_User: mysql_slave

                  Master_Port: 3306

                Connect_Retry: 60

              Master_Log_File: mysql-bin.000001

          Read_Master_Log_Pos: 591

               Relay_Log_File: relay-log.000003

                Relay_Log_Pos: 804

        Relay_Master_Log_File: mysql-bin.000001

             Slave_IO_Running: Yes

            Slave_SQL_Running: Yes

                          ........

OK,如今基於日誌的主從複製已經完成了。

5、在線開啓基於GTID的複製

接下來,就是在線切換複製類型了。首先肯定主從的gtid_mode都是off狀態。

mysql> show variables like '%gtid_mode%';

+---------------+-------+

| Variable_name | Value |

+---------------+-------+

| gtid_mode     | OFF   |

+---------------+-------+

1 row in set (0.00 sec)

1)Master(3306)操做

爲了更加模擬線上環境,咱們寫一個腳本,一直往主庫插入數據,同時從庫也一直再同步主庫的數據。

mysql> CREATE DATABASE `test`;

mysql> USE test;

mysql> CREATE TABLE `tt` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`count` int(11) DEFAULT NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

而後建立一個腳本一直往test.tt表中插入數據。

$ cat test.sh

#!/bin/bash

for i in `seq 1 1000000`;do

  mysql -S /data/mysql/3306/mysql.sock -e "insert into test.tt(count) values($i);"

done

如今就能夠開始丟在後臺執行。

接下來,在主庫(3306)和把enforce_gtid_consistency變成warn。

mysql> set global enforce_gtid_consistency=warn;

Query OK, 0 rows affected (0.00 sec)

ENFORCE_GTID_CONSISTENCY這個參數主要有以下設置,主要用於不讓違反GTID設置的操做執行,若是執行會報錯如:Statement violates GTID consistency: CREATE TABLE … SELECT.

  • OFF:全部操做容許。
  • ON:不容許違反gtid的操做,而且報錯。
  • WARN:在MySQL 5.7.6添加,全部操做容許,可是違反GTID的操做會報出警告。

ENFORCE_GTID_CONSISTENCY=WARN是肯定事務都支持gtid,不會在err log中出現警告以下:

2016-11-21T22:35:24.322055Z 55 [Warning] Statement violates GTID consistency: CREATE TABLE ... SELECT.

而後看一下error log。

$ tail /data/mysql/3306/log/error.log

2016-11-21T05:24:10.064466Z 5 [Note] Start binlog_dump to master_thread_id(5) slave_server(20), pos(, 4)

2016-11-21T08:12:52.480029Z 8 [Note] Changed ENFORCE_GTID_CONSISTENCY from OFF to WARN.

若是沒有錯誤信息,才能夠進行下一步開啓enforce_gtid_consistency操做。

mysql> set global enforce_gtid_consistency=on;

Query OK, 0 rows affected (0.00 sec)

而後進行開啓gtid_mode操做,gtid_mode這個參數有四個值,必定要按照以下順序進行gtid_mode的開啓操做(關閉是相反的)。 

  • off:生成的是匿名事務,slave也只能應用匿名事務。
  • off_permissive:生成的是匿名事務,slave能夠應用匿名事務和GTID事務。
  • on_permissive:生成的是GTID事務,slave能夠應用匿名事務和GTID事務。(這一步操做完成後,主節點二進制日誌就會變成gtid模式)
  • on:生成的是GTID事務,slave也只能應用GTID事務。
mysql> set global gtid_mode=off;

Query OK, 0 rows affected (0.03 sec)



mysql> set global gtid_mode=off_permissive;

Query OK, 0 rows affected (0.04 sec)

當主庫設置完gtid_mode=off_permissive以後,這個時候也要在從庫執行到這一步,爲的是slave能夠應用匿名事務和GTID事務。切記,主從設置是交叉的,若是從庫沒有設置到gtid_mode=off_permissive,而主庫下一步操做gtid_mode = on_permissive後,從庫的IO線程就會斷掉。帶來的後果就是若是主從有延遲,那麼主從數據頗有可能會不一致。而且這種狀況下,也不能算是一個完整的在線切換複製類型,只能算是半在線。

正確的作法就是以下操做,在從庫也先進行以下設置:

2)Slave(3307)操做

mysql> set global enforce_gtid_consistency=warn;

Query OK, 0 rows affected (0.00 sec)



mysql> set global enforce_gtid_consistency=on;

Query OK, 0 rows affected (0.00 sec)



mysql> set global gtid_mode=off;

Query OK, 0 rows affected (0.03 sec)


mysql> set global gtid_mode=off_permissive;

Query OK, 0 rows affected (0.04 sec)

當從庫也設置完gtid_mode=off_permissive以後,就能夠在主庫進行開啓GTID了。

3)Master(3306)操做

mysql> set global gtid_mode=on_permissive;

Query OK, 0 rows affected (0.03 sec)

開啓以後,因爲腳本在一直寫數據,你能夠立馬看見二進制狀態的變化。

mysql> show master status;

+------------------+----------+--------------+------------------+--------------------------------------------+

| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                          |

+------------------+----------+--------------+------------------+--------------------------------------------+

| mysql-bin.000004 |    28388 |              |                  | 3b4cc092-af94-11e6-8a81-001dd8b71e2b:1-117 |

+------------------+----------+--------------+------------------+--------------------------------------------+

1 row in set (0.00 sec)

查看肯定已經沒有匿名事務了,這個值ONGOING_ANONYMOUS_TRANSACTION_COUNT有一次爲0便可。

mysql> show status like 'ONGOING_ANONYMOUS_TRANSACTION_COUNT';

+-------------------------------------+-------+

| Variable_name                       | Value |

+-------------------------------------+-------+

| Ongoing_anonymous_transaction_count | 0     |

+-------------------------------------+-------+

1 row in set (0.00 sec)
mysql> SELECT @@GLOBAL.GTID_OWNED;

肯定此時的Retrieved_Gtid_Set/Executed_Gtid_Set正常增加(甚至你能夠在slave上使用:SELECT MASTER_POS_WAIT(file, position);

來強制等待slave端直到指定位置,這個位置就是你肯定的使用GTID事務的位置)。
能夠看到當主庫設置完gtid_mode = on_permissive後,二進制狀態變成了GTID模式。這個時候就能夠在從庫開啓gtid_mode = on_permissive了。

4)Slave(3307)操做

mysql> set global gtid_mode=on_permissive;

Query OK, 0 rows affected (0.03 sec)

接下來show slave status就能夠看到從庫已經切換爲GTID複製了。

mysql> show slave status\G

*************************** 1. row ***************************

               Slave_IO_State: Waiting for master to send event

                  Master_Host: 10.0.60.143

                  Master_User: mysql_slave

                  Master_Port: 3306

                Connect_Retry: 60

              Master_Log_File: mysql-bin.000004

          Read_Master_Log_Pos: 207164

               Relay_Log_File: relay-bin.000005

                Relay_Log_Pos: 207377

        Relay_Master_Log_File: mysql-bin.000004

             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: 207164

              Relay_Log_Space: 207636

              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: 103306

                  Master_UUID: 6edc34c8-d23d-11e6-b440-fa163e2a6390

             Master_Info_File: /data/mysql/3307/data/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: 6edc34c8-d23d-11e6-b440-fa163e2a6390:1-135

            Executed_Gtid_Set: 6edc34c8-d23d-11e6-b440-fa163e2a6390:1-135

                Auto_Position: 0

         Replicate_Rewrite_DB:

                 Channel_Name:

           Master_TLS_Version:

1 row in set (0.01 sec)

5)Master&Slave都操做
下面就能夠在主庫和從庫上分別設置gtid_mod = on了。

mysql> set global gtid_mode=on;

Query OK, 0 rows affected (0.04 sec)

查看gtid的開啓。

mysql> show variables like '%gtid%';

+----------------------------------+-----------+

| Variable_name                    | Value     |

+----------------------------------+-----------+

| binlog_gtid_simple_recovery      | ON        |

| enforce_gtid_consistency         | ON        |

| gtid_executed_compression_period | 1000      |

| gtid_mode                        | ON        |

| gtid_next                        | AUTOMATIC |

| gtid_owned                       |           |

| gtid_purged                      |           |

| session_track_gtids              | OFF       |

+----------------------------------+-----------+

8 rows in set (0.01 sec)

至此,主從複製在線切換GTID已經完成了。最後別忘了把gtid相關信息寫進配置文件中,否則重啓MySQL後就又失效了。具體能夠看:MySQL基於GTIDs的複製實現

change master

mysql> stop slave;

mysql> CHANGE MASTER TO MASTER_HOST='10.0.60.143',MASTER_PORT=3306,master_user='mysql_slave',MASTER_PASSWORD='123456',MASTER_AUTO_POSITION=1;

mysql> start slave;

若是出現主從不一致的狀況,那麼可使用pt工具進行修復便可,詳情請看這篇文章:使用pt-table-checksum&pt-table-sync檢查和修復主從數據一致性


6、在線關閉基於GTID的複製

1)Slave操做

mysql> stop slave;

而後記錄slave status

Exec_Master_Log_Pos: 7631438

Relay_Master_Log_File: bin_log.000016

從新執行CHANGE MASTER

mysql> CHANGE MASTER TO MASTER_AUTO_POSITION = 0,MASTER_LOG_FILE = 'bin_log.000016', MASTER_LOG_POS = 7631438;

從新開啓Slave。

mysql> start slave;

2)Master&slave操做
生成的是GTID事物,slave能夠應用匿名和GTID事物。

mysql> SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;

3)Master&Slave操做

生成的是匿名事物,slave能夠應用匿名和GTID事物。

mysql> SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;

4)Master&Slave操做

mysql> SELECT @@GLOBAL.GTID_OWNED;

等到主庫和備庫此顯示爲空,而且Retrieved_Gtid_Set/Executed_Gtid_Set再也不變更。(甚至你能夠在slave上使用:SELECT MASTER_POS_WAIT(file, position);來強制等待slave端直到指定位置,這個位置就是你肯定的沒有使用GTID事務的位置)
完成這一步實際上GTID事物已經沒有生成和應用了。

5)Master&Slave操做

mysql> SET @@GLOBAL.GTID_MODE = OFF;

最後別忘記修改配置文件my.cnf,使其永久生效。

爲了方便你們交流,本人開通了微信公衆號(關注看更多精彩)和QQ羣,QQ羣1(291519319)和QQ羣2(659336691)。喜歡技術的一塊兒來交流吧

相關文章
相關標籤/搜索