半同步复制状态切换
一、简介
假设当前m-s处于半同步复制状态,这个状态在某些情况下可能会发生切换。
通过status而不是variables去查看当前复制状态
mysql> show global status like 'Rpl_semi_sync_master_status';
+-----------------------------+-------+
| Variable_name | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | ON |
+-----------------------------+-------+
1 row in set (0.00 sec)
如果是ON则为半同步状态,如果是OFF,则是异步复制状态。
二、状态切换
状态切换可能是半同步切换到异步,异步切换到半同步两种。
半同步切换异步状态
如简介中所述,如果当前运行在半同步复制状态,在如下情况下会发生切换
- 等待ack超时,被动切换
事务提交阶段需要等待slave返回的ack信息,并且通过rpl_semi_sync_master_wait_for_slave_count 设置ack slave的数量,通过rpl_semi_sync_master_timeout控制ack超时时间,当master无法在rpl_semi_sync_master_timeout时间内读取到ack信息时,则会触发半同步切换到异步的过程。这部分的代码见如下
if (wait_result != 0)
{
/* This is a real wait timeout. */
sql_print_warning("Timeout waiting for reply of binlog (file: %s, pos: %lu), "
"semi-sync up to file %s, position %lu.",
trx_wait_binlog_name, (unsigned long)trx_wait_binlog_pos,
reply_file_name_, (unsigned long)reply_file_pos_);
rpl_semi_sync_master_wait_timeouts++;
/* switch semi-sync off */
switch_off();
}
int ReplSemiSyncMaster::switch_off()
{
const char *kWho = "ReplSemiSyncMaster::switch_off";
function_enter(kWho);
state_ = false;
rpl_semi_sync_master_off_times++;
wait_file_name_inited_ = false;
reply_file_name_inited_ = false;
sql_print_information("Semi-sync replication switched OFF.");
/* signal waiting sessions */
active_tranxs_->signal_waiting_sessions_all();
return function_exit(kWho, 0);
}
- 通过设置参数,主动切换
通过设置变量rpl_semi_sync_master_enabled可以手动控制状态切换
在简介中,假设当前M-S运行在半同步复制状态,可以通过如下设置进行切换
mysql> set global rpl_semi_sync_master_enabled=off;
Query OK, 0 rows affected (0.02 sec)
代码控制在
参数设置的接口
static MYSQL_SYSVAR_BOOL(enabled, rpl_semi_sync_master_enabled,
PLUGIN_VAR_OPCMDARG,
"Enable semi-synchronous replication master (disabled by default). ",
NULL, // check
&fix_rpl_semi_sync_master_enabled, // update
0);
修改半同步复制状态
static void fix_rpl_semi_sync_master_enabled(MYSQL_THD thd,
SYS_VAR *var,
void *ptr,
const void *val)
{
*(char *)ptr= *(char *)val;
if (rpl_semi_sync_master_enabled)
{
if (repl_semisync.enableMaster() != 0)
rpl_semi_sync_master_enabled = false;
else if (ack_receiver.start())
{
repl_semisync.disableMaster();
rpl_semi_sync_master_enabled = false;
}
}
else
{
if (repl_semisync.disableMaster() != 0)
rpl_semi_sync_master_enabled = true;
ack_receiver.stop();
}
return;
}
从on->off
int ReplSemiSyncMaster::disableMaster()
{
/* Must have the lock when we do enable of disable. */
lock();
if (getMasterEnabled())
{
/* Switch off the semi-sync first so that waiting transaction will be
* waken up.
*/
switch_off();
if ( active_tranxs_ && active_tranxs_->is_empty())
{
delete active_tranxs_;
active_tranxs_ = NULL;
}
reply_file_name_inited_ = false;
wait_file_name_inited_ = false;
commit_file_name_inited_ = false;
ack_container_.clear();
set_master_enabled(false);
sql_print_information("Semi-sync replication disabled on the master.");
}
unlock();
return 0;
}
异步切换到半同步
如果初始状态为半同步,由于其他原因,被迫切换到异步复制,那么在某些条件下,可以自动从异步状态切换到半同步状态。
- master-slave网络恢复,master可以正常的接受ack信息。
void ReplSemiSyncMaster::reportReplyBinlog(const char *log_file_name,
my_off_t log_file_pos)
{
const char *kWho = "ReplSemiSyncMaster::reportReplyBinlog";
int cmp;
bool can_release_threads = false;
bool need_copy_send_pos = true;
function_enter(kWho);
mysql_mutex_assert_owner(&LOCK_binlog_);
if (!getMasterEnabled())
goto l_end;
if (!is_on())
/* We check to see whether we can switch semi-sync ON. */
try_switch_on(log_file_name, log_file_pos);
从代码中可以看出,如果参数rpl_semi_sync_master_enabled设置为on,并且当前状态不为on,则会尝试进行切换到半同步。
- 如果m-s一开始就运行在异步环境,则可以通过参数设置切换到半同步状态
mysql> set global rpl_semi_sync_master_enabled=on;
Query OK, 0 rows affected (0.01 sec)
这个就没什么好说的了,常规操作。