美文网首页Go知识库MQ消息系列
消息中间件的一些思考

消息中间件的一些思考

作者: 千淘萬漉 | 来源:发表于2018-12-12 18:39 被阅读55次
    1.为什么使用消息队列?

    核心说起来就是:解耦、异步、削峰。

    • 解耦:RPC的调用是强依赖的,系统之间的调用会存在耦合,而通过消息中间件可以将业务上弱依赖、系统调用上的强依赖关系进行解耦。
    • 异步:其实还是上一步解耦的延生,原先业务上是同步代码采用中间件进行异步操作以后,系统的响应耗时大大降低。
    • 削峰:MQ会提供两种模式消息获取方式:1-server推模式,2-client拉模式,MQ-client根据自己的处理能力,每隔一定时间,或者每次拉取若干条消息,实施流控,达到保护自身的效果。并且这是MQ提供的通用功能,无需上下游修改代码。
    • 延时队列:采用轮询db的方式做了太多的无用功,采用Jdk原生的延时队列无法应对应用重启的情况,而MQ自带了延时推送的功能,是延时任务上理想的解决方案。
    2.消息队列的不足?
    • 引入了MQ中间将势必会增加系统的复杂性,需要考虑更多的问题:如何保证消息没有重复消费?如何处理消息丢失的情况?如何保证消息传递的顺序性。
    • 引发业务上一致性的问题:这也是由于异步解耦的,原本A的响应需要BC的成功,用同步操作是没有问题的,但如果为了提高响应在解耦后B成功而C调用失败,而A已经给了客户成功的响应,这里就会有结果处理不一致的问题。
    3.各种消息中间件的对比与选型
    特性 ActiveMQ RabbitMQ RocketMQ Kafka
    单机吞吐量 万级,吞吐量比RocketMQ和Kafka要低了一个数量级 万级,吞吐量比RocketMQ和Kafka要低了一个数量级 10万级,RocketMQ也是可以支撑高吞吐的一种MQ 10万级别,这是kafka最大的优点,就是吞吐量高。一般配合大数据类的系统来进行实时数据计算、日志采集等场景
    topic数量对吞吐量的影响 topic可以达到几百,几千个的级别,吞吐量会有较小幅度的下降。RocketMQ的一大优势,在同等机器下,可以支撑大量的topic topic从几十个到几百个的时候,吞吐量会大幅度下降。所以在同等机器下,kafka尽量保证topic数量不要过多。如果要支撑大规模topic,需要增加更多的机器资源
    时效性 ms级 微秒级,这是rabbitmq的一大特点,延迟是最低的 ms级 延迟在ms级以内
    可用性 高,基于主从架构实现高可用性 高,基于主从架构实现高可用性 非常高,分布式架构 非常高,kafka是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
    消息可靠性 有较低的概率丢失数据 经过参数优化配置,可以做到0丢失 经过参数优化配置,消息可以做到0丢失
    功能支持 MQ领域的功能极其完备 基于erlang开发,所以并发能力很强,性能极其好,延时很低 MQ功能较为完善,还是分布式的,扩展性好 功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准

    总结:

    • ActiveMQ非常成熟,功能强大,在业内大量的公司以及项目中都有应用,偶尔会有较低概率丢失消息;现在社区以及国内应用都越来越少,官方社区现在对ActiveMQ 5.x维护越来越少,几个月才发布一个版本。而且确实主要是基于解耦和异步来用的,较少在大规模吞吐的场景中使用,适用于小公司业务规模不大的场景。

    • RabbitMQ是由Erlang语言开发,性能极其好,延时很低;吞吐量到万级,MQ功能比较完备,而且开源提供的管理界面非常棒;社区相对比较活跃,几乎每个月都发布几个版本分在国内一些互联网公司近几年用rabbitmq也比较多一些。
      但是问题也是显而易见的,RabbitMQ确实吞吐量会低一些,这是因为他做的实现机制比较重。而且Erlang开发,很难去看懂源码,掌控很弱,基本职能依赖于开源社区的快速维护和修复bug。而且Rabbitmq集群动态扩展会很麻烦。

    • RocketMQ接口简单易用,有阿里背书,日处理消息上百亿之多,可以做到大规模吞吐,性能也非常好,分布式扩展也很方便,社区维护还可以,可靠性和可用性都是可以,还可以支撑大规模的topic数量,支持复杂MQ业务场景,而且一个很大的优势在于,阿里出品都是java系的,我们可以自己阅读源码,定制自己公司的MQ,可以掌控。社区活跃度相对较为一般,文档相对来说简单,然后接口这块不是按照标准JMS规范走的有些系统要迁移需要修改大量代码。

    • Kafka的特点明显——仅仅提供较少的核心功能,但是提供超高的吞吐量,ms级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展。同时kafka最好是支撑较少的topic数量即可,保证其超高吞吐量,而且kafka唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略,这个特性天然适合大数据实时计算以及日志收集。

    4.如何保证消息不被重复消费啊(设计消息消费时的幂等性)?

    需要结合具体的业务来看,重启系统重启应用等突发事件发生时可能会无可避免的产生MQ的消息重复推送,这个时候要保证消息消费时,重复的数据在DB里面只有一条:

    • 比如数据要写库,可根据主键查一下,如果Primary Key存在则只是update操作。
    • 比如redis写操作,每次都是set,天然幂等性
    • 复杂一点的情况,则可以让生产者发送每条数据的时候,里面加一个全局唯一的ID,到了消费者这里以后,先根据这个ID去DB里查一下,是否之前消费过吗?如果没有消费过,可以写入DB。如果消费过了,则直接略过!
    5.如何保证消息的可靠性传输(如何处理消息丢失的问题)?

    这个地方针对不同的消息中间件有不同的确认机制,以RabbitMQ为例,其一般承担的是非常核心的业务数据,必须保证数据不能丢失,从消息链路的每个环节都必须保证可靠性:消息发送,RabbitMQ自身还有消息接收三个环节。消息发送时的事务+确认机制,RabbitMQ持久化机制,还有消费端的手动Ack模式。具体可以参阅:《深入浅出RabbitMQ》

    6.如何保证消息的顺序性?

    会错乱的场景和对应的解决方案:

    • Rabbitmq:一个Queue,多个Consumer。
      拆分多个Queue,每个Queue一个Consumer,就是多一些Queue而已,确实是麻烦点;或者就一个Queue但是对应一个Consumer,然后这个Consumer内部用内存队列做排队,然后分发给底层不同的Worker来处理

    • Kafka:一个Topic,一个Partition,一个Consumer,内部多线程也容易错乱。
      一个Topic,一个Partition,一个Consumer,内部单线程消费,写N个内存Queue,然后N个线程分别消费一个内存queue即可

    7.消息的高可用

    RabbitMQ方面采用的是镜像队列的来保证服务的高可用,基于主从架构。引入RabbitMQ的镜像队列机制,将queue镜像到cluster中其他的节点之上。在该实现下,如果集群中的一个节点失效了,queue能自动地切换到镜像中的另一个节点以保证服务的可用性。在通常的用法中,针对每一个镜像队列都包含一个master和多个slave,分别对应于不同的节点。slave会准确地按照master执行命令的顺序进行命令执行,故slave与master上维护的状态应该是相同的。——可参考《深入浅出RabbitMQ》

    8.消息堆积的处理方案
    9.如果让你写一个消息队列,该如何进行架构设计啊?

    相关文章

      网友评论

        本文标题:消息中间件的一些思考

        本文链接:https://www.haomeiwen.com/subject/zijphqtx.html