消息队列之概论
什么是消息队列?消息队列能做什么?消息队列为什么会出现?再说消息队列之前我们要先知道什么是消息队列、能够做什么、为什么会出现消息队列?
1、什么是消息队列
消息队列是在分布式系统中最常用的且最重要的组件之一,这个分布式系统不是指你的一个服务部署到不同的机器中,如果你是一个相同的服务部署到不同的机器这种不能称之为分布式系统,准确来说应该说是集群服务,而分布式系统通常是指有很多个不同的服务分别部署到不同的服务器中,
如图:
,如何在不同的服务中进行快速的数据交互或者调用,通常有两种方式分别是RPC调用和消息队列,常见的RPC调用分别有Http、GRPC等。而消息队列的方式是指由三个重要部分分别是《消息生产者、消息服务中心、消息消费者》组成。
- 生产者: 消息的生产者只负责将消息发送给消息服务中心,它只在意消息是否成功的存储在了消息队列服务中。
- 消息服务中心: 消息服务中心其实可以当做一个中间商来看,其实它的作用就是将数据持久化到自己服务内,不在意是谁发送的消息。
- 消息消费者: 消息消费者是指从中间商获取消息的一个部分,它只在意我是否能拿到消息至于是谁发布的它不在意。
2、消息队列能做什么
消息队列可以做:应用解耦、流量削峰、日志收集、消息通讯、事务最终一致性等场景都可以使用消息队列。
2.1、流量削峰
什么是流量削峰,在互联网行业中,可能会在某一个时间段网站迎来用户的请求高峰期的> 情况例如(12306、淘宝双十一)等,在系统设计之初可能只是简单写入数据库,但是如果一直延续这样的设计遇到高峰期的请求就会给数据库带来巨大的压力,并发量超出了系统的承载能力可能会引起系统雪崩。当访问量剧增的> 时候系统一览可以继续使用最常见的是使用消息队列,将短时间的高并发请求持久化到消息队列服务中,从而实现削平高峰期的请求并发流量,改善系统性能。
2.2、系统解耦
在大型系统的开发过程中会经常碰到 类情况 随着需求的叠加 各模块之间逐渐变成了相互调用的关系,这种模块间紧密关联的关系就是紧相合 紧相合带来的问题是对一个模块的功能变更将导致其关联模块发生变化,因此各个模块难以独立演要解决这个题,可以在模块之间调用时增加 个中问层来实现解楠,这也方便了以后的 扩展。所谓解锢,简单地讲,就是一个模块只关心自己的核心流程,而依赖该棋块执行结果的其他模块如果做的不是很重要的事情,有通知即可,无须等待结果 换句话说,基于消息队列的模型,关心的是通 ,而非处理。
2.3、事务最终一致性
如果系统很小,将两个表存储在相同的数据库中,我们可以通过数据库的强一致性事务进行管理,如果我们是大型系统需要操作不同的数据库完成一个业务那么就无法使用数据库事务来完成了,?业界曾经提出过 个处理分布式事务的规范 XAo XA 主要定义了全事务管理器( Transaction Manager )和局部资源管理器( Resource Manager )之间的接。 XA接口是双向的系统接口,在事务管理器及 个或多个资源管理器之间形成通信桥梁。兀气引入事务管理器充当全局事务中的协调者的角色。事务管理器控制着全局事务,管理事务生命周期,并协调资源。资源管理器负责控制和管理实际资源(如数据库或 JMS 队列)。目前各主流数据库都提供了对凡气规范的支持。它的缺陷是性能很差,不适合高并发和高性能要求的场景。我们可以通过消息队列来处理事务问题,其实在分布式事务中最主要的是CAP定理,和Base理论,在此不详细介绍CAP定理和Base理论,具体的可以自行百度。
2.4、日志收集
消息队列也可以用来做日志收集,在项目运行中日志也是一个很重要的组成部分,可以通过日志跟踪调试信息、定位问题、用户操作行为等等。具体的日志分析就需要大数据来进行分析了,日志收集的消息队列用的最多的就是kafka。
3、消息服务中心的功能与特点
消息队列它包含了两个关键词《消息和队列》,消息是指在不通服务之间传递的具体数据,消息可以是各式各样的;对于队列的含义我个人理解的其实就是数据结构中队列的概念,是指先进先出,消息的入队和出队并不一定是同步进行的,所以需要一个容器来暂存和处理消息,而消息服务中心就是这个容器。在上面有提到过三个重要的组成部分,分别是:消息生产者->Producer、消息服务中心->Broker、消息消费者->Consumer,除了这些一个好的消息队列还应该具备以下功能:消息堆积、消息持久化、可靠投递、消息重复、高可用集群部署等各种问题。
3.1、消息堆积
因为消息队列的生产者、消费者是两个分开处理消息的系统,也无法预制两者对消息的处理速度快慢,一旦在某个时间段内消费者的处理速度没有跟上生产者发送消息的速度会导致消息处理中心积压无法及时得到释放。因此一个好的消息队列产品需要具备处理这种情况,比如通过设置一个阀值,超过阀值的消息不在放入处理中心等,避免消息中心系统资源耗尽,导致消息中心服务宕机。
3.2、消息持久化
在设计一个消息队列时,如果生产者的消息到达消息服务中心不做任何处理就直接转给消费者那么消息服务中心的存在也就失去了意义,无法满足流量削峰等需求,所以消息服务中心的常规做法都是将消息暂存到消息服务中心本地,然后择机将消息投递给消费者,消息的暂存可以在内存中,也可以选择存储到磁盘、数据库、文件等地方。将消息存放到内存中最大的问题就是一旦宕机消息会丢失。如果你的业务场景要求消息不能丢失,那么势必需要将消息持久化,前面也有提到过持久化方案分为很多种。
3.3、可靠投递
可靠投递是指不允许存在消息途中丢失的情况。从消息的整个生命周期来分析的话,消息丢失的情况一般出现在以下过程中:
- 从生产者到消息服务中心
- 从消息服务中心到消息消费者
- 消息中心一旦宕机是否持久化了消息
由于跨越不同系统,中间调用会朋友许多问题,例如网络问题、系统宕机等不确定的情形,但是对消息发送者来说都是一件事,消息没有送达,在有些场景下需要保证消息不能丢失,例如网购时订单支付成功消息不能丢失,否则这笔订单会卡在未支付环节。
3.4、集群
在大型系统应用中,系统架构一般都需要实现高可用性,用来排除单点故障引起的系统中断,保证7*24小时不间断运行,所以消息服务中心需要对集群模式提供支持,集群不仅可以让消费者和生产者在某个节点宕机的情况下继续运行,集群之间的多个节点还能够共享负载,当某台机器或者网络出现故障时自动进行负载均衡,从而保证多节点来提高消息通信的吞吐量。
4、主流消息服务中间件对比
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|---|
单机吞吐量 | 万级,与RocketMQ、kafka相比吞吐量略低 | 1W量级,与RocketMQ、kafka相比吞吐量略低 | 10 万级,支撑高吞吐 | 10 万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景 |
Topic数量对吞吐量的影响 | 未知 | 未知 | topic 可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是 RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topic | topic 从几十到几百个时候,吞吐量会大幅度下降,在同等机器下,Kafka 尽量保证 topic 数量不要过多,如果要支撑大规模的 topic,需要增加更多的机器资源 |
时效性 | ms 级 | 微秒级,这是 RabbitMQ 的一大特点,延迟最低 | 毫秒级 | 毫秒 |
可用性 | 可以基于主从架构实现高可用 | 可以基于主从架构实现高可用 | 很高(主从模式) | 非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
消息丢失 | 有较低的概率丢失数据 | 基本不丢 | 参数优化配置,可以做到 0 丢失 | 参数优化配置,可以做到 0 丢失 |
消费模式 | 推拉 | 推拉 | 拉取 | |
优点 | MQ领域的功能极其完备 | 由于erlang语言的特性,mq 性能较好,高并发;健壮、稳定、易用、跨平台、支持多种语言、文档齐全;社区活跃度高;路由机制完备 | MQ功能较为完善,还是分布式的,扩展性好,支持10亿级别的消息堆积,不会因为堆积导致性能下降 | 性能卓越,单机写入TPS约在百万条/秒,最大的优点,就是吞吐量高。 |
缺点 | 官方社区现在对ActiveMQ 5.x维护越来越少,较少在大规模吞吐的场景中使用。 | erlang开发,很难去看懂源码,基本职能依赖于开源社区的快速维护和修复bug,不利于做二次开发和维护。RabbitMQ吞吐量会低一些,这是因为他做的实现机制比较重。需要学习比较复杂的接口和协议,学习和维护成本较高。 | 支持的客户端语言不多,目前是java及c++,其中c++不成熟; 社区活跃度一般, 没有在 mq 核心中去实现JMS等接口,有些系统要迁移需要修改大量代码 | Kafka单机超过64个队列/分区,Load会发生明显的飙高现象,队列越多,load越高,发送消息响应时间变长 |
总结
消息中间件是非底层操作系统软件、非业务应用软件,更不是直接面对最终用户使用的,不能直接给用户带来价值的软件统称为中间件。消息中间件关注的是数据的发送和结构,利用高效、可靠的异步消息投递机制集成成分布式系统。