消息队列已经逐渐成为企业IT系统内部通信的核心手段。它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。

当今市面上有很多主流的消息中间件,如老牌的ActiveMQ、RabbitMQ,炙手可热的Kafka,阿里巴巴自主开发的Notify、MetaQ、RocketMQ等。

本文主要探讨主流的消息队列MQ比较,特征,以及典型使用场景。

目前主流的MQ产品

1.ZeroMQ

号称最快的消息队列系统,尤其针对大吞吐量的需求场景。

扩展性好,开发比较灵活,采用C语言实现,实际上只是一个socket库的重新封装,如果做为消息队列使用,需要开发大量的代码。ZeroMQ仅提供非持久性的队列,也就是说如果down机,数据将会丢失。其中,Twitter的Storm中使用ZeroMQ作为数据流的传输。

2.RabbitMQ

结合erlang语言本身的并发优势,支持很多的协议:AMQP,XMPP, SMTP, STOMP,也正是如此,使的它变的非常重量级,更适合于企业级的开发。

性能较好,但是不利于做二次开发和维护。

3.ActiveMQ

历史悠久的开源项目,是Apache下的一个子项目。已经在很多产品中得到应用,实现了JMS1.1规范,可以和spring-jms轻松融合,实现了多种协议,不够轻巧(源代码比RocketMQ多),支持持久化到数据库,对队列数较多的情况支持不好。

4.Redis

做为一个基于内存的K-V数据库,其提供了消息订阅的服务,可以当作MQ来使用,目前应用案例较少,且不方便扩展。对于RabbitMQ和Redis的入队和出队操作,各执行100万次,每10万次记录一次执行时间。

测试数据分为 128Bytes、512Bytes、1K和10K四个不同大小的数据。

实验表明:入队时,当数据比较小时Redis的性能要高于RabbitMQ,而如 果数据大小超过了10K,Redis则慢的无法忍受;出队时,无论数据大小,Redis都表现出非常好的性能,而RabbitMQ的出队性能则远低于 Redis。

5.Kafka/Jafka

Kafka是Apache下的一个子项目,是一个高性能跨语言分布式发布/订阅消息队列系统,而Jafka是在Kafka之上孵化而来的,即Kafka的一个升级版。

具有以下特性:

  • 快速持久化,可以在O(1)的系统开销下进行消息持久化;
  • 高吞吐,在一台普通的服务器上既可以达到10W/s的吞吐速率;完全的分布式系统,Broker、Producer、Consumer都原生自动支持分布式,自动实现负载均衡;
  • 支持Hadoop数据并行加载,对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。
  • Kafka通过Hadoop的并行加载机制统一了在线和离线的消息处理。Apache Kafka相对于ActiveMQ是一个非常轻量级的消息系统,除了性能非常好之外,还是一个工作良好的分布式系统。

何时需要消息队列

当你需要使用消息队列时,首先需要考虑它的必要性。

可以使用mq的场景有很多,最常用的几种:

  1. 做业务解耦
  2. 最终一致性
  3. 广播
  4. 错峰流控等

反之,如果需要强一致性,关注业务逻辑的处理结果,则RPC显得更为合适。

消息队列使用场景

1.解耦

解耦是消息队列要解决的最本质问题。所谓解耦,简单点讲就是一个事务,只关心核心的流程。而需要依赖其他系统但不那么重要的事情,有通知即可,无需等待结果。换句话说,基于消息的模型,关心的是“通知”,而非“处理”。

举一个例子,关于订单系统,订单最终支付成功之后可能需要给用户发送短信积分什么的,但其实这已经不是我们系统的核心流程了。

如果外部系统速度偏慢(比如短信网关速度不好),那么主流程的时间会加长很多,用户肯定不希望点击支付过好几分钟才看到结果。那么我们只需要通知短信系统“我们支付成功了”,不一定非要等待它立即处理完成。

2.最终一致性

最终一致性指的是两个系统的状态保持一致,要么都成功,要么都失败。

当然有个时间限制,理论上越快越好,但实际上在各种异常的情况下,可能会有一定延迟达到最终一致状态,但最后两个系统的状态是一样的。

业界有一些为“最终一致性”而生的消息队列,如:

  • Notify(阿里)
  • QMQ(去哪儿)等

其设计初衷,就是为了交易系统中的高可靠通知。

以一个银行的转账过程来理解最终一致性,转账的需求很简单,如果A系统扣钱成功,则B系统加钱一定成功。反之则一起回滚,像什么都没发生一样。

然而,这个过程中存在很多可能的意外:

  1. A扣钱成功,调用B加钱接口失败。
  2. A扣钱成功,调用B加钱接口虽然成功,但获取最终结果时网络异常引起超时。
  3. A扣钱成功,B加钱失败,A想回滚扣的钱,但A机器down机。

可见,想把这件看似简单的事真正做成,真的不那么容易。

