MySQL GTID複製

什麼是GTID

什麼是GTID呢, 簡而言之,就是全局事務ID(global transaction identifier ),最初由google實現,官方MySQL在5.6才加入該功能。
GTID是事務提交時建立分配的惟一標識符,全部事務均與GTID一一映射。html

GTID的格式相似於:
5882bfb0-c936-11e4-a843-000c292dc103:1
這個字符串,用「:」分開,前面表示這個服務器的server_uuid,這是一個128位的隨機字符串,在第一次啓動時生成(函數generate_server_uuid),對應的variables是隻讀變量server_uuid。 它能以極高的機率保證全局惟一性,並存到文件
DATADIR/auto.cnf中。所以要注意保護這個文件不要被刪除或修改。mysql

第二部分是一個自增的事務ID號,事務id號+server_uuid來惟一標示一個事務。sql

一個GTID的生命週期包括:
1.事務在主庫上執行並提交
給事務分配一個gtid(由主庫的uuid和該服務器上未使用的最小事務序列號),該GTID被寫入到binlog中。
2.備庫讀取relaylog中的gtid,並設置session級別的gtid_next的值,以告訴備庫下一個事務必須使用這個值
3.備庫檢查該gtid是否已經被其使用並記錄到他本身的binlog中。slave須要擔保以前的事務沒有使用這個gtid,也要擔保此時已讀取gtid,但未提交的事務也不能使用這個gtid.
4.因爲gtid_next非空,slave不會去生成一個新的gtid,而是使用從主庫得到的gtid。這能夠保證在一個複製拓撲中的同一個事務gtid不變。
因爲GTID在全局的惟一性,經過GTID,咱們能夠在自動切換時對一些複雜的複製拓撲很方便的提高新主庫及新備庫,例如經過指向特定的GTID來肯定新備庫複製座標。

shell

mysql> show global variables like '%gtid%';
+--------------------------+------------------------------------------+
| Variable_name            | Value                                    |
+--------------------------+------------------------------------------+
| enforce_gtid_consistency | ON                                       |
| gtid_executed            | 5882bfb0-c936-11e4-a843-000c292dc103:1-6 |
| gtid_mode                | ON                                       |
| gtid_owned               |                                          |
| gtid_purged              |                                          |
+--------------------------+------------------------------------------+
5 rows in set (0.00 sec)

mysql> show global variables like '%uuid%';
+---------------+--------------------------------------+
| Variable_name | Value                                |
+---------------+--------------------------------------+
| server_uuid   | 5882bfb0-c936-11e4-a843-000c292dc103 |
+---------------+--------------------------------------+
1 row in set (0.00 sec)

shell> cat auto.cnf 
[auto]
server-uuid=5882bfb0-c936-11e4-a843-000c292dc103

設置GTID複製

  1. 同步主從數據
    mysql> SET @@global.read_only = ON;
    Query OK, 0 rows affected (0.01 sec)
  2. 中止全部數據庫
    shell> mysqladmin -u root -p shutdown
  3. 設置開發GTID模式並啓動全部數據庫數據庫

    shell> vi my.cnf  添加以下內容
    ================================================================
    [mysqld]
    gtid_mode=ON
    log-slave-updates=ON
    enforce-gtid-consistency=ON          #強制GTID的一致性
    ================================================================
  4. 從庫指定主庫安全

    mysql> CHANGE MASTER TO  
         -> MASTER_HOST = host, 
         -> MASTER_PORT = port, 
         -> MASTER_USER = user, 
         -> MASTER_PASSWORD = password, 
         -> MASTER_AUTO_POSITION = 1;
    
    mysql> START SLAVE;
    Query OK, 0 rows affected (0.04 sec)
  5. 禁止read-only模式服務器

    mysql> SET @@global.read_only = OFF;
    Query OK, 0 rows affected (0.00 sec)

多線程複製基於庫 

MySQL 5.6以前的版本,同步複製是單線程的,隊列的,只能一個一個執行,在5.6裏,能夠作到多個庫之間的多線程複製,例如數據庫裏,存放着用戶表,商品表,價格表,訂單表,那麼將每一個業務表單獨放在一個庫裏,這時就能夠作到多線程複製,但一個庫裏的表,多線程複製是無效的。 注,每一個數據庫僅能使用一個線程,複製涉及到多個數據庫時多線程複製纔有意義session

GTID複製的限制

GTID 模式實例和非GTID模式實例是不能進行復制的,要求很是嚴格,要麼都是GTID,要麼都不是
gtid_mode 是隻讀的,要改變狀態必須1)關閉實例、2)修改配置文件、3) 重啓實例多線程

  • 更新非事務引擎表
    在同一事務中更新事務表與非事務表將致使多個GTIDs分配給同一事務
