---本文大綱
一、什麼是GTID
二、應用場景
三、多線程複制說明
四、實作過程
五、多源複制原理
六、實作過程
----------------------------------
一、什麼是GITD
gtid是一個 unique 唯一的表示符,他是由伺服器的uuid 全局唯一辨別,是由128位的随機符組成,mysql-5.6是依靠server-id和uuid 來辨別複制架構中的每一個主機,因為是128位的随機字元串在全局都不會重複,server-id 和uuid以及每一個mysql事物的事物序号組成了唯一的gtid ,自從引進mysql-5.6之後每一個二進制日志當中在每一個事物的首部都會寫上gtid 标記,是以gtid使得追蹤和比較複制事物變得非常簡單而且能夠實作從崩潰中快速恢複。尤其是innodb 引擎要想實作高可用功能必須要借助于gtid來實作。
<a href="http://s3.51cto.com/wyfs02/M00/24/8C/wKioL1NSKh-RfZsnAAHRN5xIcEc108.bmp" target="_blank"></a>
當使用mariadb實作高可用時,GTID是顯得尤為重要,例如,在一個高可用環境中,一主多從的模式下,當主庫當機後(寫延遲),叢集資料總管可以在節點清單中的多個從庫中任選一個提升為主庫,而不會影響到業務本身,而其它的從庫将會以新提升起來為主庫為目前叢集中的主庫,以後将從這個庫上複制同步;雖然這樣做完成了“瞬間”業務切換,但可能在主庫未當機之前,多個從庫的複制同步落後于主庫,這樣一來,當主庫當機後,叢集資料總管正好切換到一個與自己事務送出可能不一緻的從庫(B)上,當有應用讀取之前己在當機的主庫中送出的事務時,發現現在的主庫沒有,這樣就會出現事務不一緻,而GTID就能很好的解決這個問題。首先當一個從庫被提升為一個主庫時,那麼之前指向原來主庫的從庫将全部指向新提升的主庫,來進行之後的複制,而後,剛提升的主庫B會整合所有從庫中己完成的的事務,來添補自己缺少的部分,而B從那裡知道,缺少的是那一個事務,有那麼多的事務,這個事務是那一個呢,這就是通過GTID來辨別的,因為GTID辨別了來源伺服器的辨別與第多少個事務(Source_id:transaction_id),每一個改變是事件都會與GTID相關連起來記錄于binlog日志中以供其它從庫同步,進而做到全局唯一的辨別。
注:
在多級複制中GTID是不會改變的。
在GTID中,如果主伺服器中有多個資料庫,要實作多線程複制是靠I/O複制到從庫的中繼日志中由多個SQL thread來進行應用于本地的。
MySQL 5.6之前的版本,同步複制是單線程的,隊列的,隻能一個一個執行,在5.6裡,可以做到多個庫之間的多線程複制,例如資料庫裡,存放着使用者表,商品表,價格表,訂單表,那麼将每個業務表單獨放在一個庫裡,這時就可以做到多線程複制,但一個庫裡的表,多線程複制是無效的。
每個資料庫僅能使用一個線程,複制涉及到多個資料庫時多線程複制才有意義;
同一個庫的事務複制,就必須按先後順序複制。
在複制模型中,同一個線程(I/O線程)可以對多個資料庫提供服務。
此處僅是實作GTID複制。
1、資源配置設定
服務類型
版本類型
ip位址
OS
Centos6.5x86_64
無
Mariadb Master
10.0.10-MariaDB-log Source distribution
192.168.1.122/24
Mariadb Slave
192.168.1.210/24
2、Mariadb Master配置清單
⑴、編輯配置檔案/etc/my.cnf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<code>[client]</code>
<code>port = 3306</code>
<code>socket = </code><code>/tmp/maria</code><code>.sock</code>
<code>[mysqld]</code>
<code>skip-external-locking</code>
<code>key_buffer_size = 256M</code>
<code>max_allowed_packet = 1M</code>
<code>table_open_cache = 256</code>
<code>sort_buffer_size = 1M</code>
<code>read_buffer_size = 1M</code>
<code>read_rnd_buffer_size = 4M</code>
<code>myisam_sort_buffer_size = 64M</code>
<code>thread_cache_size = 8</code>
<code>query_cache_size= 16M</code>
<code>thread_concurrency = 4</code>
<code>datadir=</code><code>/mydata/data</code>
<code>log-bin=mysql-bin</code>
<code>binlog_format=row</code>
<code>server-</code><code>id</code><code>=10</code>
<code>log-slave-update =True</code>
<code>master-info-repository=TABLE</code>
<code>relay-log-info-repository=TABLE</code>
<code>sync</code><code>-master-info=1</code>
<code>slave-parallel-threads=2</code>
<code>master-verify-checksum=CRC32</code>
<code>slave-sql-verify-checksum=1</code>
<code>binlog-rows-query-log-events=1</code>
<code>report-port=3306</code>
<code>report-host=master.mysql.com</code>
<code>[mysqldump]</code>
<code>quick</code>
<code>max_allowed_packet = 16M</code>
<code>[mysql]</code>
<code>no-auto-rehash</code>
<code>[myisamchk]</code>
<code>key_buffer_size = 128M</code>
<code>sort_buffer_size = 128M</code>
<code>read_buffer = 2M</code>
<code>write_buffer = 2M</code>
<code>[mysqlhotcopy]</code>
<code>interactive-timeout</code>
注解:
binlog-format
二進制日志的格式,有row、statement和mixed幾種類型;
當設定隔離級别為READ-COMMITED必須設定二進制日志格式為ROW,現在MySQL官方認為STATEMENT這個已經不再适合繼續使用;但mixed類型在預設的事務隔離級别下,可能會導緻主從資料不一緻;
log-slave-updates、report-port和report-host
用于啟動GTID及滿足附屬的其它需求;
master-info-repository和relay-log-info-repository
啟用此兩項,可用于實作在崩潰時保證二進制及從伺服器安全的功能;
sync-master-info
啟用之可確定無資訊丢失;
slave-paralles-threads
設定從伺服器的SQL線程數;0表示關閉多線程複制功能;
binlog-checksum、master-verify-checksum和slave-sql-verify-checksum
啟用複制有關的所有校驗功能;
binlog-rows-query-log-events
啟用之可用于在二進制日志記錄事件相關的資訊,可降低故障排除的複雜度;
log-bin
啟用二進制日志,這是保證複制功能的基本前提;
server-id
同一個複制拓撲中的所有伺服器的id号必須惟一
log_slave_updates
記錄從伺服器的更新
⑵、授權複制節點及使用者
<code>MariaDB [(none)]> </code><code>GRANT</code> <code>REPLICATION SLAVE </code><code>ON</code><code>*.* </code><code>TO</code> <code>[email protected] IDENTIFIED </code><code>BY</code> <code>'replpass'</code><code>;</code>
<code>Query OK, 0 </code><code>rows</code> <code>affected (0.01 sec)</code>
<code>MariaDB [(none)]> flush </code><code>privileges</code>
<code> </code><code>-> ;</code>
<code>Query OK, 0 </code><code>rows</code> <code>affected (0.00 sec)</code>
⑶、備份Master節點的資料,同步于slave(此操作并非必須的,如果Master上有大量資料需要同步到新的Slave上,Slave是新上線的此操作才有意義)
<code># mysqldump -uroot -hmaster.mysql.com --all-databases --lock-all-tables --flush-logs --master-data=2 > /tmp/all.sql</code>
<code>#scp /tmp/all.sql 192.168.1.210:/tmp</code>
⑷、檢視一下Master GTID辨別
<code>MariaDB [(none)]> show variables </code><code>like</code> <code>"%gtid%"</code>
<code>+</code><code>------------------------+----------+</code>
<code>| Variable_name | Value |</code>
<code>| gtid_binlog_pos | 0-1-2130 |</code>
<code>| gtid_binlog_state | 0-1-2130 |</code>
<code>| gtid_current_pos | 0-1-2130 |</code>
<code>| gtid_domain_id | 0 |</code>
<code>| gtid_ignore_duplicates | </code><code>OFF</code> <code>|</code>
<code>| gtid_seq_no | 0 |</code>
<code>| gtid_slave_pos | |</code>
<code>| gtid_strict_mode | </code><code>OFF</code> <code>|</code>
<code>| last_gtid | 0-1-2130 |</code>
<code>9 </code><code>rows</code> <code>in</code> <code>set</code> <code>(0.00 sec)</code>
3、Mariadb Slave配置清單
44
45
<code>relay-log=relay-log-bin</code>
<code>server-</code><code>id</code><code>=20</code>
<code>binlog-</code><code>format</code><code>=ROW</code>
<code>log-slave-updates=</code><code>true</code>
<code>binlog-checksum=CRC32</code>
<code>master-verify-checksum=1</code>
<code>binlog-rows-query-log_events=1</code>
<code>report-host=slave.mysql.com</code>
除了server-id,其它的都與主庫一樣。
⑵、應用完全備份
<code># mysql </tmp/all.sql</code>
⑶、連接配接Master
<code>MariaDB [(none)]> change master </code><code>to</code> <code>master_host=</code><code>'192.168.1.122'</code><code>,master_user=</code><code>'repluser'</code><code>,master_password=</code><code>'replpass'</code><code>,master_use_gtid=current_pos;</code>
⑷、看一下效果
<a href="http://s3.51cto.com/wyfs02/M01/24/90/wKioL1NSlejjtfQRAAYk3TiXlIA217.jpg" target="_blank"></a>
⑸、測試一下
在Master建立一個資料庫,建立一張測試表
<code>MariaDB [(none)]> use yydb</code>
<code>Database</code> <code>changed</code>
<code>MariaDB [yydb]> </code><code>create</code> <code>table</code> <code>t1 (id </code><code>int</code><code>(4) </code><code>not</code> <code>null</code><code>,</code><code>name</code> <code>char</code><code>(30) </code><code>not</code> <code>null</code><code>);</code>
<code>Query OK, 0 </code><code>rows</code> <code>affected (0.03 sec)</code>
在Slave的日志檢視一下,是否含有GTID辨別
<code># at 793</code>
<code>#140419 23:40:27 server id 1 end_log_pos 726 CRC32 0x7d8f09f0 GTID 0-1-2132</code>
<code>/*!100001 SET @@session.gtid_seq_no=2132*</code><code>//</code><code>*!*/;</code>
<code># at 835</code>
<code>#140419 23:40:27 server id 1 end_log_pos 852 CRC32 0x4b60d93e Query thread_id=4 exec_time=0 error_code=0</code>
<code>use `yydb`/*!*/;</code>
<code>SET TIMESTAMP=1397922027/*!*/;</code>
<code>create table t1 (</code><code>id</code> <code>int(4) not null,name char(30) not null)</code>
<code>/*!*/;</code>
如果Master與Slave的GTID辨別不符,就無法實作基于GTID的複制,隻要将Slave庫中的GTID修改與Master一緻就可以了
檢視GTID辨別的語句是
<code>MariaDB [yydb]> show </code><code>global</code> <code>variables </code><code>like</code> <code>'gtid_current_pos'</code><code>;</code>
修改GTID的語句是
<code>MariaDB [(none)]> </code><code>SET</code> <code>GLOBAL</code> <code>gtid_slave_pos =</code><code>'Master_GTID'</code><code>;</code>
=================================基于GTID複制到此結束====================================
首先,我們需要清楚 multi-master 與multi-source 複制不是一樣的. Multi-Master 複制通常是環形複制,你可以在任意主機上将資料複制給其他主機。
<a href="http://s3.51cto.com/wyfs02/M02/24/90/wKioL1NSzBLROFPdAAPnGUo1a2Y130.jpg" target="_blank"></a>
Multi-source 是不同的. MySQL5.7版本中修複了一個複制限制 , 這限制是一個從站隻能有一個主站. 這是一個在我們設計複制環境中的限制因素,也有一些極客使它正常工作了。但是現在有一個官方的解決辦法了。是以。簡單的說, Multi-Source 意味着一個從站能有一個以上主站. 現在, 像下圖一樣的複制環境是可能的:
<a href="http://s3.51cto.com/wyfs02/M01/24/91/wKiom1NSzVrAcEHxAAPUwKAkuC0275.jpg" target="_blank"></a>
這将幫助我們建立一些複制的層次結構,這在過去是不可能的。 舉個例子,你可以 将一個從站放在你的辦公室裡。在辦公室裡從所有主站中複制資料傳播到世界各地。
而在微觀上說,各Master開啟一個binlog dump線程通知Slave端,由Slave開啟多個IO threads到各Master端上複制二進制日志并記錄到本地的relay日志中,由本地的SQL thread在讀取出來并在本地應用。進而實作複制功能。
六、配置過程
IP位址
Master 1
192.168.1.109
Master 2
192.168.1.111
Slave
192.168.1.110
2、在各Master上開啟二進制日志,授權複制使用者
⑴、Master 1
編輯配置檔案
<code>socket = </code><code>/tmp/mysql</code><code>.sock</code>
<code>datadir=</code><code>/mariadb/data</code>
<code>server-</code><code>id</code><code>= 10</code>
binlog-format日志格式使用預設就可以
隻需要修改[mysqld]區域
授權複制使用者
<code>MariaDB [(none)]> </code><code>grant</code> <code>replication slave,replication client </code><code>on</code> <code>*.* </code><code>to</code> <code>'repluser'</code><code>@</code><code>'192.168.1.110'</code> <code>identified </code><code>by</code> <code>'replpass'</code><code>;</code>
⑵、Master 2
<code>#vim /etc/my.cnf</code>
<code>server-</code><code>id</code><code>= 20</code>
<code>MariaDB [(none)]> grantreplication slave,replication client </code><code>on</code><code>*.* </code><code>to</code><code>'repluser'</code><code>@</code><code>'192.168.1.110'</code><code>identified </code><code>by</code><code>'replpass'</code><code>;</code>
<code>Query OK, 0 rowsaffected (0.00 sec)</code>
⑶、Slave
連接配接兩個Master
<code>MariaDB [(none)]> change master </code><code>'Master1'</code> <code>to</code> <code>master_host=</code><code>'192.168.1.109'</code><code>,master_user=</code><code>'repluser'</code><code>,master_password=</code><code>'replpass'</code><code>,master_log_file=</code><code>'mysql-bin.000006'</code><code>,master_log_pos=326;</code>
檢視Slave的狀态
46
47
<code>MariaDB [(none)]> show slave </code><code>'Master1'</code> <code>status\G</code>
<code>*************************** </code><code>1</code><code>. row ***************************</code>
<code> </code><code>Slave_IO_State: Waiting </code><code>for</code> <code>master to send event</code>
<code> </code><code>Master_Host: </code><code>192.168</code><code>.</code><code>1.109</code>
<code> </code><code>Master_User: repluser</code>
<code> </code><code>Master_Port: </code><code>3306</code>
<code> </code><code>Connect_Retry: </code><code>60</code>
<code> </code><code>Master_Log_File: mysql-bin.</code><code>000007</code>
<code> </code><code>Read_Master_Log_Pos: </code><code>326</code>
<code> </code><code>Relay_Log_File: master-relay-bin-master1.</code><code>000009</code>
<code> </code><code>Relay_Log_Pos: </code><code>535</code>
<code> </code><code>Relay_Master_Log_File: mysql-bin.</code><code>000007</code>
<code> </code><code>Slave_IO_Running: Yes</code>
<code> </code><code>Slave_SQL_Running: Yes</code>
<code> </code><code>Replicate_Do_DB:</code>
<code> </code><code>Replicate_Ignore_DB:</code>
<code> </code><code>Replicate_Do_Table:</code>
<code> </code><code>Replicate_Ignore_Table:</code>
<code> </code><code>Replicate_Wild_Do_Table:</code>
<code> </code><code>Replicate_Wild_Ignore_Table:</code>
<code> </code><code>Last_Errno: </code><code>0</code>
<code> </code><code>Last_Error:</code>
<code> </code><code>Skip_Counter: </code><code>0</code>
<code> </code><code>Exec_Master_Log_Pos: </code><code>326</code>
<code> </code><code>Relay_Log_Space: </code><code>1128</code>
<code> </code><code>Until_Condition: None</code>
<code> </code><code>Until_Log_File:</code>
<code> </code><code>Until_Log_Pos: </code><code>0</code>
<code> </code><code>Master_SSL_Allowed: No</code>
<code> </code><code>Master_SSL_CA_File:</code>
<code> </code><code>Master_SSL_CA_Path:</code>
<code> </code><code>Master_SSL_Cert:</code>
<code> </code><code>Master_SSL_Cipher:</code>
<code> </code><code>Master_SSL_Key:</code>
<code> </code><code>Seconds_Behind_Master: </code><code>0</code>
<code>Master_SSL_Verify_Server_Cert: No</code>
<code> </code><code>Last_IO_Errno: </code><code>0</code>
<code> </code><code>Last_IO_Error:</code>
<code> </code><code>Last_SQL_Errno: </code><code>0</code>
<code> </code><code>Last_SQL_Error:</code>
<code> </code><code>Replicate_Ignore_Server_Ids:</code>
<code> </code><code>Master_Server_Id: </code><code>10</code>
<code> </code><code>Master_SSL_Crl:</code>
<code> </code><code>Master_SSL_Crlpath:</code>
<code> </code><code>Using_Gtid: No</code>
<code> </code><code>Gtid_IO_Pos:</code>
<code>1</code> <code>row </code><code>in</code> <code>set</code> <code>(</code><code>0.00</code> <code>sec)</code>
<code>MariaDB [(none)]> change master </code><code>'Master2'</code> <code>to</code> <code>master_host=</code><code>'192.168.1.111'</code><code>,master_user=</code><code>'repluser'</code><code>,master_password=</code><code>'replpass'</code><code>,master_log_file=</code><code>'mysql-bin.000010'</code><code>,master_log_pos=342;</code>
<code>MariaDB [(none)]> show slave </code><code>'Master2'</code> <code>status\G</code>
<code>*************************** 1. row ***************************</code>
<code> </code><code>Slave_IO_State: Waiting </code><code>for</code> <code>master </code><code>to</code> <code>send event</code>
<code> </code><code>Master_Host: 192.168.1.111</code>
<code> </code><code>Master_Port: 3306</code>
<code> </code><code>Connect_Retry: 60</code>
<code> </code><code>Master_Log_File: mysql-bin.000010</code>
<code> </code><code>Read_Master_Log_Pos: 342</code>
<code> </code><code>Relay_Log_File: master-relay-bin-master2.000002</code>
<code> </code><code>Relay_Log_Pos: 535</code>
<code> </code><code>Relay_Master_Log_File: mysql-bin.000010</code>
<code> </code><code>Last_Errno: 0</code>
<code> </code><code>Skip_Counter: 0</code>
<code> </code><code>Exec_Master_Log_Pos: 342</code>
<code> </code><code>Relay_Log_Space: 841</code>
<code> </code><code>Until_Log_Pos: 0</code>
<code> </code><code>Master_SSL_Allowed: </code><code>No</code>
<code> </code><code>Seconds_Behind_Master: 0</code>
<code>Master_SSL_Verify_Server_Cert: </code><code>No</code>
<code> </code><code>Last_IO_Errno: 0</code>
<code> </code><code>Last_SQL_Errno: 0</code>
<code> </code><code>Master_Server_Id: 20</code>
<code> </code><code>Using_Gtid: </code><code>No</code>
<code>1 row </code><code>in</code> <code>set</code> <code>(0.00 sec)</code>
⑷、測試一下
在Master1建立一個資料庫,在Master2也建立一個資料庫
<code>MariaDB [(none)]> show variables </code><code>like</code> <code>'server_id'</code><code>;</code>
<code>+</code><code>---------------+-------+</code>
<code>| Variable_name | Value |</code>
<code>| server_id | 10 |</code>
<code>MariaDB [(none)]> </code><code>create</code> <code>database</code> <code>m1db;</code>
<code>Query OK, 1 row affected (0.01 sec)</code>
<code>MariaDB [(none)]> show databases;</code>
<code>+</code><code>--------------------+</code>
<code>| </code><code>Database</code> <code>|</code>
<code>| information_schema |</code>
<code>| jjdb |</code>
<code>| m1db |</code>
<code>| mysql |</code>
<code>| performance_schema |</code>
<code>| test |</code>
<code>| yydb |</code>
<code>7 </code><code>rows</code> <code>in</code> <code>set</code> <code>(0.00 sec)</code>
<code>| server_id | 20 |</code>
<code>MariaDB [(none)]> </code><code>create</code> <code>database</code> <code>m2db;</code>
<code>Query OK, 1 row affected (0.00 sec)</code>
<code>| m2db |</code>
<code>| xxdb |</code>
<code>6 </code><code>rows</code> <code>in</code> <code>set</code> <code>(0.00 sec)</code>
<code>MariaDB [(none)]></code>
在Slave端顯示結果為
在此實驗中多源複制各Master中不能有同名庫,否則複制将失敗。
===========================================完=====================================
本文轉自 jinlinger 51CTO部落格,原文連結:http://blog.51cto.com/essun/1398848,如需轉載請自行聯系原作者