目录
介绍下消息队列?
问题回答
- 消息队列(Message Queue),简称为MQ,是分布式系统中重要的组件
- 消息队列主要解决了应用耦合、异步处理、流量削锋等问题
- 目前使用比较多的Mq是RabbitMQ、RocketMQ、ActiveMQ、Kafka。
- 了解下出处RabbitMQ、RocketMQ、ActiveMQ
-
- ActiveMQ是由Apache出品,可以运行在Java语言所支持的平台之上,社区活跃度不太高了。
- RocketMQ出自 阿里的开源产品,用 Java 语言实现,社区活跃度高,
- RabbitMQ则是国外一个公司研发的,基于的Erlang语言编写,社区活跃度高。
- 使用情况
-
- ActiveMQ用的越来越少
- RabbitMQ不错,不过erlang语言开发,想要深入研究和掌控他有点难
- RocketMQ不错,开源的,是不错的选择;大型公司,基础架构研发实力较强,用RocketMQ是很好的选择
- 是大数据领域的实时计算、日志采集等场景,用Kafka是业内标准
- 总结:Kafka主要在大数据领域用的多,用来处理日志之类的,JavaEE用RabbitMQ、RocketMQ、ActiveMQ居多,用来处理业务,其中RabbitMQ使用广泛。
介绍下RabbitMQ
- RabbitMQ是一个由erlang语言编写的、开源的、在AMQP基础上完整的、可复用的企业消息系统。
- RabbitMQ包括五种队列模式,简单队列、工作队列、发布/订阅、路由、主题、rpc等。项目中用路由和主题模式比较多
- 有消息确认机制
-
- 模式1:自动确认
- 模式2:手动确认
- 有持久化机制,提供交换机和队列的持久化
-
- 持久化:将交换机或队列数据保存到磁盘,服务器宕机或者重启之后数据依然存在。
- 非持久化:将交换机或队列数据保存到磁盘到内存,服务器宕机或者重启之后数据会丢失
辅助理解
1、RabbitMQ五种消息发送模式
简单队列
- 生产者将消息发送到队列,消费者从队列获取消息。
- 一个队列对应一个消费者。
工作队列
- 一个生产者,多个消费者。
- 一条消息只会被一个消费者接收。
- rabbitmq采用轮询的方式将消息是平均发送给消费者的。
- 消费者在处理完某条消息后,才会收到下一条消息。
发布/订阅模式(Publish/Subcribe)
- 将消息发送到交换机,队列从交换机获取消息,队列需要绑定到交换机。
- 每一个消费者都有自己的一个队列。
- 生产者没有将消息直接发送到队列,而是发送到交换机(简单队列和工作队列就是发到队列的)。
- 每一个队列都要绑定到交换机。
- 生产者发送的消息,经过交换机到达队列,实现一个消息被多个消费者获取的目的。
- 交换机类型为“fanout”。
- 注意:交换机本身没有存储消息的能力,消息只能存储到队列中。
路由模式(Routing)
- 路由模式是发布/订阅模式的一种特殊情况。
- 路由模式的交换机类型为“direct”。
- 绑定队列到交换机时指定 key,即路由键,一个队列可以指定多个路由键。
- 生产者发送消息时需要指定路由键,这时,消息只会发送到绑定的key的对应队列中。
主题模式(Topic)
- 将路由键和某模式进行匹配。此时,队列需要绑定到一个模式上。符号“#”匹配一个或多个词,“*”匹配一个词。
- 绑定队列到交换机指定key时,进行通配符模式匹配。
怎么理解了应用耦合、异步处理、流量削锋?
问题回答
应用解耦
通过消息中间件,让系统和系统之间耦合度降低,系统B出现问题,不会导致依赖它的系统A出现问题
比如以电商应用为例,应用中有订单系统、库存系统、物流系统、支付系统。用户创建订单后,如果耦合调用库存系统、物流系统、支付系统,任何一个子系统出了故障,都会造成下单操作异常。
当转变成基于消息队列的方式后,系统间调用的问题会减少很多,比如物流系统因为发生故障,需要几分钟来修复。在这几分钟的时间里,物流系统要处理的内存被缓存在消息队列中,用户的下单操作可以正常完成。当物流系统恢复后,继续处理订单信息即可,下单用户感受不到物流系统的故障。提升系统的可用性。
异步处理
通过消息中间件,让两个操作由串行变为并行,提高吞吐量
假设用户注册需要发送邮件和发送注册短信,不使用消息队列,那么这些操作就是串行执行,用户注册所需要的时间,就是所有时间的总和。类似这样
但是如果使用消息队列,那发短信和发邮件可以并行处理
明显减少了总的处理时间
流量削锋
通过消息中间件,让需要处理的请求,先进入消息队列缓冲,然后在进行消费。
比如购物网站开展秒杀活动,一般由于瞬时访问量过大,服务器接收过大,会导致流量暴增,相关系统无法处理请求甚至崩溃。而加入消息队列后,系统可以从消息队列中取数据,相当于消息队列做了一次缓冲。
-
RabbitMQ如何保证消息不丢失?
问题回答
- 丢消息的情况有3种情况
-
- 生产者丢
- rabbitmq丢
- 消费端弄丢
- 如何保证消息不丢失,就是分别避免每一个环节丢失
-
- 保证生产者不丢消息
- 保证rabbitmq不丢消息
- 保证消费端不丢消息
- 保证生产者不丢消息,要确保说写rabbitmq的消息别丢,可以开启confirm模式。
-
- 每次写的消息都会分配一个唯一的id,如果写入了rabbitmq中,rabbitmq会给你回传一个ack消息,告诉你说这个消息ok了。
- 如果rabbitmq没能处理这个消息,会回调你一个nack接口,告诉你这个消息接收失败,我们可以重试。
- 保证rabbitmq不丢消息,开启rabbitmq的持久化(持久化queue和message)
-
- 消息写入之后会持久化到磁盘,假如rabbitmq挂了,恢复之后会自动读取之前存储的数据,一般数据不会丢。
- rabbitmq还没持久化,自己就挂了,可能导致少量数据会丢失的,但是这个概率较小。
- 持久化queue,在创建queue的时候将其设置为持久化的,这样就可以保证rabbitmq持久化queue的元数据,但是不会持久化queue里的数据;
- 持久化Message,在发送消息的时候将消息的deliveryMode设置为2,就是将消息设置为持久化的,此时rabbitmq就会将消息持久化到磁盘上去。
- 保证消费端不丢消息
-
- 依靠ack机制,简单来说,就是你关闭rabbitmq自动ack,通过一个api来手动ack就行,就是每次你自己代码里确保处理完的时候,在程序里ack一下。
-
辅助理解
1、看图