Broker是RocketMQ的核心组件,完成接受Producer生产的消息、处理Consumer的消费消息的请求、消息的持久化、以及HA等等。

  • 消息的存储和发送

    作为一个优秀的分布式队列,需要达到实时性、高吞吐量、高可用的要求。为了满足高可用性,通常的做法就是将消息进行持久化,入磁盘,RocketMQ也是如此。同时,磁盘的读取速度需要与网络传速速度匹配才能提高消息队列的性能,举个例子,读取本地的消息内容并通过网络发送需要经过两个步骤:1)read(file,tmp_buf,len);// tmp_buf是预先申请的内存用来读取本地内容 。 2)write(socket,tmp_buf,len);//通过Socket将tmp_buf进行发送。看似简单的两个操作实际上发生了4次数据复制(从磁盘到内核态,从内核态到用户态,从用户态到网络驱动的内核态,从网络驱动的内核态到网卡,最后进行传输),RockerMQ为提高消息发送的效率,使用堆外内存,也就是“零拷贝”,省去了从内核态到用户态的过程。

  • 消息的存储结构

    需要特别指出的是,ConsumerQueue中存储的不是消息本身,而是一个指向物理存储的地址,类似于DB的索引文件,这个物理存储的位置就是CommitLog。commitLog会存储ConsumerQueue、Key、Tag等信息,即使ConsumerQueue丢失也可以通过commitLog进行恢复。若存消息本身,由于多个Broker都可能会存相同的消息作为相互的备份,那么就会浪费空间。主从结点都会有一个consumequeue,根据不同的topic以及不同queueId,对消息索引进行存储。
    RocketMQ中的核心机制
    CommitLog以物理文件的形式进行存储,对所有ConsumerQueue都共享,CommitLog是顺序写,随机读。为了满足顺序写,需要知道CommitLog最后写到哪里了,因此需要借助ConsumerQueue,实际情况中会将所有的Queue都读入到内存,就能很快知道偏移量是多少;为了提升随机读的性能,RocketMQ会批量从磁盘中读取放入到内存中,加快后续的读取速度。

  • 高可用机制

    RocketMQ中的高可用机制主要是通过master和slave的配合,master角色的broker支持读写,slave角色的broker只读,也就是说生产方只能连接master角色的broker,但是消费方既可以连接所有broker,当然,我们并不需要指定从master读取还是从slave读取,而是自动切换,也就是说当master角色的机器宕机后,自动切换至slave角色的broker。另一方面,如何保障发送端的高可用呢?换句话说,如果连接的master角色的broker宕机后消息怎么保障仍能写入成功?这个需要利用broker的多组机制,相同brokerName,不同brokerId的机器称之为broker组,比如一主一从构建的broker组,当连接的broker组的master不可用,可以选择其他broker组进行发送。不同的broker之间相对独立并不需要进行同步,自然也不需要用到zookeeper进行分布式协调。

  • 刷盘方式

    RocketMQ消息的刷盘包括同步刷盘和异步刷盘,这样既能保证断电后恢复,又可以保障消息存储量。异步刷盘:在返回写成功状态时,消息可能只是被写入到了内存中,当内存中积累了一定量的消息后统一触发写入磁盘操作。同步刷盘:只要返回成功状态,消息已经被写入磁盘,也就是当消息写入到内存的时候通知刷盘线程进行刷盘操作,自己阻塞,刷盘完成后唤醒等待线程,返回写成功状态。

  • 复制方式

    一个Broker组有master和slave,有同步和异步两种复制方式,同步复制:master和slave均写入成功才反馈成功;异步复制:只要master成功就反馈成功。
    这两种复制方式的优劣点在于:在异步方式下,系统的延迟低,吞吐量高,但是一旦master宕机而slave没能同步到消息的时候会出现消息丢失;在同步方式下,系统延迟高,吞吐量低,但是能保障消息的不丢失,因为slave会有着全部的备份数据。

相关文章: