MySQL Slave同一server_id的冲突原因分析

互联网十八般武艺 互联网十八般武艺

今天分析一个诡异问题,一个模拟Slave线程的程序,不断的被Master Server给kill掉,最终发现是因为有两个Slave使用同样一个server id去连接Master Server,为什么两个Slave用同一个server id会被Master Server给Kill呢?分析了源码,这源于MySQL Replication的重连机制.

我们首先看看一个Slave注册到Master会发生什么,首先Slave需要向Master发送一个COM_REGISTER_SLAVE类型的请求(sql_parse.cc)命令请求,这里Master会使用register_slave函数注册一个Slave到slave_list,代码如下:

  1. caseCOM_REGISTER_SLAVE:
  2. {
  3. if(!register_slave(thd,(uchar*)packet,packet_length))
  4. my_ok(thd);
  5. break;
  6. }

在注册Slave线程的时候会发生什么呢?我们略去无用的代码直接看重点,repl_failsafe.cc代码如下:

  1. intregister_slave(THD*thd,uchar*packet,uintpacket_length)
  2. {
  3. intres;
  4. SLAVE_INFO*si;
  5. uchar*p=packet,*p_end=packet+packet_length;
  6. ....//省略
  7. if(!(si->master_id=uint4korr(p)))
  8. si->master_id=server_id;
  9. si->thd=thd;
  10. pthread_mutex_lock(&LOCK_slave_list);
  11. unregister_slave(thd,0,0);//关键在这里,先取消注册server_id相同的Slave线程
  12. res=my_hash_insert(&slave_list,(uchar*)si);//把新的Slave线程注册到slave_list//phpfensi.com
  13. pthread_mutex_unlock(&LOCK_slave_list);
  14. returnres;
  15. .....
  16. }

这是什么意思呢?这就是重连机制,slave_list是一个Hash表,server_id是Key,每一个线程注册上来,需要删掉同样server_id的Slave线程,再把新的Slave线程加到slave_list表中.

线程注册上来后,请求Binlog,发送COM_BINLOG_DUMP请求,Master会发送binlog给Slave,代码如下:

  1. caseCOM_BINLOG_DUMP:
  2. {
  3. ulongpos;
  4. ushortflags;
  5. uint32slave_server_id;
  6. status_var_increment(thd->status_var.com_other);
  7. thd->enable_slow_log=opt_log_slow_admin_statements;
  8. if(check_global_access(thd,REPL_SLAVE_ACL))
  9. break;
  10. /*TODO:Thefollowinghastobechangedtoan8byteinteger*/
  11. pos=uint4korr(packet);
  12. flags=uint2korr(packet+4);
  13. thd->server_id=0;/*avoidsuicide*/
  14. if((slave_server_id=uint4korr(packet+6)))//mysqlbinlog.server_id==0
  15. kill_zombie_dump_threads(slave_server_id);
  16. thd->server_id=slave_server_id;
  17. general_log_print(thd,command,"Log:'%s'Pos:%ld",packet+10,
  18. (long)pos);
  19. mysql_binlog_send(thd,thd->strdup(packet+10),(my_off_t)pos,flags);//不断的发送日志给slave端
  20. unregister_slave(thd,1,1);//发送完成后清理Slave线程,因为执行到这一步肯定是binlogdump线程被kill了
  21. /*fakeCOM_QUIT--ifwegethere,thethreadneedstoterminate*/
  22. error=TRUE;
  23. break;
  24. }

mysql_binlog_send函数在sql_repl.cc,里面是轮询Master binlog,发送给Slave,再来简单看看unregister_slave做了什么,repl_failsafe.cc,代码如下:

  1. voidunregister_slave(THD*thd,boolonly_mine,boolneed_mutex)
  2. {
  3. if(thd->server_id)
  4. {
  5. if(need_mutex)
  6. pthread_mutex_lock(&LOCK_slave_list);
  7. SLAVE_INFO*old_si;
  8. if((old_si=(SLAVE_INFO*)hash_search(&slave_list,
  9. (uchar*)&thd->server_id,4))&&
  10. (!only_mine||old_si->thd==thd))//拿到slave值
  11. hash_delete(&slave_list,(uchar*)old_si);//从slave_list中拿掉
  12. if(need_mutex)
  13. pthread_mutex_unlock(&LOCK_slave_list);
  14. }
  15. }

这就可以解释同样的server_id为什么会被kill,因为一旦注册上去,就会现删除相同server_id的Slave线程,然后把当前的Slave加入,这是因为有时Slave断开了,重新请求上来,当然需要踢掉原来的线程,这就是线程重连机制.

相关广告
  • MySQL Slave同一server_id的冲突原因分析 MySQL Slave同一server_id的冲突原因分析 MySQL Slave同一server_id的冲突原因分析
相关阅读

MySQL Slave同一server_id的冲突原因分析

2019/10/10 17:32:56 | 谷歌SEO算法 | Dropbox