天天看點

MySQL并發複制系列三:MySQL和MariaDB實作對比

經過上兩篇關于mysql/mariadb 的binary log group commit的發展曆程和enhanced multi-threaded slave的介紹,相信大家對mysql 基于binay log 的replication的原理以及為了解決主備資料複制延遲問題而引入的enhanced multi-threaded slave 功能,支援從庫多線程并發回放主庫送出的事務有了更深入的了解。同時為了更好的發揮mysql 5.7/mariadb 10 并發複制的性能,兩個版本都在主庫binary log group commit的階段做了更加深入的優化。

無論是mysql還是mariadb在binary log group commit優化的目的都是:使高并發下的事務盡可能的在同一個時間點送出,然後用一次fsync()的操作将這一組的binary log緩存的資料寫入磁盤。當并發事務可以在同一個時間送出,說明每個線程所執行的事務之間沒有鎖沖突(如果有鎖沖突,并發的事務将無法在同一個時刻送出),那麼意味着這一組并發送出的事務在slave機器上能并發重放主庫送出的事務,是以我們隻需要在master機器對二進制日志進行group commit的時候标記上組送出相關資訊,slave機器就可以安全的并發執行主庫送出的事務。

我們來看一個例子:

事務t1、t2(start transaction)開始事務,落後于事務t3、t4的(start transaction)開始時間,但是這一組事務都在c(commit)時間點送出事務,是以這一組事務(t1、t2、t3、t4)将在master機器上進行binary log group commit,然後該二進制日志推送到slave機器上時可以并發執行這一組被标記的事務。

MySQL并發複制系列三:MySQL和MariaDB實作對比

原理:

從上面的例子可以看出,并發線程執行不同的事務隻要在同一時刻能夠commit(說明線程之間沒有鎖沖突),那麼master節點就可以将這一組的事務标記并在slave機器上安全的進行并發重放主庫送出的事務。是以盡可能的使所有線程能在同一時刻送出可以極大的提高slave機器并發執行事務的數量使主備資料同步。

在上一篇文章提到過:mysql/mariadb開啟binary log日志後使二進制日志寫入順序和存儲引擎送出順序保持一緻,binary log group commit分為三個過程:

MySQL并發複制系列三:MySQL和MariaDB實作對比

圖1: binary log group commit 三個階段

在 flush stage:所有已經注冊線程都将寫入binary log緩存

在sync stage :binary log緩存的資料将會sync到磁盤,當sync_binlog=1時所有該隊列事務的二進制日志緩存永久寫入磁盤

在 commit stage:    leader根據順序調用存儲引擎送出事務。

那麼為了使更多的并發線程事務能夠視為在同一個時刻commit即在sync階段(調fsync()把binary log檔案系統緩存日志永久刷入磁盤檔案)master機器标記并發送出的事務為同一組事務的資訊寫入binary log日志中。我們可以在flush stage将注冊為leader的線程帶領更多的follower線程到sync stage進行一次fsync()的操作,來增加binary log group commit的數量。

如下圖:

目前mysql/mariadb資料庫執行個體上運作三個線程分别送出t1、t2、t3事務,t1事務的線程率先送出進入第一階段flush stage隊列,發現該隊列是空隊列故注冊成leader,與此同時t2事務進入flush stage成為該隊列的follower等待leader調配,事務t1的leader帶領t2事務進入sync stage進行一次fsync()操作那麼t1、t2在binary log進行一次group commit。

在二進制日志内标記了這一組事務。之後t3線程的事務随後進入了binary log送出的過程。

MySQL并發複制系列三:MySQL和MariaDB實作對比

圖2: 組送出過程

mariadb 10通過@@binlog_commit_wait_count and @@binlog_commit_wait_usec 兩個參數設定,既事務commit階段的時候至少等binlog_commit_wait_usec毫秒直到有binlog_commit_wait_count個數時進行一次組送出,來提高每組事務中的事務數量,并可以通過查詢狀态變量@@binlog_commit和@@binlog_group_commit來查參數來檢視目前binary log group commit比例。

mysql5.7通過引入 binlog_group_commit_sync_delay和 binlog_group_commit_sync_no_delay_count參數即提高binary log組送出并發數量,既mysql等待binlog_group_commit_sync_delay毫秒的時間直到binlog_group_commit_sync_no_delay_count個數時進行一次組送出。

實作:

binary log group commit在mysql 5.7和mariadb 10 中是預設開啟不需要配置任何資訊,且在binary log中标記的組送出資訊依賴于gtid,而mysql和mariadb的gtid組成和實作方式不一樣,這裡我們簡單梳理下。

在mysql 5.7版本由于binary log group commit是預設開啟的,是以即使你不開啟gtid_mode在配置檔案中,binary log的内容中同樣也有gtid 資訊隻不過标記的資訊是"anonymous"

