MQ-消息中间件(消息队列)

简介:

MQ(message queue)消息队列,也叫消息中间件

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

它是类似于数据库一样需要独立部署在服务器上的一种应用,提供接口给其他系统调用。

什么是消息队列?

  • 消息(Message):传输的数据。
  • 队列(Queue):队列是一种先进先出的数据结构。
  • 消息队列从字面的含义来看就是一个存放消息的容器。
  • 消息队列可以简单理解为:把要传输的数据放在队列中。
  • 把数据放到消息队列叫做生产者
  • 从消息队列里边取数据叫做消费者

消息队列是一种异步的服务间通信方式,是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。使用较多的消息队列有RocketMQ、RabbitMQ、Kafka等。

面向消息的中间件,简称为消息中间件,是一类以消息为载体进行通信的中间件,利用高效可靠的消息机制来实现不同应用间大量的数据交换。按其通信模型的不同,消息中间件的通信模型有两类:消息队列和消息传递。通过这两种消息模型,不同应用之间的通信和网络的复杂性脱离,摆脱对不同通信协议的依赖,可以在复杂的网络环境中高可靠、高效率的实现安全的异步通信。消息中间件的非直接连接,支持多种通信规程,达到多个系统之间的数据的共享和同步。面向消息中间件是一类常用的中间件。

为什么使用消息队列?

使用消息队列有三个好处:

解耦

耦合性:后台各个系统相互依赖,如果一个系统挂掉了,其他也会导致无法运行

举一个例子:比如你要把自己的房子租给别人,那么你可以自己去找租客,找不到就会一直找。但是你(生产者)把房子(消息)交给房产中介(中间件),你就不需要再找寻租客了,中间件的作用类似房产中介,你把消息交给中间件,就可以去忙别的了,什么时候有租房的,就可以去中间件里找需要的消息。

于是消息队列就进行解耦,加入了消息队列之后,不同的后台只需要将自己的数据写进消息队列即可,一个系统挂掉了,他在消息队列中的数据依旧存在,不用担心出现整体无法运行的情况

异步

异步提速:比如说我们原本有3个后台系统要向前端输出数据,每个后台都需要300ms,还要加上访问数据库的时间,如果一个用户访问的后台较多,那么访问的时间也会变得很久,用户体验较差

但如果使用了消息队列的话,不管要访问多少个后台数据,所有的后台只需要把数据都压进消息队列里面就可行了,如何用户再根据自己的需求从消息队列拿,大大减少所需时间

削峰

如果我们有一段时间的请求量非常大,就好比双11的时候,我们的后台只能接受1000个,但一下发过来3000个,这时候后台扛不住,就会崩溃

“流量削峰一般在秒杀活动中应用广泛,加入消息中间件,可以缓解短时间内的高并发请求。”

但是如果使用了消息队列,消息队列会把加载不了的信息丢到消息队列里面去,等后台持续性的加载,这样就不会出现系统崩溃的问题,顶多也只是慢一点

日志处理

解决大量日志传输。

消息通讯

消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。

消息队列有什么优点和缺点?

优点就是上面所说的三个: 解耦,异步,削峰,日志处理,消息通讯

缺点:

系统的可用性降低:我系统引入的外部依赖越多,消息队列就越容易挂掉,不加消息队列之前,我们虽然有耦合的问题,2个系统可能互相关联,一方挂掉导致其他一个也无法正常使用,但是如果加了消息队列,消息队列一旦挂掉,那么所有的系统都会挂掉

系统复杂性变高:硬生生加个 MQ 进来,你怎么保证消息没有重复消费?怎么[处理消息丢失的情况]?怎么保证消息传递的顺序性?

一致性问题:生产者把消息提交给中间件,消费者取走一条数据,此时中间件将数据标记为已消费,但此时消费者宕机了,数据没有成功消费完,此时就产生了数据一致性问题。

如何保证消息的可靠性传输?(如何处理消息丢失的问题)

消息发送给消息队列

a、丢失的原因:因为网络传输的不稳定性,当生产者在向MQ发送消息的过程中,MQ没有成功接收到消息,但是生产者却以为MQ成功接收到了消息,不会再次重复发送该消息,从而导致消息的丢失。

b、解决办法: 有两个解决办法:事务机制和confirm机制,最常用的是confirm机制。

消息的顺序性问题:

data1 和 data2 是有顺序的,必须 data1 先执行,data2 后执行;这两个数据被不同的消费者消费到了,可能 data2 先执行,data1 后执行,这样原来的顺序就错乱了。

如何解决消息的顺序性问题(概括的说):

①:单线程消费来保证消息的顺序性;

②:保证生产者 - 中间件 - 消费者是一对一的关系;

③:对消息进行编号,消费者处理时根据编号判断顺序。

消息的重复问题:

造成消息重复的根本原因是:网络不可达。中间件发送data1给消费者,但是由于网络延迟的原因,一直停留在网络中,延迟一段时间中间件没有收到消费者的确认,就会再次发送data1,第二次发送的data1经过其他的没有延迟的路由器到达了消费者,恰恰此时第一次发送的data1的网络通了,也到达了消费者,这就造成了数据的重复问题。

