MySQL的非同步複製和半同步複製

天府雲創發表於2017-11-07

Mysql在5.5及其以後的版本引入了半同步的概念,在這裡也普及一些基礎知識。


一:神馬是半同步,同步,非同步。

1:Mysql的複製過程就是slave去master拉日誌回來,存到relay檔案中,然後執行。

2:Master根本不考慮資料是否達到了slave,或者slave是否執行成功了。

3:預設情況下mysql主從複製就是非同步的方式,別看好像資料剛被建立,slve就可以看到了,因為你的資料量太小了,無法感受到非同步的現象。

4:同步就是兩邊資訊都完全一樣,master確認了slvae資料複製並執行成功,才叫同步。


我們舉個生產例子說明一下這件事。

生產中是否做過資料庫讀寫分離?不管什麼資料庫,讀寫分離就是為了減輕資料庫壓力,假設我們有2臺伺服器,A是寫入庫,B是讀庫。使用者註冊了你網站的會員,註冊的時候,是通過A庫寫入, 登入的時候是同步B伺服器,對吧?


非同步:

註冊寫到A庫,應用前端直接返回註冊成功,然後B庫才到A庫拉取新資料,在本地執行同步。如果由於網路,資料量等原因,B庫還沒有執行新資料,新使用者就點選登入視窗,這個時候,應用前端就提示該使用者尚未註冊。。蛋疼了吧??


同步情況:

註冊寫到A庫,A庫要把資訊同步到B庫,確定B庫執行成功後,返回資訊給前端,這個時候應用前端才顯示註冊成功。使用者在註冊後登入就不會出現異常了。這才符合邏輯吧?Mysql主從複製中,主庫根本不去考慮從庫是否把資訊拷貝過去,或者成功執行了。


半同步又是什麼概念??

如果按mysql主從複製原理看,slave到master把資料垃取下來,然後執行,執行完後,把狀態返回給master,這個時候應用程式才給客戶端響應成功,這種延遲,使用者都接受嗎?找一個折中的方法:Mysql半同步在5.5版本橫空出世。


半同步情況:

   一主一從,一主多從情況下,Master節點只要確認至少有一個slave接受到了事務,即可向發起請求的客戶端返回執行成功的操作,master節點是不需要等待slave節點成功執行完這個事務。slave節點接受到這個事務,併成功寫入到本地relay日誌中,就算是成功了。

  半同步在資料完成性上得到了保障,起碼主從架構中,有一個備份集,當然,這也不是說半同步配置成功,就不會丟失資料,都是有可能的,比如sql錯誤,半同步發現錯誤後,預設會自動轉換成半同步的。有利有弊,半同步也增加了成本,對效能也有一定的影響。開源的就是這樣。不然為什麼Oracle要收費。哈哈。。



二:檢視系統是否支援半同步

檢視是否載入半同步外掛。

sql> show plugins;

查詢是否有semisync字母。如果沒有跟著步驟走。


步驟1:查詢mysql外掛目錄位置。

sql>show variables like ‘plugin_dir‘;

+---------------+--------------------------------+
| Variable_name | Value                 |
+---------------+--------------------------------+
| plugin_dir   | /usr/local/mysql56/lib/plugin/ |
+---------------+--------------------------------+

步驟2:檢視目錄檔案是否存在。

$ll /usr/local/mysql56/lib/plugin/

技術分享

我們可以發現有2個檔案,一個是master.so 一個是slave.so,在主伺服器載入master檔案,在從伺服器載入slave檔案就可以。

【實驗拓撲】
MySQL主從複製
主機名主機地址角色
node1192.168.2.201Master
node2192.168.2.202Slave
node3192.168.2.203Slave

本文使用CentOS7.1,資料庫:MariaDB-5.5.50 注意:本文關閉了selinux,以及iptables。

一、非同步複製:

相關知識點:
  • MySQL的非同步複製是MySQL自帶的資料同步功能,在公司裡面也是也就最為常見的。
  • Master伺服器中需要開啟二進位制日誌binlog,從伺服器需要開啟中繼日誌relay-log
  • 二進位制日誌binlog的主要功能是:記錄令資料庫內容產生改變的語句,如insert語句;二進位制日誌在備份還原的時候至關重要。
  • 中繼日誌relay-log則是從伺服器中開啟,作用是從主伺服器的二進位制日誌中複製,並在在從伺服器本地執行一次,達到與主伺服器內容一致的效果。
  • 一般MySQL複製是放在內網中進行的,因為MySQL的同步並沒有進行加密。而且相比較於在公網傳輸,在內網中丟包的概率較低,頻寬也高。
Master節點:Node1
(1) 啟動二進位制日誌;
    [mysqld]
    log_bin=mysql-bin
(2) 為當前節點設定一個全域性唯一的ID號;
    [mysqld]
    server_id=1
(3) 授權建立僅有複製許可權的使用者賬號;
    mysql> GRANT REPLCATION SLAVE, REPLICATION CLIENT ON *.* TO 'repuser'@'192.168.2.%' IDENTIFIED BY 'repuser';

