消息队列学习开篇

什么是消息队列?消息队列有哪些?又解决了哪些问题?该怎么选择消息队列?使用消息队列的时候会遇到哪些问题?带着这些疑问先对消息队列进行初步了解。

介绍

在计算机科学中,消息队列(英语:Message queue)是一种进程间通信或同一进程的不同线程间的通信方式,软件的贮列用来处理一系列的输入,通常是来自用户。消息队列提供了异步的通信协议,每一个贮列中的纪录包含详细说明的数据,包含发生的时间,输入设备的种类,以及特定的输入参数,也就是说:消息的发送者和接收者不需要同时与消息队列交互。消息会保存在队列中,直到接收者取回它。
一个 WIMP 环境像是 Microsoft Windows,借由优先的某些形式(通常是事件的时间或是重要性的顺序)来存储用户产生的事件到一个 事件贮列 中。系统把每个事件从事件贮列中传递给目标的应用程序。 ——摘自维基百科

维基百科中的解释,但是总感觉一大串术语,又是进程又是通信的,还有各种设备什么的。对于小白来说就用最简单的一句话就行了,消息队列就是用来发送和接收消息的队列,发送消息方叫作生产者,接收消息方叫作消费者
不要纠结这些专业术语了,我们了解消息队列主要用来业务上的问题的,老是按照专业的角度去理解多费事,入门简单的了解它是干什么的解决了什么问题就行了😜

应用场景

消息队列的应用场景主要有削峰、异步、解耦。

  1. 削峰
    对于一些平时访问量不是很大的接口,但是在某些特殊时期的访问会陡然剧增,这个时候机器部署如果在不使用消息队列的情况下需要配置最大化,但是这在非特殊时期完全是资源浪费,这个时候就可以考虑使用消息中间件了,在不增加机器的情况下,还能抗住特殊时期的大量请求。不知道有没有说的明白,其实我想说的就是秒杀的场景,平时接口的访问量不是很大,但是在大促期间的访问却很大。
  2. 异步
    异步也是一个主要的应用场景,就是对于一个耗时的操作,用户完全没有必要等到所有的流程都走完,耗时的那部分完全可以产生一条消息,稍后处理,直接返回给用户端,提高用户体验。
  3. 解耦
    解耦应该是这三个场景描述的解释中最难拿捏的,

常见的消息队列

KafkaPulsarRocketMQActiveMQRabbitMQ

业界主流的消息队列大概就这些了,基本上都是各大公司开源的系统,并交由apache孵化的。

如何选择消息队列

既然业界有那么多的消息中间件,那在业务中我们如果遇到了需要使用消息中间件的场景,我们又该如何去选择合适的消息中间件呢?一般可以从社区的活跃度、支持的语言、以及消息队列的功能来进行筛选,接下来将详细介绍消息中间件所具有的功能。

功能维度

队列

在消息中间件中,队列是一个不可或缺的角色,除了生产者和消费者之外,消息中间件提供了很多特殊功能的队列。一般的队列都是先进先出,但是下面的这些队列还具有其他特色。

  1. 优先级队列
    在优先级队列中,消息是具有优先级的,并不是传统的先进先出模式,在优先级队列中,优先级较高的消息会被优先消费。优先消费只有在有消息堆积的情况下才会产生,如果生产者生产消息的速度远远小于消费者消费消息的速度,那么消息队列中就不会有过多的消息,生产者刚生产完一条消息就被消费掉,不存在优先消费的现象。

  2. 延迟队列
    延迟队列是指消息队列中的消息不会立即被消费者消费,需要经过一定的延迟才会被消费者消费。延迟队列一般有两种实现方式,消息延迟和队列延迟。消息延迟的队列在新添加消息的时候需要进行排序,在性能上不如后者,延迟队列的设计方案一般会创建对个延迟级别的队列,这样就不需要对消息进行排序了。

大家上网搜关于延迟队列的应用场景,大多数都是关于订单支付的场景。在购物时,我们选好商品进行结算,但是正在输入支付密码或者刷脸的时候,领导过来了,交代你一个任务,此时你必须立马执行,那么此时支付就失败了,但是电商后台的订单记录还是存在的,并且这个商品是处于正在出售的状态,别的顾客是不能购买的,那么对于商家来说肯定是亏本的,他不管卖给谁,主要是把货卖出去。更糟糕的情况是如果你完成任务后,忘了支付。这个时候对于卖家来说就想骂人了,本来商品一天就可以买掉的,结果现在的情况是又多等了一天。如果这个时候在提交订单的时候往消息队列当中发送一条取消订单的延迟消息,那么在用户忘记支付的时候,延迟队列可以实现自动取消支付订单,让其他顾客来买,不是更加优雅吗?

  1. 死信队列
    当消息无法被正确的投递,即消费者服务从消息队列中获取消息。

  2. 回退队列
    正常的队列在消息被消费发生异常时,消息会被回退,这个时候消费者在此消费被回退的消息继续发生异常回退,反复回退消费,那么消息永远处于队列顶端,阻碍了其他消息被消费。如果为这个正常的队列设置一个回退队列,发生上述情况时,将消息放入回退队列中,这样就不会阻碍其他消息被消费了。

  3. 重试队列
    重试队列是指发生异常消费时,将消息添加到重试队列,达到重新投递延迟后在此被消费者消费。重试队列分为很多等级,每一个等级的投递延迟都不一样,被消费异常的消息随着重试的次数增加会被回退到更高等级的重试队列,意味着重试次数越多再次投递越久。当消息重试次数达到上限后,就会被放入到死信队列。

