A-A+

解决多实例server_id相同问题的方法及原理

2015年08月06日 DB 解决多实例server_id相同问题的方法及原理已关闭评论

GCS上架MySQL,使用的server_id是根据机器ip生成的(10位整数,小于2^32 -1),同机器多实例的server_id是相同的。

这样就存在一个问题,同一机器的多个实例作为同一DB的slave时,会出错:

[Note] Slave: received end packet from server, apparent master shutdown:

[Note]  Slave I/O thread: Failed reading log event, reconnecting to retry, log ......

 

关于mysql多个slave使用同一个server_id产生的问题及原因可以参考这里:

http://hatemysql.com/?p=115

http://www.penglixun.com/tech/database/mysql_multi_slave_same_serverid.html

重点分析下GCS是如何解决这个问题的:

MySQL多实例在GCS中是很常见的,同IP多实例做为同一DB的slave的情况也有可能发生,所以现在要解决的是,怎么在即满足server_id最大 2^32-1的条件,又能保证同IP多实例的server_id不冲突?

GCS是根据port来区分不同MySQL实例的,IP+PORT就能保证实例的唯一性了。

坊间流传的ip2int已经不够用了(转化出来的int大2^32-1,10倍整数),没有PORT使用的数位了。

分析ip2int发现,原理实际上是将ip(255.255.255.255)分为4段,每段转为2进制后,拼接(或者说 移位)后再转化为int的:

大致代码如下:


sub ip2int{
    my $ip=shift;
    my @ipAttr = split(/\./, $ip);
    $ip_int = &tobinary($ipAttr[0]) . &tobinary($ipAttr[1]) . &tobinary($ipAttr[2]) . &tobinary($ipAttr[3]);
         
    return b2oct($ip_int);  
}

sub b2oct{
    my $input = shift;
    return oct('0b'.$input);
}

sub tobinary{
     my $input = shift;
     my $Str = sprintf("%08b",$input);    
     return $Str;
}

现在的要解决的是为PORT挤出空位来(假设GCS单机实例不超过64个)。

从IP网段下手,内网IP分为3个网段,分别是:

  • A类地址:10.0.0.0--10.255.255.255
  • B类地址:172.16.0.0--172.31.255.255
  • C类地址:192.168.0.0--192.168.255.255

发现IP第一段只有3种情况,却占有8位2进制。拆分第一个IP段占有的8位2进制,用2位来表示IP的3种情况,剩下6位表示64个实例标识。

代码如下:

注:因为GCS的MySQL实例端口多数从20000开始(或3306单实例),最多64个实例,故取模10000,再次取模64(同时可模掉3306>64的情况)。

use utf8;

sub getServerIdByIpAndPort{
my $ip = shift;
my $port = shift;

my $server_id = qq//;
my $first = qq//;
my @ipAttr = split(/\./, $ip);

if($ipAttr[0] eq qq/172/){
$first = qq/1/;
}elsif($ipAttr[0] eq qq/10/){
$first = qq/2/;
}elsif($ipAttr[0] eq qq/192/){
$first = qq/3/;
}else{
$first = qq/

原创文章,转载请注明: 转载自腾讯游戏DBA团队

本文链接地址: 解决多实例server_id相同问题的方法及原理

文章的脚注信息由WordPress的wp-posturl插件自动生成

评论已关闭!

Copyright © 腾讯游戏DBA团队 保留所有权利.  

用户登录

分享到: