MySQL 5.7半同步機制

甲骨文技術支援發表於2017-02-27

所謂半同步機制,master節點只要確認有至少一個slave節點接收到了事物,即可向客戶端返回操作成功的資訊,master節點甚至不需要等待slave節點也成功執行完這個事物,只要至少有一個slave節點接收到這個事物,並且將之成功寫入到本地的中繼日誌檔案,就算成功。

一,MySQL的半同步複製是以外掛形式提供,檢視目前是否安裝


  1. (root@localhost) [(none)]> show plugins;
  2. +----------------------------+----------+--------------------+---------+---------+
  3. | Name | Status | Type | Library | License |
  4. +----------------------------+----------+--------------------+---------+---------+
  5. | binlog | ACTIVE | STORAGE ENGINE | NULL | GPL |
  6. | mysql_native_password | ACTIVE | AUTHENTICATION | NULL | GPL |
  7. | sha256_password | ACTIVE | AUTHENTICATION | NULL | GPL |
  8. | MEMORY | ACTIVE | STORAGE ENGINE | NULL | GPL |
  9. | InnoDB | ACTIVE | STORAGE ENGINE | NULL | GPL |
  10. | INNODB_TRX | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  11. | INNODB_LOCKS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  12. | INNODB_LOCK_WAITS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  13. | INNODB_CMP | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  14. | INNODB_CMP_RESET | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  15. | INNODB_CMPMEM | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  16. | INNODB_CMPMEM_RESET | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  17. | INNODB_CMP_PER_INDEX | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  18. | INNODB_CMP_PER_INDEX_RESET | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  19. | INNODB_BUFFER_PAGE | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  20. | INNODB_BUFFER_PAGE_LRU | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  21. | INNODB_BUFFER_POOL_STATS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  22. | INNODB_TEMP_TABLE_INFO | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  23. | INNODB_METRICS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  24. | INNODB_FT_DEFAULT_STOPWORD | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  25. | INNODB_FT_DELETED | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  26. | INNODB_FT_BEING_DELETED | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  27. | INNODB_FT_CONFIG | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  28. | INNODB_FT_INDEX_CACHE | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  29. | INNODB_FT_INDEX_TABLE | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  30. | INNODB_SYS_TABLES | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  31. | INNODB_SYS_TABLESTATS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  32. | INNODB_SYS_INDEXES | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  33. | INNODB_SYS_COLUMNS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  34. | INNODB_SYS_FIELDS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  35. | INNODB_SYS_FOREIGN | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  36. | INNODB_SYS_FOREIGN_COLS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  37. | INNODB_SYS_TABLESPACES | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  38. | INNODB_SYS_DATAFILES | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  39. | INNODB_SYS_VIRTUAL | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  40. | MRG_MYISAM | ACTIVE | STORAGE ENGINE | NULL | GPL |
  41. | PERFORMANCE_SCHEMA | ACTIVE | STORAGE ENGINE | NULL | GPL |
  42. | CSV | ACTIVE | STORAGE ENGINE | NULL | GPL |
  43. | MyISAM | ACTIVE | STORAGE ENGINE | NULL | GPL |
  44. | ARCHIVE | ACTIVE | STORAGE ENGINE | NULL | GPL |
  45. | partition | ACTIVE | STORAGE ENGINE | NULL | GPL |
  46. | FEDERATED | DISABLED | STORAGE ENGINE | NULL | GPL |
  47. | BLACKHOLE | ACTIVE | STORAGE ENGINE | NULL | GPL |
  48. | ngram | ACTIVE | FTPARSER | NULL | GPL |
  49. +----------------------------+----------+--------------------+---------+---------+
  50. 44 rows in set (0.00 sec)
二,本例目前還沒有安裝,檢視plugin目錄位置

  1. (root@localhost) [(none)]> show variables like 'plugin_dir';
  2. +---------------+------------------------------+
  3. | Variable_name | Value |
  4. +---------------+------------------------------+
  5. | plugin_dir | /usr/local/mysql/lib/plugin/ |
  6. +---------------+------------------------------+
  7. 1 row in set (0.00 sec)
