MySQL中的冪等複製分析

aoerqileng發表於2023-02-13

之前遇到複製異常,如果確定沒有問題,都是跳過異常事務,最近看到了一個新的複製模式:冪等複製

--slave-exec-mode=mode
這個引數預設是strict模式,可以設定成IDEMPOTENT,進入冪等複製模式



官方檔案中描述,這種模式能抑制duplicate-key and no-key-found errors;


下面看下程式碼中的實現,首先是定義了冪等模式的錯誤碼,對普通的錯誤碼,進行了轉義

inline int idempotent_error_code(int err_code)
{
int ret= 0;
switch (err_code)
{
case 0:
ret= 1;
break;
    /*
      The following list of "idempotent" errors
      means that an error from the list might happen
      because of idempotent (more than once)
      applying of a binlog file.
      Notice, that binlog has a  ddl operation its
      second applying may cause
      case HA_ERR_TABLE_DEF_CHANGED:
      case HA_ERR_CANNOT_ADD_FOREIGN:
      which are not included into to the list.
      Note that HA_ERR_RECORD_DELETED is not in the list since
      do_exec_row() should not return that error code.
    */
case HA_ERR_RECORD_CHANGED:
case HA_ERR_KEY_NOT_FOUND:
case HA_ERR_END_OF_FILE:
case HA_ERR_FOUND_DUPP_KEY:
case HA_ERR_FOUND_DUPP_UNIQUE:
case HA_ERR_FOREIGN_DUPLICATE_KEY:
case HA_ERR_NO_REFERENCED_ROW:
case HA_ERR_ROW_IS_REFERENCED:
ret= 1;
break;
default:
ret= 0;
break;
}
return (ret);
}



處理冪等錯誤的函式,如果轉義後的錯誤碼是冪等的錯誤,那麼級別就是warning,並且清理worker中的錯誤

int Rows_log_event::handle_idempotent_and_ignored_errors(Relay_log_info const *rli, int *err)
{
int error= *err;
if (error)
{
int actual_error= convert_handler_error(error, thd, m_table);
bool idempotent_error= (idempotent_error_code(error) &&
(rbr_exec_mode == RBR_EXEC_MODE_IDEMPOTENT));
bool ignored_error= (idempotent_error == 0 ?
ignored_error_code(actual_error) : 0);
if (idempotent_error || ignored_error)
{
loglevel ll;
if (idempotent_error)
ll= WARNING_LEVEL;
else
ll= INFORMATION_LEVEL;
slave_rows_error_report(ll, error, rli, thd, m_table,
get_type_str(),
const_cast<Relay_log_info*>(rli)->get_rpl_log_name(),
(ulong) common_header->log_pos);
thd->get_stmt_da()->reset_condition_info(thd);
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
*err= 0;
if (idempotent_error == 0)
return ignored_error;
}
}
return *err;
}


在從庫的

Rows_log_event::do_scan_and_update(Relay_log_info const *rli)

執行中,查詢到記錄,應用的時候,報錯,就呼叫冪等錯誤碼處理函式,進行處理

if ((error= do_apply_row(rli)))
{
if (handle_idempotent_and_ignored_errors(rli, &error))
goto close_table;
do_post_row_operations(rli, error);
}
在找不到記錄的時候也進行處理
case HA_ERR_KEY_NOT_FOUND:
        /* If the slave exec mode is idempotent or the error is
            skipped error, then don't break */
if (handle_idempotent_and_ignored_errors(rli, &error))
goto close_table;
idempotent_errors++;
continue;



我們看到在處理錯誤的時候,只是進行了錯誤日誌級別的調整,和清除錯誤資訊,沒有其他操作,在找到記錄後,處理了錯誤,然後又進行了後續的處理do_post_row_operations,這個函式中就是設定了變數m_curr_row,針對主鍵衝突的問題,是用master的值更新了衝突的行,這個是在哪裡進行的?


在寫入資料的時候,會傳遞一個引數,指定是否要覆蓋

int
Write_rows_log_event::do_exec_row(const Relay_log_info *const rli)
{
DBUG_ASSERT(m_table != NULL);
int error= write_row(rli, rbr_exec_mode == RBR_EXEC_MODE_IDEMPOTENT);
if (error && !thd->is_error())
{
DBUG_ASSERT(0);
my_error(ER_UNKNOWN_ERROR, MYF(0));
}
return error;
}
設定了這個引數,rbr_exec_mode == RBR_EXEC_MODE_IDEMPOTENT,覆蓋的引數會設定成true,這樣重複的主鍵,
會被覆蓋



冪等的設定,沒有完全收斂到一個入口,還是有些分散

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

相關文章