如何解决消息的重复问题?

①:消费端处理消息的业务逻辑保持幂等性。只要保持幂等性,不管来多少条重复消息,最后处理的结果都一样。

②:保证每条消息都有唯一编号且保证消息处理成功与去重表的日志同时出现。利用一张日志表来记录已经处理成功的消息的 ID,如果新到的消息 ID 已经在日志表中,那么就不再处理这条消息。

什么是幂等性?

幂等性是指,用户对同一操作(如在新建a.txt并写入hello world),发起了一次请求还是多次请求,对服务器的影响是一致的,不会请求几次就新建几个a.txt文件并写入hello world。

幂等性的适用领域:

比如第一次付款时实际支付成功,但是信息返回时网络中断导致系统误判,需要用户重新支付一次,但肯定不能让用户支付双倍的价钱啊;又比如第一次付款的确失败了,但第二次付款时发生意外,导致支付请求被重复发送等等。在一次支付的过程中,每个环节都有可能会发生问题,我们要如何规避这类问题引发的风险?幂等性是解决这类问题的方案之一,所以在电商,银行,互联网金融等对数据准确性要求很高的领域中,这一特性具有十分重要的地位。

幂等性的实现方式有哪些?如何实现幂等性?

  • 去重表:

在插入数据的时候,插入去重表,利用数据库的唯一索引特性,保证唯一的逻辑。这种方法适用于在业务中有唯一标的插入场景中,比如在支付场景中,如果一个订单只会支付一次,所以订单ID可以作为唯一标识。这时,我们就可以建一张去重表,并且把唯一标识作为唯一索引,在我们实现时,把创建支付单据和写入去去重表,放在一个事务中,如果重复创建,数据库会抛出唯一约束异常,操作就会回滚。

  • 悲观锁:

select for update,整个执行过程中锁定该订单对应的记录。注意:悲观锁在DB读大于写的情况下尽量少用。

  • select + insert:

并发不高的后台系统,或者一些任务JOB,为了支持幂等,支持重复执行,简单的处理方法是,先查询下一些关键数据,判断是否已经执行过,在进行业务处理,就可以了。注意:核心高并发流程不要用这种方法。

  • token机制:

防止页面重复提交。数据提交前要向服务器申请token,token放到redis或jvm内存,用户访问服务器需要提交token并让后台校验token,,token有效时间过期后需要删除token,用户再次访问时生成新的token返回。token特点:要申请,一次有效性,可以限流。

  • 对外提供接口的api:

如银联提供的付款接口:需要接入商户提交付款请求时附带:source来源,seq序列号。source+seq在数据库里面做唯一索引,防止多次付款,(并发时,只能处理一个请求)

  • 全局唯一ID:

如果使用全局唯一ID,就是根据业务的操作和内容生成一个全局ID,在执行操作前先根据这个全局唯一ID是否存在,来判断这个操作是否已经执行。如果不存在则把全局ID,存储到存储系统中,比如数据库、redis等。如果存在则表示该方法已经执行。

使用中间件的架构是什么样的?

  • 客户端—中间件—服务器端。也可以叫做:
  • 生产者—消息队列—消费者。

常用的中间件推荐?

  • 中小型公司,技术实力较为一般,技术挑战不是特别高,用 RabbitMQ 是不错的选择;

大型公司,基础架构研发实力较强,用 RocketMQ 是很好的选择。

如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的。

常用中间件(Kafka ,ActiveMQ ,RabbitMQ ,RocketMQ)之间的对比

ActiveMQ

RabbitMQ

RocketMQ

Kafka

单机吞吐量

万级,比RabbitMQ低

同ActiveMQ,2.6w/s(消息做持久化)

10万级,支撑高吞吐,11.6w/s

10万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景,17.3w/s

时效性ms级微秒级,这是RabbitMQ的一大特点,延迟最低ms级延迟在ms级以内
可用性高,基于主从架构实现高可用同ActiveMQ非常高,分布式架构非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
消息可靠性有较低的概率丢失数据基本不丢失经过参数优化配置,可以做到0丢失同RocketMQ

开发语言

Java

Erlang

Java

Scala/Java

主要维护者

Apache

Mozilla/Spring

Alibaba

Apache

成熟度

成熟

成熟

开源版本不够成熟

比较成熟

订阅形式

点对点(p2p)、广播(发布-订阅)

提供了4种:direct, topic ,Headers和fanout。fanout就是广播模式

基于topic/messageTag以及按照消息类型、属性进行正则匹配的发布订阅模式

基于topic以及按照topic进行正则匹配的发布订阅模式

持久化

支持少量堆积

支持少量堆积

支持大量堆积

支持大量堆积

顺序消息

不支持

不支持

支持

支持

性能稳定性

一般

较差

集群方式

支持简单集群模式,比如’主-备’,对高级集群模式支持不好。

支持简单集群,'复制’模式,对高级集群模式支持不好。

常用 多对’Master-Slave’ 模式,开源版本需手动切换Slave变成Master

天然的‘Leader-Slave’无状态集群,每台服务器既是Master也是Slave

管理界面

一般

较好

一般

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值