天天看點

MGR修改max_binlog_cache_size參數導緻異常

一、問題來源

這是一位朋友的問題,因為前期朋友設定max_binlog_cache_size為8m,後面線上進行了修改了本參數,但是結果導緻整個3節點的MGR叢集除了primary節點其他兩個second節點均掉線。大概的日志如下:

MGR修改max_binlog_cache_size參數導緻異常

二、使用binlog cache的大概流程

這也是我以前寫過的一個過程。

  • 開啟讀寫事務。
  • 執行‘DML’語句,在‘DML’語句第一次執行的時候會配置設定記憶體空間給binlog cache緩沖區。
  • 執行‘DML’語句期間生成的Event不斷寫入到binlog cache緩沖區。
  • 如果binlog cache緩沖區已經寫滿了,則将binlog cache緩沖區的資料寫入到binlog cache臨時檔案,同時清空binlog cache緩沖區,這個臨時檔案名以ML開頭。
  • 事務送出,binlog cache緩沖區和binlog cache臨時檔案資料全部寫入到binary log中進行固化,釋放binlog cache緩沖區和binlog cache臨時檔案。但是注意此時binlog cache緩沖區的記憶體空間留用供下次事務使用,但是binlog cache臨時檔案被截斷為0,保留檔案描述符。其實也就是IO_CACHE結構保留,并且保留IO_CACHE中配置設定的記憶體空間和臨時檔案檔案描述符。
  • 斷開連接配接,這個過程會釋放IO_CACHE同時釋放其持有的binlog cache緩沖區記憶體以及持有的binlog cache臨時檔案。

三、max_binlog_cache_size參數的作用

這部分也是我以前記錄過的。

max_binlog_cache_size:修改需要使用set global進行修改,定義了binlog cache臨時檔案的最大容量。如果某個事務的Event總量大于了(max_binlog_cache_size+binlog_cache_size)的大小那麼将會報錯,如下:

ERROR 1197 (HY000): Multi-statement transaction required more than
'max_binlog_cache_size' bytes of storage; increase this mysqld variable
and try again      

我們在函數_my_b_write可以看到如下代碼:

if (pos_in_file+info->buffer_length > info->end_of_file) //判斷binlog cache臨時檔案的位置加上本次需要寫盤的資料大于info->end_of_file的大小則抛錯
  {
    errno=EFBIG;
    set_my_errno(EFBIG);
    return info->error = -1;
  }      

其中info->end_of_file的大小正是來自于我們的參數max_binlog_cache_size。

四、分析問題

從second節點的報錯來看,是applier線程應用的事務超過了max_binlog_cache_size設定的大小,但是朋友已經修改了其大小,并且主庫并沒有報這個錯誤。

我們知道MGR applier線程從啟動MGR的那一刻開始就不會停止,類似的master-slave的sql線程也是一樣,我們修改參數是通過set global修改的參數,但是實際上在對于MGR的applier線程并不會生效。

但是對于主庫來講,我們修改參數後隻要重新開機應用重新連接配接那麼參數就生效了,這個時候實際上primary session的max_binlog_cache_size和second applier的max_binlog_cache_size并不一緻,一旦有主庫做一個稍大的事務,如果這個事務的binlog大于以前設定的值,主庫雖然能成功,但是備節點就會由于applier線程的max_binlog_cache_size過小而導緻備節點脫離整個叢集。

對于這一點我們可以通過debug MySQL的sql線程進行驗證。

五、驗證

這裡我們使用master-slave來進行驗證,我們對sql線程進行debug。如下,

  • 目前配置
MGR修改max_binlog_cache_size參數導緻異常
  • sql線程
    MGR修改max_binlog_cache_size參數導緻異常
  • 修改參數
    MGR修改max_binlog_cache_size參數導緻異常
  • 主庫執行一個事務,從庫執行

    我們可以檢視sql線程binlog cache的IO CACHE的資訊如下:

    MGR修改max_binlog_cache_size參數導緻異常

可以看到這個值還是老值。

  • 重新開機後sql線程後,主庫再做一個事務觀察
MGR修改max_binlog_cache_size參數導緻異常

很明顯我們剛才修改的值重新開機sql線程後才生效。

是以故障原因得到證明。

Enjoy MySQL :)

全文完。