所有跨VM的一致性问题,从技术的角度讲通用的解决方案是:

  1. 强一致性,分布式事务,但落地太难且成本太高,后文会具体提到。
  2. 最终一致性,主要是用“记录”和“补偿”的方式。在做所有的不确定的事情之前,先把事情记录下来,然后去做不确定的事情,结果可能是:成功、失败或是不确定,“不确定”(例如超时等)可以等价为失败。成功就可以把记录的东西清理掉了,对于失败和不确定,可以依靠定时任务等方式把所有失败的事情重新搞一遍,直到成功为止。
  3. 回到刚才的例子,系统在A扣钱成功的情况下,把要给B“通知”这件事记录在库里(为了保证最高的可靠性可以把通知B系统加钱和扣钱成功这两件事维护在一个本地事务里),通知成功则删除这条记录,通知失败或不确定则依靠定时任务补偿性地通知我们,直到我们把状态更新成正确的为止。
  4. 整个这个模型依然可以基于RPC来做,但可以抽象成一个统一的模型,基于消息队列来做一个“企业总线”。
  5. 具体来说,本地事务维护业务变化和通知消息,一起落地(失败则一起回滚),然后RPC到达broker,在broker成功落地后,RPC返回成功,本地消息可以删除。否则本地消息一直靠定时任务轮询不断重发,这样就保证了消息可靠落地broker。
  6. broker往consumer发送消息的过程类似,一直发送消息,直到consumer发送消费成功确认。
  7. 我们先不理会重复消息的问题,通过两次消息落地加补偿,下游是一定可以收到消息的。然后依赖状态机版本号等方式做判重,更新自己的业务,就实现了最终一致性。

最终一致性不是消息队列的必备特性,但确实可以依靠消息队列来做最终一致性的事情。

另外,所有不保证100%不丢消息的消息队列,理论上无法实现最终一致性。好吧,应该说理论上的100%,排除系统严重故障和bug。

像Kafka一类的设计,在设计层面上就有丢消息的可能(比如定时刷盘,如果掉电就会丢消息)。哪怕只丢千分之一的消息,业务也必须用其他的手段来保证结果正确。

2.广播

消息队列的基本功能之一是进行广播。

如果没有消息队列,每当一个新的业务方接入,我们都要联调一次新接口。有了消息队列,我们只需要关心消息是否送达了队列,至于谁希望订阅,是下游的事情,无疑极大地减少了开发和联调的工作量。

比如本文开始提到的产品中心发布产品变更的消息,以及景点库很多去重更新的消息,可能“关心”方有很多个,但产品中心和景点库只需要发布变更消息即可,谁关心谁接入。

3.错峰与流控

试想上下游对于事情的处理能力是不同的。

比如,Web前端每秒承受上千万的请求,并不是什么神奇的事情,只需要加多一点机器,再搭建一些LVS负载均衡设备和Nginx等即可。

但数据库的处理能力却十分有限,即使使用SSD加分库分表,单机的处理能力仍然在万级。由于成本的考虑,我们不能奢求数据库的机器数量追上前端。

这种问题同样存在于系统和系统之间,如短信系统可能由于短板效应,速度卡在网关上(每秒几百次请求),跟前端的并发量不是一个数量级。

但用户晚上个半分钟左右收到短信,一般是不会有太大问题的。如果没有消息队列,两个系统之间通过协商、滑动窗口等复杂的方案也不是说不能实现。

但系统复杂性指数级增长,势必在上游或者下游做存储,并且要处理定时、拥塞等一系列问题。而且每当有处理能力有差距的时候,都需要单独开发一套逻辑来维护这套逻辑。所以,利用中间系统转储两个系统的通信内容,并在下游系统有能力处理这些消息的时候,再处理这些消息,是一套相对较通用的方式。

消息队列使用总结

1.消息队列不是万能的,对于需要强事务保证而且延迟敏感的,RPC是优于消息队列的。

2.对于一些无关痛痒,或者对于别人非常重要但是对于自己不是那么关心的事情,可以利用消息队列去做。

3.支持最终一致性的消息队列,能够用来处理延迟不那么敏感的“分布式事务”场景,而且相对于笨重的分布式事务,可能是更优的处理方式。

4.当上下游系统处理能力存在差距的时候,利用消息队列做一个通用的“漏斗”,在下游有能力处理的时候,再进行分发。

5.如果下游有很多系统关心你的系统发出的通知的时候,果断地使用消息队列吧。

你可能也喜欢:

  1. 消息中间件系列(一):消息中间件介绍、典型使用场景、以及使用原则
  2. 消息中间件系列(二):Kafka的原理、基础架构、以及使用场景
  3. 消息中间件系列(四):消息队列MQ的特点、选型、及应用场景详解
  4. 消息中间件系列(九):详解RocketMQ的架构设计、关键特性、与应用场景
  5. 消息中间件系列(五):MQ消息队列的12点核心原理总结
  6. 消息中间件系列(六):什么是流量削峰?如何解决秒杀业务的削峰场景

