MySQL半同步复制的原理与问题
MySQL的半同步复制,异步复制的区别在MySQL异步复制情况的建筑,MySQL主服务器将通过复制线程传输自己的二进制日志,MySQL主服务器会自动将数据返回到客户端,无论是否接受奴隶的二进制日志,半同步复制的体系结构下,当主机发送自己的binlog奴隶,有必要确保奴隶接受了二进制日志,然后返回数据到客户端。两种体系结构的比较:用户异步复制,可以保证结构的快速反应,但不能保证二进制日志确实在奴隶;半同步R对客户要求的响应eplication稍微慢点,但是他可以保证二进制日志的完整性。1。问题的背景
默认情况下,在线MySQL复制是异步复制,因此,在极端的情况下,主备切换,将有机会做库比卡主库数据,所以切换后,我们将重新回到通过工具,保证数据不丢失。半同步复制要求主库执行每一个交易,这需要至少一个备库成功接收之前,它实际上是执行,使主图书馆的强一致性可以保持。为了保证主库数据的一致性和减少数据,半同步(半同步)的MySQL的复制功能在生产环境中尝试。实际操作中,发现大多数情况下都能正常运行,但只有少数实例不能打开(仅在普通复制中)。同一主机的两个实例更精彩。一个可以打开,一个不能打开,最终定位的问题很简单,但需要付出很大的努力,下面将描述整个问题的过程。
2。半同步复制原理
MySQL主库是一致通过binlog日志。主库执行交易的局部,和binlog日志磁盘后下降返回给用户。备份库同步的主要图书馆运行的拉动主库binlog日志。默认情况下,有主库和知识库之间没有严格的同步,所以有一定的概率,数据库不等于主库数据,半同步的出现是保证数据的一致性在任何时间。而异步复制,每个需要半同步复制执行的交易至少需要一个图书馆被成功接收后返回到用户,实现原理也很简单。在主要的图书馆是在本地执行,响应消息等待库(包括binlog(文件,POS)的新图书馆收到)是接收备份库的响应消息后返回给用户,因此,这样的交易才能真正完成。在主库实例,一个特殊的线程(ack_receiver)接收备用库的响应消息,和主图书馆接收日志的通知机制的通知,可以继续执行。对于半同步的具体实现,可以参考另一篇文章中,MySQL半同步(半同步)源的实现。
3分析。问题
半同步复制的原则首先简要介绍,现在看到的具体问题。在半同步开关在主库打开,状态变量rpl_semi_sync_master_status 的问题始终是关闭的,说明复制已在普通复制的运行状态。
(1)。rpl_semi_sync_master_timeout参数修改。
半同步复制具有rpl_semi_sync_master_timeout参数,用于控制制备库响应消息的主要基地,如果超过这个值,那是图书馆准备尚未收到(制可能会挂起,也可以制备库执行的很慢,主要是图书馆远)这个时候,复制将切换到普通副本避免长时间等待数据库事务。这是50毫秒线的默认值,而不是简单的这个值太小,则改为10s,但问题仍然困惑。
(2)。打印日志
检查问题的最简单和最笨的办法就是登录并看到哪个环节出了问题,将是一个问题。主图书馆和图书馆分别有rpl_semi_sync_master_trace_level和rpl_semi_sync_slave_trace_level参数来控制打印日志,半同步复制,设置两个参数值80(64 + 16),记录详细的日志信息,以及函数调用的进入和出去。
大师:
2016-01-04 18:00:30 13212 {注} replsemisyncmaster::updatesyncheader:服务器(1721062019)、(mysql-bin.000006,500717950)同步(1),回答(1)。
2016-01-04 18:00:40 13212 {警告}超时等待回复的binlog(文件:mysql-bin.000006,名次:500717950)。
2016-01-04 18:00:40 13212 {注}半同步复制关闭。
Slave:
2016-01-04 18:00:30 {注}我replsemisyncslave:进入slavereply:38932
2016-01-04 18:00:30 38932 {注} replsemisyncslave::slavereply:回复(mysql-bin.000006,500717950)
2016-01-04 18:00:30 {注} replsemisyncslave:slavereply退出:虽然38932(0)
从主日志中可以看到2016-01-04 18:00:30,主要的图书馆建立半同步标记,并开始准备库等待响应,等待10s,仍然没有得到回复,那么超时,半同步开关模式正常模式。但从日志的2016-01-04 18:00:30已发送到主图书馆(mysql-bin.000006,500717950)表明,日志已收到。这意味着主日志已经打了半同步标记,从收到的日志,并返回包,大师也有等待10s,没有收到数据包,因此开关对普通的重复。现在的问题是,为什么主人没有收到它
(3)选择函数
如前所述,主图书馆实例有一个特殊的线程接收响应数据包(ack_receiver)。它通过选择函数监听套接字,并找到从响应消息,然后读取消息,通知工人线程可以继续执行。因为选择是一个系统调用,它从未被怀疑过,但它来了,你一定要看。有几个重要的宏定义和选择功能的相关说明。它主要是实现在三文件 / usr / / /位包括typesizes。H, / usr / / /位包括选择。H,和 / usr / / /选择系统包括H.
fd_zero(fd_set * FDSET):清除所有的文件handles.fd_set FDSET之间的连接(int fd,fd_set * FDSET):建立文件句柄fd和fdset.fd_clr之间的连接(int fd,fd_set * FDSET):清除文件句柄fd和fdset.fd_isset之间的连接(int fd,fd_set * FDSET):检查是否连接的FDSET文件句柄FD是可读写的,当>0表示可读写。
阵列
{
__fd_mask __fds_bits { __fd_setsize / __nfdbits } 1024 / 64 = 16(长整型);
} fd_set
#定义__fd_set_size 1024
typedef long int __fd_mask; / / 8字节
#定义__nfdbits(8 * sizeof(int)(__fd_mask)) / / 64
#定义__fdmask(D)(1 __fd_mask)<<(D)% __nfdbits)) / / FD % 64 = N,然后在N位设置为1。
#定义__fdelt(D)((D) / / __nfdbits长)在int表示
#定义__fds_bits(套)((设置)-> __fds_bits)
#定义__fd_set(D组)(__fds_bits(套){ __fdelt(D)} | = __fdmask(D))
#定义__fd_clr(D组)(__fds_bits(套){ __fdelt(D)} = ~ __fdmask(D))
#定义__fd_isset(D组)
((__fds_bits(套){ __fdelt(D)} __fdmask(D))!= 0)
通过fd_set,我们可以设置要监测的处理。把信息存储在fd_set数字组。数组元素的个数是由__fd_setsize / 64确定。对于__fd_setsize = 1024,有在整个阵列只有16长整型。每个处理占有一个点,这是1024位,可同时存储1024把手。假设句柄的值是138,那么138 / 64 = 2138% 64 = 10,那么这个句柄标记在第二长整型1第十位的数组。如果句柄值超过1024,它不溢出来吗我仔细地编写了代码,发现没有错误判断,如果句柄值大于1024会溢出,因为选择函数遍历数组中的每一位,然后确定句柄是否可读或可写,它永远不会被判断为超过1024个句柄。因此,主库将永远不知道库是否发送了响应包。
(4)核查
以上只是理论分析,如果实际操作的情况下句柄大于1024,则问题所在。
1。获取mysql进程
ps aux grep mysqld grep端口| |
2.gdb附加到该进程
分布式控制系统
三.找到ack_receive线和开关
信息线
螺纹thread_id
4。打印套接字值,其中FD值为2344。
(5)如何解决
我们看到,__fd_setsize的定义通常是1024,结果在选择功能只能听1024处理最多和最大的句柄值不超过1024。第一种方法是增加参数,但是这种方法需要重新编译Linux内核。此外,由于选择机制每一次我们需要遍历每个点来判断是否有一个消息来处理,如果是建立非常大,它会导致效率非常低。选择是一个古老的IO复用机制。先进的poll和epoll具有相似的功能,功能更强大,并没有限制在处理总数和最大的处理,选择,投票,epoll等机制,你可以在网上查的信息。这里没有讨论。
(6)正式版本
看着新的Git的Oracle版本正式版,5.7的源代码,这也是实现选择,所以有一个类似的问题。当然,因为句柄数具有复用机制,当连接数或连接不长,出现FD > 1024是不容易,所以这个错误是不是显得很容易,但问题是普遍存在的。
(7)问题延伸
之后的问题所在,另一个问题已经困扰了我半天。因为有3件在MySQL内核的听力,1是选择在监听端口,2是线程池监控epoll,和3是一种半同步选择监视器。奴隶binlog转储线程常见的工作线程和工作线程,套接字将由epoll,使binlog转储插座将受到半同步选择监测和epoll同时线程池的监测。它不凌乱吗后来,经过认真地看代码,我们发现epoll监控线程池的使用epolloneshot模式。收到消息后,它将解开并绑定它,需要重新注册,这样就不会同时监视两个监视机制的同一句柄。
在这一点上,调度问题的过程已经结束,结论很简单,但确实需要一些努力来定位问题。因为选择是一种更常见的多路IO多路复用机制,所以对选择函数有用的童鞋可能要注意它的局限性。