延迟队列和重试队列都有投递延迟,但是两者却有着本质的却别,延迟队列只会投递一次,并且由消息队列内部触发;重试队列会投递很多次但是有上线限制,并且由消费者控制。

消费模式

  1. 推(Push)模式
    由Broker节点主动推送消息至消费端,实时性较好,需要保证发送的消息不会压垮消费端。
  2. 拉(Pull)模式
    由消费者主动从Broker节点拉取消息,可以根据消费端自身的消费能力处理消息,不过实时性较差。

其他特性

  1. 广播消费
    消息的传递模式有两种:点对点模式和发布订阅模式。
    点对点模型:在一群系统中,系统A给系统B发送消息,只能被B接收,不能被其他系统弄接收
    发布订阅模型:在此模型中,发送发被称为发布者,接受者被称为订阅者,发布者与订阅者通过主题关联,多个发布者可以给同一个主题发送消息,一个主题也可以被多个订阅者订阅消息。
  2. 消息回溯
    被消费者消费过的消息还能被再次读取到,消息回溯的作用有很多,常见的场景有索引恢复、本地缓存构建以及消息丢失排查。
  3. 消息堆积&持久化
    在之前提到的流量削峰场景中,当有大量的消息发送到Broker节点,这个时候就需要依赖消息堆积将消息保存下来,等着消费者来消费。
  4. 消息追踪
    消息追踪就是指需要了解到消息从哪来以及发送到哪
  5. 消息过滤
    按照指定的规则为消费者提供消息
  6. 多租户
    多租户有点类似在一台电脑上开多个账户,目前还没接触到此类的业务,不太理解其作用。

性能

这里有一篇阿里中间件团队关于主流消息的性能测试对比文章,详情移步这里,通过对比可以了解到在同一配置下,Kafka(17w/s) > RocketMQ(11w/s) > RabbitMQ(5w/s)。

高可用

高可用一般包含两个方面:可靠性和可用性,消息队列中的可靠性主要是指对消息不丢失的保障程度;可用性是指无故障运行的时间百分比(就是经常网上看到的99.999%类似数据)。

Kafka和RabbitMQ对比

功能项 Kafka(1.1.0版本) RabbitMQ(3.6.10版本)
优先级队列 不支持 支持、建议优先级设置在0-10之间
死信队列 不支持 支持
延迟队列 不支持 支持
重试队列 不支持 原生不支持,可以根据借助延迟队列在消费端结合业务实现
消费模式 推模式 推模式 + 拉模式
广播模式 支持 支持
消息回溯 支持,可以根据offset读取已经消费过的消息 不支持,消息消费后会被删除
消息过滤 支持,客户端级别 原生不支持,需二次封装
多租户 不支持 支持
多协议支持 支持定义协议 AMQP、MQTT、STOMP等
跨语言支持 支持多语言客户端 支持多语言客户端
流量控制 消费者和生产者都可以控制 生产者控制
消息顺序 严格意义上不支持,但是可以通过单分区实现 不支持,但是当消费者和生产者都是单线程时,可以实现
安全机制 TSL/SSL、SASL身份认证和(读写)权限控制 TSL/SSL、SASL身份认证和(读写)权限控制
幂等性 支持单个生产者单分区会话的幂等性 不支持
事务性消息 支持 支持

在功能性比较上Kafka稍微弱于RabbitMQ,毕竟Kafka在设计之初就是为了统计日志,主要是针对性能,功能方面肯定是弱势,但是Kafka也在一直的更新中,后续的版本中也会出现更加优秀的版本也不一定。

这段对比也是抄自网上的文章,主要是想记的更深一点,就手动抄了一遍

总结

记得第一次接触消息队列是一个计费系统,在设计之初选择的是RabbitMQ,当时主要考虑的是消息的100%不丢失特性,毕竟涉及到钱的每一笔订单都很关键,但是后期组长要求换成Kafka,当时对消息队列不是很了解,就盲目的换掉了,这也是我为什么收集资料整理这篇文章的主要目的,希望以后再做消息队列选型的时候不会再盲目选择。当然在了解过这些知识之后我觉得当时应该首选RabbitMQ的,毕竟计费系统有很多功能上需要借助其来实现,目前没有用到只能说明现在的业务还不是很复杂。
对于一名初学者来说,要想从一个上帝的视角介绍所有的消息队列,显然是不可能的,本片文章大部分摘自朱小厮的消息中间件选型分析,把看过的心得体会记录下来。😍强烈推荐看一遍😍

相关链接

  1. 消息中间件选型分析