zoukankan      html  css  js  c++  java
  • 浅谈消息队列之RocketMQ

    什么是消息队列?

     
     

    为什么要用消息队列?

       即,应用场景是什么,也就是用了有什么好处

        解耦

            多应用间通过消息队列对同一消息进行处理,避免调用接口失败导致整个过程失败

        异步

            多应用对消息队列中同一消息进行处理,应用间并发处理消息,相比串行处理,减少处理时间

        削峰/限流

            避免流量过大导致应用系统挂掉的情况


    使用消息队列需要注意什么?

    系统复杂性增加

    如何保证消息队列是高可用,即做到集群高可用

    如何保证消费的可靠性传输,即不丢消息

    如何保证消息不被重复消费,即保证消费的幂等性

    如何保证消息的顺序性,即保证数据的逻辑正确性


    简单分析RocketMQ的原理

    高可用

    上架构

     
     

    NameServer

    维持心跳和提供Topic-Broker的关系数据,多个Namesrv之间相互没有通信,单台Namesrv宕机不影响其他Namesrv与集群;即使整个Namesrv集群宕机,已经正常工作的Producer,Consumer,Broker仍然能正常工作,但新起的Producer, Consumer,Broker就无法工作,nameserver不会有频繁的读写,所以性能开销非常小,稳定性很高

    Broker

    Broker与Namesrv的心跳机制:单个Broker跟所有Namesrv保持心跳请求,心跳间隔为30秒,心跳请求中包括当前Broker所有的Topic信息

    高可靠并发读写服务:所有发往broker的消息,有同步刷盘和异步刷盘机制,同步刷盘时,消息写入物理文件才会返回成功,因此非常可靠;异步刷盘时,只有机器宕机,才会产生消息丢失,broker挂掉可能会发生,但是机器宕机崩溃是很少发生的,除非突然断电。

    负载均衡:Broker上存Topic信息,Topic由多个队列组成,队列会平均分散在多个Broker上,而Producer的发送机制保证消息尽量平均分布到所有队列中,最终效果就是所有消息都平均落在每个Broker上

    高可用:集群部署时一般都为主备,Broker名相同的一组Master/Slave Broker,其中包含一个Master Broker(Broker Id为0)和0~N个Slave Broker(Broker Id不为0),备机实时从主机同步消息,如果其中一个主机宕机,备机提供消费服务,但不提供写服务。

    Producer

    Producer启动时,也需要指定Namesrv的地址,从Namesrv集群中选一台Master建立长连接,生产者每30秒从Namesrv获取Topic跟Broker的映射关系,更新到本地内存中。再跟Topic涉及的所有Broker建立长连接

    生产者发送时,会自动轮询当前所有可发送的broker,一条消息发送成功,下次换另外一个broker发送,以达到消息平均落到所有的broker上。假如某个Broker宕机,意味生产者最长需要30秒才能感知到。在这期间会向宕机的Broker发送消息。当一条消息发送到某个Broker失败后,会往该broker自动再重发2次,假如还是发送失败,则抛出发送失败异常。业务捕获异常,重新发送即可。客户端里会自动轮询另外一个Broker重新发送,这个对于用户是透明的

    消息发送方式分为,同步发送,异步发送,单向发送

    Consumer

    消费者启动时需要指定Namesrv地址,与其中一个Namesrv建立长连接。消费者每隔30秒从nameserver获取所有topic的最新队列情况

     Consumer跟Broker是长连接,会每隔30秒发心跳信息到Broker。Broker端每10秒检查一次当前存活的Consumer,若发现某个Consumer 2分钟内没有心跳,就断开与该Consumer的连接,并且向该消费    组的其他实例发送通知,触发该消费者集群的负载均衡。

    消费者得到master宕机通知后,转向slave消费(重定向,对于2次开发者透明),但是slave不能保证master的消息100%都同步过来了,因此会有少量的消息丢失。但是消息最终不会丢的,一旦master恢复,未同步过去的消息会被消费掉。

    消费分为集群消费和广播消费,


    Topic+Queue :

    topic的逻辑存储模型:

     
     

    如果各Master Broker有Slave Broker,Slave Broker中的结构和其对应的Master Broker完全相同。

    Topic是逻辑概念,对于RocketMQ,一个Topic可以分布在各个Broker上,把一个Topic分布在一个Broker上的子集定义为一个Topic分片,其实就是在某一broke上一个topic的部分数据

    Queue 存在的意义:每个Topic分片等分的Queue的数量可以不同,由用户在创建Topic时指定, 是消费负载均衡过程中资源分配的基本单元.

    Topic 的创建过程:

     
     

    创建topic需要指定的参数,

        -b 指定broker上创建topic

        -c 指定cluster创建topic

    -n 指定namesrv地址,cluster模式下必须从namesrv获取broker地址,支持cluster模式下创建topic和支持broker模式下创建topic

        -t topic的名字标志

        -r/w 读写队列的个数,建议相等

        -o 待研究不确定是不是保证全局有序消息的配置

     
     

    存储持久化

    消息队列的存储选型:

    分布式KV存储,文件系统(目前业界较为常用的几款产品RocketMQ/Kafka/RabbitMQ 均采用的是消息刷盘至所部署虚拟机/物理机的文件系统来做持久化,关系性DB(ActiveMQ)

    从高可靠,高效率,中间件减少对第三方的依赖考虑, 文件系统>分布式KV存储>关系型数据库DB

    存储架构:

     
     

    对比下Kafka的存储结构:

     
     

     每个Topic有多个partition(queue),kafka的每个partition都是一个独立的物理文件, 消息直接从里面读写

    RocketMQ存储的特点:

    1.Broker单个实例下所有的队列共用一个日志数据文件(即为CommitLog)来存储

    2.consumerQueue 是个消费的逻辑队列,保存了数据在commit log中的offset

    3. 消费读取数据,需要先读取consumerQueue,再读取commit log,消息主体都是通过CommitLog来进行读写.

    缺点:

    1. 顺序写,随即读

    克服缺点:

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

    小结

    RocketMQ可以严格的保证消息有序。但这个顺序,不是全局顺序,只是分区(queue)顺序。要全局顺序只能一个分区

    RocketMQ不保证消息不重复,如果你的业务需要保证严格的不重复消息,需要你自己在业务端去重



    作者:王洪伦
    链接:https://www.jianshu.com/p/027accb2b7ae
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    Win32程序支持命令行参数的做法
    打包jar类库与使用jar类库
    Java日期格式化
    集合类层次结构关系
    深入理解Arrays.sort()
    Java 异常类层次结构
    equals()与hashCode()方法协作约定
    shp数据和tab数据的两点区别
    java+上传文件夹
    vue+大文件分片上传
  • 原文地址:https://www.cnblogs.com/eryun/p/12163775.html
Copyright © 2011-2022 走看看