zoukankan      html  css  js  c++  java
  • RocketMQ

    RocketMQ是什么

      是一个队列模型的消息中间件,具有高性能,高可靠,高实时,分布式特点;

      Producer,Consumer,队列都可以分布式;

      Producer向一些队列轮流发送消息,队列集合称为Topic,Consumer如果做广播消费,则一个consumer实例消费这个Topic对应的素有队列,如果做集群消费,则多个consumer实例平均消费这个topic对应的队列集合;

      能够保证严格的消息顺序;

      提供丰富的消息拉取模式;

      高效的订阅者水平扩展能力;

      实时的消息订阅机制;

      亿级消息堆积能力;

    RocketMQ优点

      1.强调集群无单点,可扩展

      2.任意一点高可用,水平可扩展

      3.海量消息堆积能力,消息堆积后,写入低延迟

      4.支持上万个队列

      5.消息失败重试机制

      6.消息可查询

      7.开源社区活跃

      8.成熟度

    RocketMQ物理部署结构

        

      NameServer

        NameServer是RocketMQ的寻址服务。用于把Broker的路由信息做聚合。客户端依靠NameServer决定去获取对应的topic的路由信息,从而决定对那些Broker做连接。

        NameServer是一个几乎无状态的结点,NameServer之间采取share-nothing的设计,互不通信。

        对于一个NameServer集群列表,客户端连接NameServer的时候,只会选择随机连接一个结点,以做到负载均衡。

        NameServer所有状态都从Broker上报而来,本身不存储任何状态,所有数据均在内存。如果中途所有NameServer全都挂了,影响到路由信息的更新,不会影响和Broker的通信。

      Broker

        Broker是处理消息存储,转发等处理的服务器。

        Broker以group分开,每个group只允许一个master,若干个slave。

        只有master才能进行写入操作,slave不允许。

        slave从master中同步数据。同步策略取决于master的配置,可以采用同步双写,异步复制两种。

        客户端消费可以从master和salve消费。在默认情况下,消费者都从master消费,在master挂后,客户端由于从NameServer中感知到Broker挂机,就会从slave消费。

        Broker向所有的NameServer节点建立长连接,注册topic信息。

    RocketMQ逻辑部署结构

      

      Producer Group

        用来表示一个发送消息的应用,一个Producer Group下包含多个Producer的实例,可以是多台机器,也可以是一台机器的多个进程,或者一个进程的多个Producer对象。一个Producer Group可以发送多个Topic消息,Producer Group作用如下:

          1.标识一类Producer

          2.可以通过运维工具查询这个发送消息应用下有多个Producer实例

          3.发送分布式事务消息时,如果Producer中途宕机,Broker会主动回调Producer Group内的任意一台机器来确定事务状态;

      Consumer Group

        用来表示一个消费消息应用,一个Consumer Group下包含多个Consumer实例,可以是多台机器,也可以是多个进程,或者是一个进行的多个Consumer对象。一个Consumer Group下的多个Consumer以均摊方式消费消息,如果设置为广播方式,那么这个Consumer Group下的每个实例都消费全量数据。

    RocketMQ特性

      单击支持1万以上持久化队列

        

        1.所有数据单独存储在一个Commit Log,完全顺序写,随机读;

        2.对最终用户展现的队列实际只存储消息在Commit Log的位置信息,并且串行方式刷盘;

        这样做的好处:

          1.队列轻量化,单个队列数据量非常少;

          2.对磁盘的访问串行化,避免磁盘竞争,不会因为队列增加导致IOWAIT增高;

        这样做的缺点:

          1.写虽然完全是顺序写,但是读取却变成了完全的随机读;

          2.读一条消息,会先读Consumer Queue,在读CommitLog,增加了开销;

          3.要保证Commit Log与Consumer Queue完全一致,增加了编程的复杂度;

        以上缺点如何克服:

          1.随机读,尽可能让读命中PAGECACHE,减少了IO读操作,所以内存越大越好。如果系统中堆积的消息过多,读数据要访问磁盘会不会由于随机读导致系统性能急剧下降;

          2.由于Consumer Queue存储数据量极少,而且是顺序读,在PAGECACHE预读作用下,Consumer Queue的读性能几乎与内存一致,即使堆积情况下。所以可认为Consumer Queue完全不会阻碍读性能;

          3.Commit Log中存储了所欲的元信息,包含消息体,类似于mysql,Oracle的redolog,所以只要有Commit Log在,Consumer Queue即使数据丢失,仍然可以恢复出来;

      刷盘策略

        RocketMQ的所有消息都是持久化的,先写入系统PAGECACHE,然后刷盘,可以保证内存与磁盘都有一份数据,访问时,直接从内存读取。

      异步刷盘

        

      同步刷盘

        

          同步刷盘与异步刷盘的唯一区别就是异步刷盘写完PAGECACHE直接返回,而同步刷盘需要等待刷盘完成才返回;

          同步刷盘流程如下:

            1.写入PAGECACHE后,线程等待,通知刷盘线程刷盘;

            2.刷盘线程刷盘后,唤醒前端等待线程,可能是一批线程;

            3.前端等待线程向用户返回成功;

      消息查询

        1.按照message ID查询消息

          

          MsgId总共16字节,包含消息存储主机地址,消息Commit Log offset。从MsgId中解析出Broker的地址和Commit Log的偏移地址,然后按照存储格式所在位置消息buffer解析成一个完整的消息;

        2.按照Message Key查询消息

          

          1.根据查询的key的hashcode%slotNum得到具体的槽的位置(slotNum是一个索引文件里面包含的最大槽的数目)

          2.根据slotValue(slot位置对应的值)查找到索引项列表的最后一项(倒叙排列,slotValu总是指向最新的一个索引项)

          3.遍历索引项列表返回查询时间范围内的结果集(默认一个最大返回的32条记录)

          4.hash冲突,寻找key的slot位置时相当于执行了两次散列函数,一次key的hash,一个key的hash值取模,因此这里存在两次冲突的情况;第一种,key的hash值不同但模数相同,此时查询的时候会在比较一次key的hash值(每个索引项保存了key的hash值),过滤掉hash值不相等的项。第二种,hash值相等但key不等,出于性能的考虑冲突的检测放到客户端处理(key的原始值是存储在消息问加你中的,避免对数据文件的解析),客户端比较一次消息体的key是否相同。

          5.存储,为了节省空间索引项中存储的时间是时间差值(存储时间-开始时间,开始时间存储在索引文件头中),整个索引文件是定长的,结构也是固定的;

      服务器消息过滤

        RocketMQ的消息过滤方式有别于其他消息中间件,是在订阅时,再做过滤;

          

          1.在Broker端进行Message Tag比对,先遍历Consumer Queue,如果存储的Message Tag与订阅的Message Tag不符合,则跳过,继续比对下一个,符合则传输给Consumer。注意Message Tag是字符串形式,Consumer Queue中存储的是其对应的hashCode,比对时也是比对hashCode;

          2.Consumer收到过滤后的消息后,同样也要执行在Broker端的操作,但是比对的是真实的Message Tage字符串,而不是hashCode;

          为什么过滤要这样做?

            1.Message Tag存储hashCode,是为了在consumer Queue定长方式存储,节约空间;

            2.过滤过程中不会访问Commit Log数据,可以保证堆积情况下也能高效过滤;

            3.即使存在hash冲突,也可以在consumer端进行修改,保证万无一失;

      长轮询Pull

        RocketMQ的Consumer都是从Broker拉消息来消费,但是为了能做到实时收消息,RocketMQ使用长轮询方式,可以保证消息实时性同Push方式一致。这种长轮询方式类似于Web QQ收发消息机制。

      顺序消息原理

        

      顺序消息的缺陷

        1.发送顺序消息无法利用集群FailOver特性

        2.消费顺序消息的并行度依赖于队列数量

        3.队列热点问题,个别队列由于哈希不均导致消息过多,消费速度跟不上,产生消息堆积问题

        4.遇到消息失败的消息,无法跳过,当前队列消费暂停

      事务消息

        

      发送消息负载均衡

        

      订阅消息负载均衡

        

      单队列并行消费

        

        单队列并行消费采用滑动窗口方式并行消费。在一个滑动窗口区间,可以有多个线程并行消费,但是每次提交的offset都是最小的offset。

      消息堆积问题解决

        

        在有 Slave 情冴下,Master 一旦収现 Consumer 访问堆积在磁盘的数据时,会吐 Consumer 下达一个重定吐挃令,令 Consumer 从 Slave 拉叏数据,返样正常的収消息不正常消费的 Consumer 都丌会因为消息堆积叐影响,因为系统将堆积场景不非堆积场景分割在了两个丌同的节点处理。返里会产生另一个问题,Slave 会丌会写性能下降,答案是否定的。因为 Slave 的消息写入只追求吞吏量,丌追求实时性,只要整体的吞吏量高就可以,而 Slave 每次都是从 Master 拉叏一批数据,如 1M,返种批量顺序写入方式即使堆积情冴,整体吞吏量影响相对较小,只是写入RT 会发长。

  • 相关阅读:
    龙井和碧螺春的功效与作用
    064 01 Android 零基础入门 01 Java基础语法 08 Java方法 02 无参带返回值方法
    063 01 Android 零基础入门 01 Java基础语法 08 Java方法 01 无参无返回值方法
    062 01 Android 零基础入门 01 Java基础语法 07 Java二维数组 01 二维数组应用
    061 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 08 一维数组总结
    060 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 07 冒泡排序
    059 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 06 增强型for循环
    058 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 05 案例:求数组元素的最大值
    057 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 04 案例:求整型数组的数组元素的元素值累加和
    056 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 03 一维数组的应用
  • 原文地址:https://www.cnblogs.com/mayuan01/p/12391456.html
Copyright © 2011-2022 走看看