rocketmq的HA主从同步源码解读一(HAService#start)

HA主从同步总览

master和slave之间主要同步两部分信息,元数据信息复制采用基于Netty定时同步。commitLog信息复制基于jdk nio实现;HA主从同步也即rocketmq的master将数据复制给slave,分为同步复制和异步复制;同步复制比异步复制多一个写线程阻塞等待;
HA主从同步的程序入口在CommitLog#handleHA方法中,该方法中会判断只有当前broker机器处于主从同步复制模式下时,才执行该方法,写线程阻塞在该方法中会超时阻塞,时间为5秒,时间到了,则报FLUSH_SLAVE_TIMEOUT,若是异步复制模式,则该方法啥也不做。这是同步与异步的唯一区别;
主从复制之同步复制模式逻辑和主从刷盘之同步刷盘非常像,分为三部分:
第一部分是写线程,即存储消息的线程,将消息存储到映射文件后,开始提交复制请求groupTransferService.putRequest(request);其中会将GroupCommitRequest实例提交至requestsWrite集合中,并且执行waitPoint.countDown()方法,唤醒阻塞在waitPoint上线程;接着写线程会执行service.getWaitNotifyObject().wakeupAll()和request.future().get,写线程会阻塞等待;
第二部分在messageStore.start方法中,会运行haService.start方法,其中又会运行groupTransferService.start方法,groupTransferService线程的run方法中调用了waitPoint.await(xxx)方法,带超时时间的阻塞,时间为10毫秒,时间到或被其他线程采用waitPoint.countDown方法时,才会被唤醒,唤醒后首先交换requestsRead和requestsWrite集合,接着执行this.doWaitTransfer()方法,该方法中先判断requestsRead集合,若为空,则啥也不做,否不为空,则会拿到其中每个GroupCommitRequest实例,取出其中的请求复制的偏移量和从机回传给主机的最大复制偏移量做比较,若前者大于后者,则表示,主机还有剩余数据没有复制给从机,若此时写线程未超时(没超过5秒),则groupTransferService线程会超时阻塞,时间为1秒,调用的是WaitNotifyObject实例的wait方法;当超时时间到了会自动醒来或被其他线程唤醒时,会醒来;
第三部分是在线程ReadSocketService的run方法中会调用processReadEvent#notifyTransferSome,其中又会调用notifyTransferObject.wakeup()方法将GroupTransferService线程唤醒,这个唤醒意思是主机读取了从机上报的复制偏移量,那么写线程提交的主从同步数据的请求已经完成了,现在赶紧回头告诉写线程,不要让它阻塞在那儿;所以为了唤醒写线程,则先要唤醒GroupTransferService线程,再在GroupTransferService线程中执行唤醒写线程的逻辑,GroupTransferService线程醒来后,首先比较请求复制的偏移量和从机回传给主机的最大复制偏移量(比如说写线程请求复制的偏移量为10,主机复制给从机的最大偏移量为6,此时主机需要将差值4复制给从机,最终请求的偏移量等于从机上传给主机的偏移量,即表示本次主从复制完成),然后存储结果至future中,写线程此时就会get到数据,会醒来;
其实这块和同步刷盘中的groupCommitService一模一样,也是构建GroupCommitRequest实例加入到reqeustsWrite集合中;不同的是同步刷盘中没有第三部分;
异步复制就不会走上边三部分逻辑;

1)HAService#start

HAService代表broker主机,HAClient代表broker从机;HAClient是HAService的内部类,是一个Runnalble;只有在从机上HAClient实例才可以正常运行;
在BrokerController#start中,会执行messageStore.start方法,其中会判断若没有开启DLedger,则执行haService.start方法,其中会执行四个方法,依次是this.acceptSocketService.beginAccept(),this.acceptSocketService.start(),this.groupTransferService.start(),this.haClient.start();其中前三个方法属于主机中运行的方法,最后一个属于从机中运行的方法,先研究this.haClient.start方法;找到run方法;run方法中分为以下几步:

1.1)AcceptSocketService#beginAccept

设置主机serverSocketChannel相关包括:
a)ServerSocketChannel.open方法获取一个jdk中nio的ServerSocketChannel实例;
b)获取一个jdk中nio的Selector实例,这里并没有设置serverSocketChannel接收缓冲区和发送缓冲区的大小;
c)绑定ssc的端口为10912;
d)设置ssc非阻塞;
e)最后将serverSocketChannel注册进AcceptSocketService所拥有的selector中,并且关注的accept事件;

1.2)AcceptSocketService#run

acceptSocketService线程会一直while循环,退出循环的条件是线程状态变为了stopped,所以即使readSocketService线程发现已经没有数据可读了而停止循环,但只要acceptSocketService线程不停下来,当再次有数据可读时,会触发读事件&

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

orcharddd_real

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值