iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 10
0

(以下文章擷取自筆者的 blog,分享給大家)

在資料庫的備援部份,採用 SQL Server Log-shipping 方式來處理,希望在移轉至 MariaDB 時也有不錯的類似 Log-shipping 方式執行。

MariaDB Replication uses GTID

接下來的文章來自於許多的文件,從官方文件MariaDB · 版本特性 · MariaDB 的 GTID 介绍,還有mariadb10 GTID 研究笔记. md實作,整理了一下。

Master 與 Slave

與 SQL Server Log-shipping 不一樣的地方如下

  1. 不管什麼樣的 Replication (樹狀或是環型串聯),發動端皆是 Slave,也就是說 Master 不存放任何有關 Replication 的資料,所有資料皆在 Slave 裡。
  2. 在 Primary Database (Master) 會是 Backup Trasnsaction 的動作,而在 Secondary Database (Slave) 是 Copy 與 Restore 的動作,在 MariaDB Replication 只會在 Slave 連到 Master 時看要複製哪一段的 binlog 加以重現。
  3. 因為 GTID 的設計,一個 Slave 的 Master 可以是多個,當然一個 Master 可以有多個 Slave。
  4. Slave 重現完資料以後就會繼續跟 Master 要進一步的 binlog 資料,所以基本上是沒有落差可言的,在 SQL Server Log-shipping 是有發動時間設定的(預設為 15 分鐘)。
  5. 系統的資料庫 (mysql 那些)也可以做 Replication。

在 4 的部份,其實對於現在的維運有些麻煩。因為這 15 分鐘的落差,可以拿來利用成正式環境的 buffer,下錯指令時如果還在 15 分鐘的時間分隔下,還可以趕快去備援區拿資料蓋回去,現在沒有時間設定的話就比較麻煩。有人發個 issue 希望能 merge MySQL 的 MASTER_DELAY 功能,不過表定是 10.2.x 的功能,希望能實作在 10.1.x。

在 5 的部份筆者覺得還蠻方便的就是帳號密碼的同步,在 SQL Server Log-shipping 是要分開想辦法同步的,管理就很方便了。

Slave 如何透過 GTID 做 Replication

GTID 的規格部份就不解釋了,上面的文件寫的很清楚。

在 MariaDB 有一些 Server Variables 紀錄 GTID 的資訊

Server Variables Names 意義
gtid_binlog_pos binlog 裡最後一筆紀錄的 GTID
gtid_slave_pos Slave 上紀錄的最後一個 binlog GTID
gtid_current_pos Database 上紀錄的最後一個 binlog GTID

什麼叫作 "紀錄的最後一個 binlog GTID" 呢?

gtid_slave_pos 來說,就是 master 的最後一筆 GTID。

gtid_current_pos 來說,不管當下的 Instance 之前是 Master 還是 Slave

     if gtid_binlog_pos.ServerID = Instance.ServerID and gtid_binlog_pos.DomainID = Instance.DomainID and gtid_binlog_pos.SequenceID > gtid_slave_pos.SequenceID (同 ServerID 與 DomainID 狀態下) then
       gtid_current_pos = gtid_binlog_pos
     else 
       gtid_current_pos = gtid_slave_pos (同 ServerID 與 DomainID 狀態下)
     end if

官方文件有說到一個例子,假設 A 為 Master,B 為 Slave,參數為 slave_pos,把 A 先關一會兒,讓 B 成為 Master,最後回復 A 並成為 B 的 Slave。

MariaDB_Replication_1

  • 一開始 A 的 gtid_binlog_posgtid_current_pos 相同(1-1-123, 1-1-137, 1-1-145),gtid_slave_pos 是空值。
  • B 的 gtid_slave_pos 記著 A 的最後一個 GTID。
  • 在 A 的 1-1-145 的時候把 A 先關掉,中間 B 的修改先忽略不看(假設沒發生),現在資料庫停在 1-1-145
  • 在 A 恢復以後,設定 A 為 B 的 Slave,但是這個時候的 gtid_slave_pos 是空值,所以設成 current_pos (就是 1-1-145)。
  • 到 B 的 1-1-147 的時候,最新的就是 1-1-147,B 就知道怎麼恢復了 (145-147),正式加成 A 的 Slave。

這個的假設前提是在那個中斷時間內沒 B 沒有任何的 binlog 紀錄交易,這樣能確保 1-1-1451-1-147 都只有在有 Slave 的狀態下 Master 產生的交易,假設 B 中間原來忽略的的 2-2-138 被產生了,那麼 binlog 的順序就會在 1-1-1451-1-147 中間夾一個 2-2-138,奇怪的交易紀錄,會導致 A 的加入失敗。

所以官方建議在 Slave 上不要有任何的 binlog 紀錄 (Session 中 @@sql_log_bin=0),避免當這個 Slave 有機會變成 Master 或是再 Slave 到其他地方時有交易紀錄異常的問題。

如果還是要修改 Slave 的資料造成 binlog 會有變動,還是要把參數設為 slave_pos,確保 Slave 會從 Master 看的 binlog 資料不會因為 Slave 的變動而異常,不能像 current_pos 那樣兩邊都有可能取值,不管是什麼角色。

在 B 當 Slave 的時候如果沒有開 binlog,那麼 current_posslave_pos 是同一件事,當然後續的切換是不會發生的 (B 沒 binlog 不能當 Master)。

最後的設計

剛剛最後有說到在 Slave 沒有開 binlog 的方式,筆者原來是想要用這個的,因為這蠻像現在的維運模式。

  1. 當 Master 壞了就停掉 Slave 的 Service
  2. 等到 Master 好的時候停機備份到 Master 上
  3. 在 Slave 重新建 Replication

如果 Slave 有開 binlog,第2步的停機備份似乎可以把時間縮短

  1. 當 Master 壞了就停掉 Slave 的 Service
  2. 等到 Master 好的時候倒回 Slave 的備份
  3. 同步完成後重新建立 Master / Slave 順序

明天要介紹的是測試與實作碰到的問題。


上一篇
SQL Agent 與 MariaDB Event
下一篇
Log-shipping 與 MariaDB Replication [2]
系列文
MariaDB 的使用與管理30

尚未有邦友留言

立即登入留言