三,在plugin目錄下有兩個與半同步相關的外掛

  1. [root@oracle11gtest plugin]# ls -al semisync*
  2. -rwxr-xr-x 1 root root 688816 Feb 6 19:44 semisync_master.so
  3. -rwxr-xr-x 1 root root 150555 Feb 6 19:44 semisync_slave.so
四,在master端安裝semisync_master.so,在slave端安裝semisync_slave.so

  1. (root@localhost) [(none)]> install plugin rpl_semi_sync_master SONAME 'semisync_master.so' ;
  2. Query OK, 0 rows affected (0.04 sec)

  3. (root@localhost) [(none)]> install plugin rpl_semi_sync_slave SONAME 'semisync_slave.so';
  4. Query OK, 0 rows affected (0.01 sec)
五,安裝好之後分別用show plugins命令check下

六,修改主端半同步相關引數

  1. (root@localhost) [(none)]> show variables like '%rpl_semi_sync%';
  2. +-------------------------------------------+------------+
  3. | Variable_name | Value |
  4. +-------------------------------------------+------------+
  5. | rpl_semi_sync_master_enabled | OFF |
  6. | rpl_semi_sync_master_timeout | 10000 |
  7. | rpl_semi_sync_master_trace_level | 32 |
  8. | rpl_semi_sync_master_wait_for_slave_count | 1 |
  9. | rpl_semi_sync_master_wait_no_slave | ON |
  10. | rpl_semi_sync_master_wait_point | AFTER_SYNC |
  11. +-------------------------------------------+------------+
  12. 6 rows in set (0.00 sec)

  13. (root@localhost) [(none)]> set global rpl_semi_sync_master_enabled=1;  ---用於控制是否在主端啟用半同步複製,
  14. Query OK, 0 rows affected (0.00 sec)

  15. (root@localhost) [(none)]> set global rpl_semi_sync_master_timeout=3000;  ---用於指導主端等待slave響應的時間,單位是毫秒,我這裡設為3秒
  16. Query OK, 0 rows affected (0.00 sec)
七,修改slave端半同步相關引數

  1. (root@localhost) [(none)]> show variables like '%rpl_semi_sync%';
  2. +---------------------------------+-------+
  3. | Variable_name | Value |
  4. +---------------------------------+-------+
  5. | rpl_semi_sync_slave_enabled | OFF |
  6. | rpl_semi_sync_slave_trace_level | 32 |
  7. +---------------------------------+-------+
  8. 2 rows in set (0.01 sec)

  9. (root@localhost) [(none)]> set global rpl_semi_sync_slave_enabled=1---用於控制是否在slave端啟用半同步複製,
  10. Query OK, 0 rows affected (0.00 sec)
八,重啟slave節點的io_thread執行緒,目的是讓slave重新連線master,註冊成為半同步的slave身份

  1. (root@localhost) [(none)]> stop slave io_thread;
  2. Query OK, 0 rows affected (0.01 sec)

  3. (root@localhost) [(none)]> start slave io_thread;
  4. Query OK, 0 rows affected (0.00 sec)
九,測試

在master端插入資料
insert into oms3.gl values('zg');
  1. insert into oms3.gl values('gl');
檢視slave是否應用

  1. (root@localhost) [(none)]> select * from oms3.gl;
  2. +------+
  3. | abcd |
  4. +------+
  5. | test |
  6. | gl |
  7. | zg |
  8. +------+
檢視master相關變數
  1. (root@localhost) [mysql]> show status like 'rpl_semi_sync%';
  2. +--------------------------------------------+-------+
  3. | Variable_name | Value |
  4. +--------------------------------------------+-------+
  5. | Rpl_semi_sync_master_clients | 1 |
  6. | Rpl_semi_sync_master_net_avg_wait_time | 0 |
  7. | Rpl_semi_sync_master_net_wait_time | 0 |
  8. | Rpl_semi_sync_master_net_waits | 0 |
  9. | Rpl_semi_sync_master_no_times | 0 |
  10. | Rpl_semi_sync_master_no_tx | 0 |
  11. | Rpl_semi_sync_master_status | ON |
  12. | Rpl_semi_sync_master_timefunc_failures | 0 |
  13. | Rpl_semi_sync_master_tx_avg_wait_time | 417 |
  14. | Rpl_semi_sync_master_tx_wait_time | 834 |
  15. | Rpl_semi_sync_master_tx_waits | 2 |
  16. | Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
  17. | Rpl_semi_sync_master_wait_sessions | 0 |
  18. | Rpl_semi_sync_master_yes_tx | 1 |