消息中间件系列(三):主流的消息队列中间件有哪些?相关推荐

  1. 消息中间件系列(五):MQ消息队列的12点核心原理总结

    消息队列已经逐渐成为分布式应用场景.内部通信.以及秒杀等高并发业务场景的核心手段,它具有低耦合.可靠投递.广播.流量控制.最终一致性 等一系列功能. 无论是 RabbitMQ.RocketMQ.Act ...

  2. 消息中间件系列(七):如何从0到1设计一个消息队列中间件

    消息队列作为系统解耦,流量控制的利器,成为分布式系统核心组件之一. 如果你对消息队列背后的实现原理关注不多,其实了解消息队列背后的实现非常重要. 不仅知其然还要知其所以然,这才是一个优秀的工程师需要具 ...

  3. 较主流的消息队列的比较与选型

    目前业务上需要选用合适的消息队列来做数据传输,因此特意调研了一下当下较主流的消息队列的各特点: 消息中间件三要素:生产者.消息.消费者. 衡量标准:生产者.消息.消费者三者的交互. 1.消息路由:消息 ...

  4. 浅谈消息队列及常见的分布式消息队列中间件

    背景 分布式消息队列中间件是是大型分布式系统不可缺少的中间件,通过消息队列,应用程序可以在不知道彼此位置的情况下独立处理消息,或者在处理消息前不需要等待接收此消息.所以消息队列主要解决应用耦合.异步消 ...

  5. rabbitmq实战:高效部署分布式消息队列_一文看懂消息队列中间件--AMQ及部署介绍...

    概述 最近有个小项目用到了AMQ来做消息队列,之前介绍的主要是rabbitmq,所以今天主要提一下AMQ,也简单介绍下两者的区别~ 消息队列中间件 消息队列中间件(简称消息中间件)是指利用高效可靠的消 ...

  6. 【重难点】【RabbitMQ 01】消息队列的作用、主流的消息队列、RabbitMQ 基于什么传输消息、RabbitMQ 模型架构、死信队列和延迟队列

    [重难点][RabbitMQ 01]消息队列的作用.主流的消息队列.RabbitMQ 基于什么传输消息.RabbitMQ 模型架构.死信队列和延迟队列 文章目录 [重难点][RabbitMQ 01]消 ...

  7. kafka创建topic_ELK-基础系列(六)-ELK加入消息队列-Kafka部署

    Kafka集群部署指南 一.前言 1.Kafka简介 Kafka是一个开源的分布式消息引擎/消息中间件,同时Kafka也是一个流处理平台.Kakfa支持以发布/订阅的方式在应用间传递消息,同时并基于消 ...

  8. 消息队列中间件 Message Queue 简称:MQ

    一.什么是消息队列? 消息队列,一般我们会简称它为MQ(Message Queue) 队列是一种先进先出的数据结构. 现有常用的开源消息中间件有Kafka.CMQ.JBoss Messaging.JO ...

  9. Linux 环境进程间通信(三):消息队列

    本系列文章中的前两部分,我们探讨管道及信号两种通信机制,本文将深入第三部分,介绍系统 V 消息队列及其相应 API. 消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点.作为早期unix ...

最新文章

  1. .net System.Web.Caching.Cache缓存类使用详解(转载)
  2. 实现在Android开发中的Splash Screen开场屏的效果
  3. linux系统时间修改及同步
  4. 3 帮助命令、用户管理、压缩
  5. matlab虚拟现实之使用V-Realm Builder2建模
  6. 计算机系徽文案例,信息技术系——系徽征集令,重磅发布!
  7. [javascript] Promise API
  8. python中none什么意思_如何理解Python中的None
  9. plc用c语言编程的好处,学习PLC编程的重要性
  10. 程序员年龄变大后的职业出路是什么?
  11. 空头平仓什么意思_空头开仓和空头平仓是什么意思(贵金属交易口诀)
  12. ubuntu14.04安装360随身wifi 2代
  13. 已解决:Connection timed out: connect. If you are behind an HTTP proxy, please configure the proxy
  14. 互联网(软件)公司项目管理软件调研报告
  15. 九月英语总结——不同凡响
  16. 哈工大信息安全概论2021年期末考点
  17. NAT地址转换实验记录
  18. 关于卡尔曼及卡尔曼增益的理解【精】
  19. Ubuntu18.04屏幕分辨率问题
  20. python绘图之使用matplotlib连接两个点

热门文章

  1. 我张哥做的这ARM开发板,真酸爽!
  2. 一个学妹写的按键检测函数把我秀翻了!
  3. ioremap,你应该知道的事
  4. VS2010,C++ 制作静态库(*.lib),并使用
  5. 第二周:神经网络的编程基础之Python与向量化
  6. Vue权限控制——动态注册路由
  7. LeetCode 1691. 堆叠长方体的最大高度(排序+最大上升子序DP)
  8. ACwing 4. 多重背包问题 I(DP)
  9. LeetCode 327. 区间和的个数(multiset二分查找/归并排序)
  10. 程序员面试金典 - 面试题 16.26. 计算器(栈)