mysql> cretea table tt (id int) engine=myisam;
mysql> insert into tt values(1),(2);
mysql> cretea table t (id int) engine=innodb;
mysql> insert into t values(1),(2);
mysql> set autocommit = 0;
mysql> begin;

mysql> update t set id = 3 where id =2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update tt set id = 3 where id =2;
ERROR 1785 (HY000): When @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1, updates to non-transactional tables can 
only be done in either autocommitted statements or single-statement transactions, and never in the same 
statement as updates to transactional tables.
  • CREATE TABLE … SELECT statements
    不安全的基於語句複製,實際是兩個獨立的事件,一個用於建表,一個用於向新表插入源表數據。
mysql> create table t engine=innodb as select * from tt;
ERROR 1786 (HY000): CREATE TABLE ... SELECT is forbidden when @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1.
  • 臨時表
    事務內部不能執行建立刪除臨時表語句,但能夠在事務外執行,但必須設置set autocommit = 1
mysql> create temporary table tttt(id int);
ERROR 1787 (HY000): When @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1, the statements CREATE TEMPORARY TABLE and 
DROP TEMPORARY TABLE can be executed in a non-transactional context only, and require that AUTOCOMMIT = 1.
mysql> set autocommit = 1;
Query OK, 0 rows affected (0.00 sec)

mysql> create temporary table tttt(id int);
Query OK, 0 rows affected (0.04 sec)
  • 不執行不支持的語句
    啓用--enforce-gtid-consistency選項啓動GTID模式,上述不支持的語句將會返回錯誤。

運維操做

a. 忽略複製錯誤
當備庫複製出錯時,傳統的跳過錯誤的方法是設置sql_slave_skip_counter,而後再START SLAVE。
但若是打開了GTID,就會設置失敗:運維

mysql> stop slave;
Query OK, 0 rows affected (0.03 sec)

mysql> set global sql_slave_skip_counter = 1;
ERROR 1858 (HY000): sql_slave_skip_counter can not be set when the server is running with @@GLOBAL.GTID_MODE = ON.
Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction

提示的錯誤信息告訴咱們,能夠經過生成一個空事務來跳過錯誤的事務。
咱們手動產生一個備庫複製錯誤:

[slave]
mysql> alter table t add primary key pk_id(id);
Query OK, 2 rows affected (0.12 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> insert into t values(1);
mysql> insert into t values(4);
mysql> insert into t values(5);

mysql> show master status ;
+-------------------+----------+--------------+------------------+-------------------------------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                         |
+-------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-info.000004 |      914 |              |                  | 5882bfb0-c936-11e4-a843-000c292dc103:1-17 |
+-------------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)

mysql> show slave status \G
*************************** 1. row ***************************
     ...
       Slave_IO_Running: Yes
       lave_SQL_Running: No
             Last_Errno: 1062
             Last_Error: Could not execute Write_rows event on table db_test.t; Duplicate entry '1' for key 'PRIMARY', 
       Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-info.000004, end_log_pos 401
     Retrieved_Gtid_Set: 5882bfb0-c936-11e4-a843-000c292dc103:1-15
      Executed_Gtid_Set: 5882bfb0-c936-11e4-a843-000c292dc103:1-14,
                         f1e6584a-c935-11e4-a840-000c29348dbe:1
          Auto_Position: 1
1 row in set (0.00 sec)


mysql> SET @@SESSION.GTID_NEXT= '5882bfb0-c936-11e4-a843-000c292dc103:15';
Query OK, 0 rows affected (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> SET SESSION GTID_NEXT = AUTOMATIC;

mysql> start slave;

mysql> show slave status\G
*************************** 1. row ***************************
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
                   Last_Errno: 0
           Retrieved_Gtid_Set: 5882bfb0-c936-11e4-a843-000c292dc103:1-17
            Executed_Gtid_Set: 5882bfb0-c936-11e4-a843-000c292dc103:1-17,
                               f1e6584a-c935-11e4-a840-000c29348dbe:1
                Auto_Position: 1
1 row in set (0.00 sec)

再查看show slave status,就會發現錯誤事務已經被跳過了。這種方法的原理很簡單,空事務產生的GTID加入到GTID_EXECUTED中,
這至關於告訴備庫,這個GTID對應的事務已經執行了,此時主從數據不一致。

b.重指主庫

使用change master to …. , MASTER_AUTO_POSITION=1;
注意在整個複製拓撲中,都須要打開gtid_mode

c.適當減少binlog文件的大小

若是開啓GTID,理論上最好調小每一個binlog文件的最大值,以縮小掃描文件的時間。
 
參考:http://mysqllover.com/?p=594    ##比較深刻,源碼級別
   http://www.iyunv.com/thread-22122-1-1.html
   http://blog.itpub.net/29733787/viewspace-1462550/
相關文章
相關標籤/搜索