转载请署名:印风
————————————————–
备库因为某些错误停止时有发生,最常见的错误就是”HA_ERR_KEY_NOT_FOUND”和 “HA_ERR_FOUND_DUPP_KEY”.这既有可能是主备切换导致的,也可能是MySQL Bug导致的
通常有两种办法来处理备库错误:
1). 设置 “sql_slave_skip_counter”来忽略错误.
2).set slave_exec_mode = “idempotent”来处理 “HA_ERR_FOUND_DUPP_KEY” (overwritten the record) 和”HA_ERR_KEY_NOT_FOUND”(简单的忽略掉错误).
这两种方法都可能导致主备不一致
如果你使用的是innodb存储引擎,并且使用的是ROW模式复制,那我们就可以fix这个Bug。
很久之前我写了一个工具(http://code.google.com/p/relay-fetch/,下面的slave_error_handler文件夹)可以用来处理这个问题。
以下的patch则通过修改代码,为slave_exec_mode增加新的选项SMART,来自动处理。
思想很简单
1) HA_ERR_KEY_NOT_FOUND
UPDATE_ROWS_EVENT: 先写记录的’Before Image’ ,然后再update
DELETE_ROWS_EVENT: 先写后删 , 或者直接忽略错误
2)HA_ERR_FOUND_DUPP_KEY
WRITE_ROWS_EVENT: overwrite the record
对UPDATE_ROWS_EVENT导致的重复键错误暂不做处理。
以下patch基于Percona Server 5.5.18:
Index: /PS5518/branches/PS-r1086-slave-auto-fix/sql/log_event.cc
===================================================================
— /PS5518/branches/PS-r1086-slave-auto-fix/sql/log_event.cc (revision 1136)
+++ /PS5518/branches/PS-r1086-slave-auto-fix/sql/log_event.cc (revision 1180)
@@ -8750,6 +8750,7 @@
applying the event in the replace (idempotent) fashion.
*/
if ((slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT) ||
+ (slave_exec_mode == SLAVE_EXEC_MODE_SMART) ||
(m_table->s->db_type()->db_type == DB_TYPE_NDBCLUSTER))
{
/*
@@ -8829,6 +8830,7 @@
m_table->next_number_field=0;
m_table->auto_increment_field_not_null= FALSE;
if ((slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT) ||
+ (slave_exec_mode == SLAVE_EXEC_MODE_SMART) ||
m_table->s->db_type()->db_type == DB_TYPE_NDBCLUSTER)
{
m_table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
@@ -9124,7 +9126,9 @@
Write_rows_log_event::do_exec_row(const Relay_log_info *const rli)
{
DBUG_ASSERT(m_table != NULL);
– int error= write_row(rli, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT);
+
+ int error= write_row(rli, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT ||
+ slave_exec_mode == SLAVE_EXEC_MODE_SMART);
if (error && !thd->is_error())
{
@@ -9662,7 +9666,19 @@
Delete the record found, located in record[0]
*/
error= m_table->file->ha_delete_row(m_table->record[0]);
+ } else if ( (slave_exec_mode == SLAVE_EXEC_MODE_SMART) &&
+ (error == HA_ERR_KEY_NOT_FOUND)) {
+ tmp_disable_binlog(rli->sql_thd);
+ error = m_table->file->ha_write_row(m_table->record[0]) ||
+ m_table->file->rnd_pos_by_record(m_table->record[0]);
+
+ reenable_binlog(rli->sql_thd);
+ if (!error)
+ error = m_table->file->ha_delete_row(m_table->record[0]);
+ else
+ error = HA_ERR_KEY_NOT_FOUND;
}
+
return error;
}
@@ -9782,6 +9798,17 @@
int error= find_row(rli);
if (error)
{
+ if ((slave_exec_mode == SLAVE_EXEC_MODE_SMART) &&
+ (error == HA_ERR_KEY_NOT_FOUND)) {
+ tmp_disable_binlog(rli->sql_thd);
+ error = m_table->file->ha_write_row(m_table->record[0]) ||
+ m_table->file->rnd_pos_by_record(m_table->record[0]);
+ reenable_binlog(rli->sql_thd);
+ if (error)
+ error = HA_ERR_KEY_NOT_FOUND;
+ }
+
+ if (error) {
/*
We need to read the second image in the event of error to be
able to skip to the next pair of updates
@@ -9789,6 +9816,7 @@
m_curr_row= m_curr_row_end;
unpack_current_row(rli);
return error;
+ }
}
/*
Index: /PS5518/branches/PS-r1086-slave-auto-fix/sql/sql_class.h
===================================================================
— /PS5518/branches/PS-r1086-slave-auto-fix/sql/sql_class.h (revision 1136)
+++ /PS5518/branches/PS-r1086-slave-auto-fix/sql/sql_class.h (revision 1180)
@@ -90,6 +90,7 @@
enum enum_log_warnings_suppress { log_warnings_suppress_1592 };
enum enum_slave_exec_mode { SLAVE_EXEC_MODE_STRICT,
SLAVE_EXEC_MODE_IDEMPOTENT,
+ SLAVE_EXEC_MODE_SMART,
SLAVE_EXEC_MODE_LAST_BIT};
enum enum_slave_type_conversions { SLAVE_TYPE_CONVERSIONS_ALL_LOSSY,
SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY};
Index: /PS5518/branches/PS-r1086-slave-auto-fix/sql/sys_vars.cc
===================================================================
— /PS5518/branches/PS-r1086-slave-auto-fix/sql/sys_vars.cc (revision 1136)
+++ /PS5518/branches/PS-r1086-slave-auto-fix/sql/sys_vars.cc (revision 1180)
@@ -1962,7 +1962,7 @@
DEFAULT(FALSE));
#ifdef HAVE_REPLICATION
-static const char *slave_exec_mode_names[]= {“STRICT”, “IDEMPOTENT”, 0};
+static const char *slave_exec_mode_names[]= {“STRICT”, “IDEMPOTENT”, “SMART”,0};
static Sys_var_enum Slave_exec_mode(
“slave_exec_mode”,
“Modes for how replication events should be executed. Legal values ”