qunaer面试题之一


http://www.itpub.net/thread-1726615-1-1.html

server-id做什么用的,你知道吗?

两种情况,

第一种情况:两个slave有同样的server-id会有什么问题?

第二种情况:如果是级联复制,再级联复制的路径上有相同的server-id会有什么问题。


serverid的作用

1、 mysql的同步的数据中是包含server-id的,用于标识该语句最初是从哪个server写入的,所以server-id一定要有的

2、 每一个同步中的slave在master上都对应一个master线程,该线程就是通过slave的server-id来标识的;每个slave在master端最多有一个master线程,如果两个slave的server-id 相同,则后一个连接成功时,前一个将被踢掉。 这里至少有这么一种考虑:

     slave主动连接master之后,如果slave上面执行了slave stop;则连接断开,但是master上对应的线程并没有退出;当slave start之后,master不能再创建一个线程而保留原来的线程,那样同步就可能有问题;

3、 在mysql做主主同步时,多个主需要构成一个环状,但是同步的时候有要保证一条数据不会陷入死循环,这里就是靠server-id来实现的


在第一个场景下,你会发现两个slave在不断的重连master,日志里面也会有错误信息,说slave被断掉,尝试重连,并且也连上去了。然后又被断掉,又重连…循环往复。

第二个场景,最后一个slave不能得到master的变更,在master上做的任何操作都不会应用到最后一个slave上。



MySQL复制的原理这边就不详细描述。简单的说,就是如果开启了log-bin记录二进制日志,master会在自己的binlog中记录下变更发生的时间,query(如果是Row的话会转成具体的行变更),server-id等信息,然后当slave请求(请求的信息中包括连接master的ip,port等连接信息;以及需要从master的那个二进制文件的哪个位置开始,获得之后的所有master变更)发送到master之后,master启动一个binlog dump的线程用于发送变更信息给该slave。slave通过IO thread接受消息,记录到自己的relay log中,(如果发现server-id等于自己的,它就认为是在本地产生的,直接丢弃),然后SQL thread读取relay log应用到本地MySQL。我们理解了这个,其实上面的两个问题就能够迎刃而解了。

第二个问题更加直观,master和第三个slave的server-id是一样的,所以第三个slave发现master产生的binlog,误以为是它自己产生的,就会丢弃掉。这样的话,master产生的binlog在第三个slave就无法应用。

第一个问题比较复杂一点,牵涉到master怎么处理server-id相同的slave请求。这里冲突的焦点就是,master怎么区分各个slave的不同之处。在MySQL中,就是用server id来区分的。比如:左边的slave首先连上master,master会分配binlog dump线程并于该slave通讯,发送变更信息;这时,右边的slave连上来,server-id也是2,master以server-id来区别slave,所以它认为是同一个slave连过来,请求另外一个binlog和对应position处开始的数据,于是按照正常逻辑它清理了左边slave的binlog dump线程,并给右边的分配binlog dump线程。左边的slave发现复制断掉以后会自动重连,所以右边的又悲剧了…循环往复,两个slave一直这样相互冲突


server-id是用4个字节的unsigned int来保存的,值的范围:0 .. 4294967295。有将近43亿的server-id可以用。足够我们使用了。

要保证唯一的话,手工分配是完全不靠谱的,自动分配的话,我们提供两种方法以供参考:

1、使用一个集中式的自增的公共服务。可以用oracle的sequece,mysql的自增值等。优点是比较简单,缺点就是需要一个额外的服务

2、使用IP+PORT来算出一个server-id,一个IP和PORT可以唯一定位一个MySQL实例,所以各个MySQL server-id不会有冲突。IP和PORT怎么跟server-id对应列。由于IP本身对应的就是一个4个字节,(比如:INET_ATON('209.207.224.40')=209×2563 + 207×2562 + 224×256 + 40=3520061480),加上端口两个字节,所以做不到完全的一一对应的关系。但是IP地址中有很多保留的的地址(比如:127.0.0.0到127.255.255.255是保留地址),另外由于一个IP对应的实例毕竟有限(你不可能在一个IP上启动65535个MySQL实例吧?),所以针对你自己的业务场景做一套适应的IP,PORT对应server-id的算式也是一个解决办法。比如:如果你高位两个字节都相同,就可以把端口的两个字节和IP后两个字节拼接成一个4字节的无符号整数作为server-id。