了解,消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构;目前使用较多的消息队列有 ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ
流量削锋
把消息压入RabbitMQ中可以缓冲系统压力。比如现在系统只能接受2000请求,但是一下子有10000个请求过来,那么这个请求就会压在RabbitMQ中,那么就可以慢慢进行消费了。
异步消息
以前是先去发短信,再去发邮件。引入RabbitMQ之后,我们就可以进行在发短信的同时再去发邮箱。
应用解耦
当多个系统耦合在一起的时候,系统的消息会发送给连在一起的系统,但是这个消息有些系统可能是不需要的。所以引入了之后,很方便将这个系统进行解耦,每个系统需要的就在消息队列解耦。
中⼩型公司⾸选RabbitMQ:管理界⾯简单,⾼并发。
⼤型公司可以选择RocketMQ:更⾼并发,可对Rocketmq进⾏定制化开发。
⽇志采集功能,⾸选kafka,专为⼤数据准备。
我们项目中使用 MQ 主要是做一些异步的操作,比如说我们的接口是属于 http 协议接口,
它是同步调用,如果说接口响应比较慢的情况下,会导致客户端同步阻塞等待,客户
端同步阻塞等待的情况下,会引发客户端超时,客户端一旦发生超时,就会导致客户端触发
一些重试的策略,而在触发重试的策略过程中会导致业务可能会发生重复执行,所以我们就
需要注意一些幂等性问题,而接口因为它执行比较耗时,所以呢,我们会将一些执行比较耗
时的业务逻辑代码把他直接改成使用 mq 异步去实现,能够提高就是我们的 http 协议接口
的响应速度,比如说异步的去扣库存呢,异步的去发短信呢这些场景下我们都是使用到 MQ
来进行实现落地的。
生产者投递消息过程当中可以设定一个消息 key,相同的业务逻辑呢可以设定一个相同的消息 key 在做 hash 的时候最终都会落地到同一个分区来就行存放,最终就被同一个消费者进行消费,所以想解决消息顺序这些问题,它的核心思想就是,让我们的这个消息投递存放到同一个分区里面,最终被同一个消费者消费。
消息堆积呢是一种常见的问题,尤其是在高并发的场景下,可以说是经常遇到了,生产者投递消息的这个速率,比我们的消费者消费速率明显不匹配,比如说我们最高峰的时候 生产者 它投递消息的时候一次性的 1s 内可能投递到将近几万条消息,但是我们的消费者他只有一个,而消费者消费消息的过程中是单个消费者的消费的速率比较慢,所以当时我们为了解决这个问题我们第一是先将我们的消费者做成集群的形式来进行消费,第二呢每个消费者,他一般都是批量的形式来进行消费,这样的话就可以提高我们的消费者他的消费速率,如果以后我们跟不上的情况呢,我们可以不断的横向扩张,对于我们的消费者不断的做集群,然后批量消费,这样就可以增加我们消费者的消费速率,从而可以解决我们的消息堆积的问题。
SimpleMessageListenerContainer可根据RabbitMQ消息堆积情况⾃动扩展消费者数量。
RabbitMQ使⽤发送⽅确认模式,确保消息正确地发送到RabbitMQ。
发送⽅确认模式:将信道设置成confirm模式(发送⽅确认模式),则所有在信道上发布的消息
都会被指派⼀个唯⼀的ID。⼀旦消息被投递到⽬的队列后,或者消息被写⼊磁盘后(可持久化
的消息),信道会发送⼀个确认给⽣产者(包含消息唯⼀ID)。如果RabbitMQ发⽣内部错误
从⽽导致消息丢失,会发送⼀条nack(not acknowledged,未确认)消息。
发送⽅确认模式是异步的,⽣产者应⽤程序在等待确认的同时,可以继续发送消息。当确认消息
到达⽣产者应⽤程序,⽣产者应⽤程序的回调⽅法就会被触发来处理确认消息。
接收⽅消息确认机制:消费者接收每一条消息后都必须进行确认(消息接收和消息确认是两个不同操
作)。只有消费者确认了消息,RabbitMQ才能安全地把消息从队列中删除。
这⾥并没有⽤到超时机制,RabbitMQ仅通过Consumer的连接中断来确认是否需要重新发送消息。也
就是说,只要连接不中断,RabbitMQ给了Consumer⾜够⻓的时间来处理消息。
特殊情况:
在消息⽣产时,MQ内部针对每条⽣产者发送的消息⽣成⼀个inner-msg-id,作为去重和幂等的依
据(消息投递失败并重传),避免重复的消息进⼊队列;在消息消费时,要求消息体中必须要有
⼀个bizId(对于同⼀业务全局唯⼀,如⽀付ID、订单ID、帖⼦ID等)作为去重和幂等的依据,避
免同⼀条消息被重复消费。
采取批量重导⽅法:将丢失的那批数据查询导⼊到mq⾥⾯。
消息持久化的前提是:将交换器/队列的durable属性设置为true,表示交换器/队列是持久交换器/
队列,在服务器崩溃或重启之后不需要重新创建交换器/队列(交换器/队列会⾃动创建)。
如果消息想要从Rabbit崩溃中恢复,那么消息必须:
从概念上来说,消息路由必须有三部分:交换器、路由、绑定。⽣产者把消息发布到交换器上;绑定决
定了消息如何从交换器路由到特定的队列;消息最终到达队列,并被消费者接收。
Broker:简单来说就是消息队列服务器实体。
Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
Queue:消息队列载体,每个消息都会被投⼊到⼀个或多个队列。
Binding:绑定,它的作⽤就是把exchange和queue按照路由规则绑定起来。
Routing Key:路由关键字,exchange根据这个关键字进⾏消息投递。
vhost:虚拟主机,⼀个broker⾥可以开设多个vhost,⽤作不同⽤户的权限分离。
producer:消息⽣产者,就是投递消息的程序。
consumer:消息消费者,就是接受消息的程序。
channel:消息通道,在客户端的每个连接⾥,可建⽴多个channel,每个channel代表⼀个会话
direct:如果路由键完全匹配,消息就被投递到相应的队列
fanout:如果交换器收到消息,将会⼴播到所有绑定的队列上
topic:可以使来⾃不同源头的消息能够到达同⼀个队列。 使⽤topic交换器时,可以使⽤通配
符,⽐如:“*” 匹配特定位置的任意⽂本, “.” 把路由键分为了⼏部分,“#” 匹配所有规则等。特别
注意:发往topic交换器的消息不能随意的设置选择键(routing_key),必须是由"."隔开的⼀系列
的标识符组成
headers交换器:根据发送消息内容的headers属性进⾏匹配(由于性能很差,不实⽤)
上一篇:机器学习调参
下一篇:芯片后端开发基础知识(二)