(4)檢視Master端的二進位制日誌記錄到哪裡,用於決定Slave複製的起始位置
    MariaDB [(none)]> show master status;
    +-------------------+----------+--------------+------------------+
    | File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |
    +-------------------+----------+--------------+------------------+
    | Master-log.000001 |     245 |              |                  |
    +-------------------+----------+--------------+------------------+
     #Slave伺服器如果是一個空的資料庫而主伺服器不為空:
     #在同步之前可以先用Master的全量備份,恢復到Slave資料庫中。
     #然後再從備份那一刻記錄的Position開始複製。
     #假設Master和Slave都為空,上面的情況就表示Slave從二進位制日誌Master-log.000001的245開始複製
從節點:Node2設定
(1) 啟動中繼日誌;
    [mysqld]
    relay_log=relay-log
    relay_log_index=relay-log.index
(2) 為當前節點設定一個全域性惟的ID號;
    [mysqld]
    server_id=2
    #node3把這裡改為3
(3) Slave伺服器開啟只讀模式;
    [mysqld]
    read_only = 1
(4) 使用有複製許可權的使用者賬號連線至主伺服器,並啟動複製執行緒;
     #注意:上面的是在/etc/my.cnf的配置檔案中新增,下面mysql>的則是在mysql伺服器中執行的命令
    mysql> CHANGE MASTER TO 
    MASTER_HOST='192.168.2.201', 
    MASTER_USER='repuser', 
    MASTER_PASSWORD='repuser', 
    MASTER_LOG_FILE='Master-log.000001', 
    MASTER_LOG_POS=245;

(5)在從伺服器中開啟複製執行緒
   mysql> START SLAVE;
檢視從伺服器的狀態資訊
mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.2.201
                  Master_User: repuser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: Master-log.000003
          Read_Master_Log_Pos: 1379
               Relay_Log_File: relay-log.000002
                Relay_Log_Pos: 1414
        Relay_Master_Log_File: Master-log.000003
             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: 1379
              Relay_Log_Space: 1702
              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: 1
1 row in set (0.00 sec)

插入幾條命令之後,從以上的狀態資訊中可以看得到我們的Master伺服器是192.168.2.201
擁有複製功能的賬號是repuser,現在複製到Master-log.000003的Position 1379這個位置;
上面的輸出結果中,我在複製完成之後使用了flush logs手動地滾動了二進位制日誌,所以二進位制去到000003

二、半同步複製

相關知識點:
  • 半同步複製是由谷歌研發的一種資料庫主從複製方式。
  • 與傳統的非同步複製相比,半同步複製在多個Slave節點中會選取一個節點進行半同步複製。也就是說,當Master提交一個事務的時候,在這個半同步複製的Slave端返回一個同步完成的Ack包之後,伺服器才會向使用者返回事務提交成功,而其他的節點則是採用傳統的非同步複製方式進行同步。
  • 半同步是複製是基於非同步複製之上進行的,也就是說配置半同步複製之前需要先配置到非同步複製。
  • 半同步複製可以保證在主節點發生故障的時候,總有一個節點的資料與主節點一樣。這樣在進行切換的時候,可以更加快速地把這個Slave節點設定成主節點來使用。
    Master節點:Node1
    由於上面已經進行了非同步複製的配置,下面僅進行半同步複製的操作。
    (1)Master安裝外掛並修改變數:
    mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
    外掛的檔名字和路徑一般在rpm -ql mariadb-server那裡檢視。
    這個外掛的庫檔案是安裝好之後就直接有的,只是沒有預設安裝。
    (2)啟用選項
    mysql> SET GLOBAL VARIABLES rpl_semi_sync_master_enabled=1;
Slave節點:Node2

(1)slave安裝外掛並修改變數:

mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> SET GLOBAL VARIABLES rpl_semi_sync_slave_enabled=1;

這裡需要注意的是,node1作為主節點使用的是master模組。node2,node3作為從節點使用slave模組

(2)檢視半同步複製的全域性變數

mysql> SHOW GLOBAL VARIABLES LIKE '%semi%';
+------------------------------------+-------+
| Variable_name                      | Value |
+------------------------------------+-------+
| rpl_semi_sync_master_enabled       | ON    |
| rpl_semi_sync_master_timeout       | 10000 |
| rpl_semi_sync_master_trace_level   | 32    |
| rpl_semi_sync_master_wait_no_slave | ON    |
+------------------------------------+-------+

設定rpl_semi_sync_master_enabled=1的效果
第一行是ON則表示半同步複製已經開啟。

(3)檢視半同步複製的全域性變數

mysql> SHOW GLOBAL STATUS LIKE '%semi%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 1     |
| Rpl_semi_sync_master_net_avg_wait_time     | 645   |
| Rpl_semi_sync_master_net_wait_time         | 645   |
| Rpl_semi_sync_master_net_waits             | 1     |
| Rpl_semi_sync_master_no_times              | 1     |
| Rpl_semi_sync_master_no_tx                 | 5     |
| Rpl_semi_sync_master_status                | ON    |
| Rpl_semi_sync_master_timefunc_failures     | 0     |
| Rpl_semi_sync_master_tx_avg_wait_time      | 783   |
| Rpl_semi_sync_master_tx_wait_time          | 783   |
| Rpl_semi_sync_master_tx_waits              | 1     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx                | 1     |
+--------------------------------------------+-------+

第一行Rpl_semi_sync_master_clients顯示1,表示有一臺主機是半同步複製的狀態。

最後需要說明的是,semi複製的MySQL5.7中效能有明顯的改善。
假如真的需要使用半同步複製,建議使用5.7的版本。(一般三例項的,從用半同步,從的從用非同步


總結半同步複製:

什麼是半同步複製?我們知道在預設情況下,MySQL的複製是非同步的,這意味著主伺服器及其從伺服器是獨立的。

非同步複製可以提供最佳的效能,因為主伺服器在將更新的資料寫入它的二進位制日誌(Binlog)檔案中後,

無需等待驗證更新資料是否已經複製到從伺服器中,就可以自由處理其它進入的事務處理請求。但這也同時帶來了很高的風險,

如果在主伺服器或從伺服器端發生故障,會造成主從資料的不一致,甚至在恢復時造成資料丟失。

半同步複製是從MySQL5.5開始引入了一種半同步複製功能,該功能可以確保主伺服器和訪問鏈中至少一臺從伺服器之間的資料

一致性和冗餘。在這種配置結構中,一臺主伺服器和其許多從伺服器都進行了配置,這樣在複製拓撲中,

至少有一臺從伺服器在父主伺服器進行事務處理前,必須確認更新已經收到並寫入了其中繼日誌(Relay Log)。當出現超時,

源主伺服器必須暫時切換到非同步複製模式重新複製,直到至少有一臺設定為半同步複製模式的從伺服器及時收到資訊。

非同步複製(Asynchronous replication)

MySQL預設的複製即是非同步的,主庫在執行完客戶端提交的事務後會立即將結果返給給客戶端,並不關心從庫是否已經接收並處理,這樣就會有一個問題,主如果crash掉了,此時主上已經提交的事務可能並沒有傳到從上,如果此時,強行將從提升為主,可能導致新主上的資料不完整。

 

全同步複製(Fully synchronous replication)

指當主庫執行完一個事務,所有的從庫都執行了該事務才返回給客戶端。因為需要等待所有從庫執行完該事務才能返回,所以全同步複製的效能必然會收到嚴重的影響。

 

半同步複製(Semisynchronous replication)

介於非同步複製和全同步複製之間,主庫在執行完客戶端提交的事務後不是立刻返回給客戶端,而是等待至少一個從庫接收到並寫到relay log中才返回給客戶端。相對於非同步複製,半同步複製提高了資料的安全性,同時它也造成了一定程度的延遲,這個延遲最少是一個TCP/IP往返的時間。所以,半同步複製最好在低延時的網路中使用。

 

下面來看看半同步複製的原理圖:

 

 

 

半同步複製的潛在問題

客戶端事務在儲存引擎層提交後,在得到從庫確認的過程中,主庫當機了,此時,可能的情況有兩種

 

事務還沒傳送到從庫上

此時,客戶端會收到事務提交失敗的資訊,客戶端會重新提交該事務到新的主上,當當機的主庫重新啟動後,以從庫的身份重新加入到該主從結構中,會發現,該事務在從庫中被提交了兩次,一次是之前作為主的時候,一次是被新主同步過來的。

 

事務已經傳送到從庫上

此時,從庫已經收到並應用了該事務,但是客戶端仍然會收到事務提交失敗的資訊,重新提交該事務到新的主上。

 

無資料丟失的半同步複製

針對上述潛在問題,MySQL 5.7引入了一種新的半同步方案:Loss-Less半同步複製。

 

針對上面這個圖,“Waiting Slave dump”被調整到“Storage Commit”之前。

 

當然,之前的半同步方案同樣支援,MySQL 5.7.2引入了一個新的引數進行控制-rpl_semi_sync_master_wait_point

rpl_semi_sync_master_wait_point有兩種取值

 

AFTER_SYNC

這個即新的半同步方案,Waiting Slave dump在Storage Commit之前。

 

AFTER_COMMIT

老的半同步方案,如圖所示。

 

半同步複製的安裝部署

要想使用半同步複製,必須滿足以下幾個條件:

1. MySQL 5.5及以上版本

2. 變數have_dynamic_loading為YES

3. 非同步複製已經存在


【參考資料】
1、MySQL的非同步複製和半同步複製 - 簡書 http://www.jianshu.com/p/d877cbe9f0f0
2、Mysql5.6.21半同步 http://www.mamicode.com/info-detail-576734.html
3、MySQL資料的主從複製、半同步複製和主主複製詳解 - CSDN部落格 http://blog.csdn.net/goustzhu/article/details/9339621
4、MySQL非同步複製、半同步複製詳解 - paul_hch - 部落格園 http://www.cnblogs.com/paul8339/p/6879329.html
5、MySQL半同步複製 - iVictor - 部落格園 http://www.cnblogs.com/ivictor/p/5735580.html

相關文章