>    show binlog events in 'mysql-bin.000004';截取一段資訊

1.  ...............

| mysql-bin.000004 | 3571 | anonymous_gtid |     15112 |        3636 | set @@session.gtid_next= 'anonymous'          |

2.  | mysql-bin.000004 | 3636 | query          |     15112 |        3712 | begin                   |

3.  | mysql-bin.000004 | 3712 | rows_query     |     15112 |        3763 | # insert into t1 () values ()                 |

4.  | mysql-bin.000004 | 3763 | table_map      |     15112 |        3807 | table_id: 108 (db2.t1)                        |

5.  | mysql-bin.000004 | 3807 | write_rows     |     15112 |        3847 | table_id: 108 flags: stmt_end_f               |

6.  | mysql-bin.000004 | 3847 | xid            |     15112 |        3878 | commit /* xid=33 */                           |

.................

>     mysqlbinlog -vvv mysql-bin.00004 | less

1.  #151231 14:34:03 server id 15112  end_log_pos 2408 crc32 0x5586fe71     anonymous_gtid last_committed=6 sequence_number=8

2.  set @@session.gtid_next= 'anonymous'/*!*/;

3.  # at 2408

4.  #151231 14:34:03 server id 15112  end_log_pos 2484 crc32 0x748efb17     query   thread_id=11    exec_time=0     error_code=0

5.  set timestamp=1451543643/*!*/;

6.  begin

7.  ..

mariadb的gtid同樣也是預設開啟且gtid是由domain id、server id和transaction sequence number組成:

MySQL并發複制系列三:MySQL和MariaDB實作對比

圖3 mariadb gtid組成

>    show binlog events in 'mysql-bin.000003';截取一段資訊

1.  .......

| mysql-bin.000003 |  335 | gtid              |     15102 |         377 | begin gtid 0-15102-64139                      |

2.  | mysql-bin.000003 |  377 | table_map         |     15102 |         434 | table_id: 18 (test.sbtest1)                   |

3.  | mysql-bin.000003 |  434 | write_rows_v1     |     15102 |         657 | table_id: 18 flags: stmt_end_f                |

4.  | mysql-bin.000003 |  657 | xid               |     15102 |         688 | commit /* xid=16 */                           |

5.  | mysql-bin.000003 |  688 | gtid              |     15102 |         732 | begin gtid 0-15102-64140 cid=20               |

6.  | mysql-bin.000003 |  732 | table_map         |     15102 |         789 | table_id: 19 (test.sbtest6)                   |

7.  | mysql-bin.000003 |  789 | write_rows_v1     |     15102 |        1012 | table_id: 19 flags: stmt_end_f                |

8.  | mysql-bin.000003 | 1012 | xid               |     15102 |        1043 | commit /* xid=20 */                           |

9.  | mysql-bin.000003 | 1043 | gtid              |     15102 |        1087 | begin gtid 0-15102-64141 cid=20               |

10. | mysql-bin.000003 | 1087 | table_map         |     15102 |        1145 | table_id: 20 (test.sbtest12)                  |

11. | mysql-bin.000003 | 1145 | write_rows_v1     |     15102 |        1368 | table_id: 20 flags: stmt_end_f                |

12. | mysql-bin.000003 | 1368 | xid               |     15102 |        1399 | commit /* xid=21 */                           |

......

>    mysqlbinlog -vvv mysql-bin.00003  | less

1.     .......

2.     # at 1754

3.  #160104 15:16:46 server id 15102  end_log_pos 1798 crc32 0x26104c0b gtid 0-15102-64143 cid=20 trans

4.  /*!100001 set @@session.gtid_seq_no=64143*//*!*/;

5.  begin

6.  /*!*/;

7.  # at 1798

8.  #160104 15:16:46 server id 15102  end_log_pos 1856 crc32 0x2c994f5a     table_map: `test`.`sbtest12` mapped to number 20

9.  # at 1856

10. #160104 15:16:46 server id 15102  end_log_pos 2079 crc32 0x02b5a694     write_rows: table id 20 flags: stmt_end_f

11.

12.  binlog '

13.  .........

結論:

mysql 5.7 / mariadb 10的parallel replication都是基于主庫上binary log group commit。

mysql:  主庫并發送出的事務group commit寫入binary log日志中,當事務被标記的 last_committed=n的值相同時(通過binlog_group_commit_sync_delay、 binlog_group_commit_sync_no_delay_count參數設定提高并發事務數量),可以在slave節點并發回放主庫送出的事務。

mariadb: 主庫并發送出的事務group commit寫入binary log日志中,當事務被标記的 cid=n 的值相同時(通過 binlog_commit_wait_count、binlog_commit_wait_usec參數設定提高并發事務數量),可以在slave節點并發回放主庫送出的事務。

<b>本文來自雲栖社群合作夥伴“dbgeek”</b>