主要關注四個引數:
Rpl_semi_sync_master_status ---表示當前master節點是否啟用了半同步模式

Rpl_semi_sync_master_no_tx  ---表示當前未成功傳送到slave節點的事物數量

Rpl_semi_sync_master_yes_tx ---表示當前已成功傳送到slave節點的事物數量

Rpl_semi_sync_master_clients---表示當前處於半同步模式的slave節點數量

5.7的半同步機制變化

一:rpl_semi_sync_master_wait_slave_count引數設定有幾個slave接收到了binlog才成功返回客戶端請求,預設是一臺,但不可以指定是具體哪臺。

二:rpl_semi_sync_master_wait_point 引數,它有兩種選擇:

AFTER_SYNC(5.7預設值,5.6中無此選項)
    主庫把每一個事務寫到二進位制日誌並且傳送給從庫,主庫在等待從庫寫到自己的relay-log裡的確認資訊,在接到確認資訊後,主資料庫把事務寫到儲存引擎裡並把相應結果反饋給客戶端。

AFTER_COMMIT(5.6預設值)
    主庫把每一個事務寫到二進位制日誌並且傳送給從庫,然後馬上就把事務寫到儲存引擎裡;主庫在等待從庫寫到自己的relay-log裡的資訊確認後,主庫把相應結果反饋給客戶端。

他們倆個的區別:
AFTER_COMMIT模式的弊端在於,雖然主庫一直沒有告訴提交事務的客戶端事務已經成功(在從庫成功確認前)但是實際已經提交了,其它客戶端此時已經可以看到事務的結果了。
也就是對於事務提交者自身,的確保證了只要收到成功就一定成功了,但是其它客戶端卻可能存在發現事務成功了,但最後卻沒成功,因為資料已經到了儲存引擎層。

比如A客戶端執行事務將欄位id從0修改為1
1.A提交事務到主庫
2.主庫寫binlog
3.主庫傳送給從庫,同時主庫提交事務到儲存引擎
此時還未收到從庫確認,此時A還在等待結果,但是此時另外客戶端B已經可以看到欄位id為1了。

假如此時主庫當機,如果從庫實際收到剛才的事務僅僅是主庫未收到確認,那麼此時從庫的資料還是正確的也是id=1,客戶端切換到從庫後,都看到id=1
但是如果從庫沒有實際收到剛才的事務,那麼此時從庫上id=0,對於客戶端A,這個並沒有問題,因為A先前提交的事務沒有收到任何反饋,所以A需要透過其它方式來確定先前事務是否成功,也就是A可以接受id=0或id=1。
但是對於客戶端B來說,已經id=1的變成id=0則很可能是無法接受的

AFTER_SYNC模式則可以解決這個問題,繼續上面的例子:
1.A提交事務到主庫
2.主庫寫binlog
3.主庫傳送給從庫
4.主庫等待從庫確認,此時id=0,沒有任何客戶端能看到id=1的結果,因為沒有提交
5.主庫收到從庫確認,主庫開始提交到儲存引擎
6.主庫返回結果給客戶端

假如第4步時主庫當機,客戶端切換到從庫,如果從庫實際接收到事務,那麼此時id=1,如果從庫未接收到事務,那麼此時id=0,
無論哪種狀態,對於所有客戶端資料庫都是一致,事務都沒有丟失,同樣客戶端A需要自己檢查事務狀態,因為他沒收到反饋,業務上他本身就允許兩種可能(提交or回滾)




來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/20893244/viewspace-2134377/,如需轉載,請註明出處,否則將追究法律責任。

相關文章