Fork me on GitHub

java基础之----RabbitMQ

概述

MQ也即是Message Queue,翻译就是消息队列,那何为消息队列就是存放消息的队列,为什么需要一个队列来存放这些消息,为什么不直接发送呢?举个例子,如果一个服务正常可以支持tps是1000,现在突然请求量达到5000,怎么办,有可能直接把服务器访问崩溃了,这时如果使用消息队列,就可以先把消息放到队列中,然后服务器慢慢处理,这叫做错峰处理,在我们实际的工作经验中,mq更多的是用在服务端需要长时间处理的场景中,因为http请求要求的时效性太高,如果服务端处理时间过长,就会导致很多的请求超时,而使用mq就可以解决这个问题。

消息队列的作用

上面概述中已经叙述了消息队列的部分功能,下面列举一下消息队列的详细作用。

  • 非实时性:当不需要立即获得结果,但是并发量又需要进行控制的时候,差不多就是需要使用消息队列的时候。主要解决了应用耦合、异步处理、流量削锋等问题。
  • 应用耦合:多应用间通过消息队列对同一消息进行处理,避免调用接口失败导致整个过程失败;(如:订单->库存)
  • 异步处理:多应用对消息队列中同一消息进行处理,应用间并发处理消息,相比串行处理,减少处理时间;(点对多场景,广播场景(注册发短信,发邮件)等等)
  • 限流削峰:应用于秒杀或抢购活动中,避免流量过大导致应用系统挂掉的情况;(根据服务承受度设置队列大小,超过了就返回活动结束了,咱们经常各大商城秒杀,心里还没有点B数吗)减少压力,避免服务挂掉。
  • 消息驱动的系统:系统分为消息队列、消息生产者、消息消费者,生产者负责产生消息,消费者(可能有多个)负责对消息进行处理;(分工处理(各自对应相应的队列),灵活应用(收到就处理/定时处理))

消息队列的缺点

  • 系统的复杂性提高
  • 系统可用性降低,一旦mq当机宕机,整个系统就无法使用了

RabbitMQ如何保证高可用

rabbitmq有三种模式:

  • 单机模式,这个不会在成产上使用
  • 简单集群模式,这种集群模式还是只有一个队列,但是消费者可以连接到不同的节点去消费,因为别的节点会保存一份这个队列的元数据信息,然后rabbitmq内部,把消息从这个队列先同步到别的节点,然后在发给消费者,如果存放消息的那个节点宕机了,那就玩完了,消费者无法在获取消息
  • 镜像集群模式:这种模式是rabbitmq实现的真正的高可用模式,这种模式是mq会把同一个队列复制多份,然后生产这发送的消息会同步到每个队列,也就是说多个节点,每个节点保留一份完整的消息。这样当某个节点挂机了,不影响其他节点继续提供服务。

具体参考,这个是石杉老师讲的:https://www.jianshu.com/p/d372ee0646f3

实现消息队列的两种模式

点对点:每个消息只有一个消费者,不可重复消费,而且消费完消息就从队列中清除。

发布\订阅:每条消息有多个消费者,比如微信的订阅功能,点击订阅之后就可以不定期的给你推送,这个还分pull模式和push模式。所谓的pull模式就是消费者主动去队列消费消息,而push模式是生产者将消息发到mq之后,mq服务端马上将这条消息投递给 Consumer,优劣很容易看出,消费者按照自己的能力去拿消息处理的方式肯定更好,这也是为什么消息队列基本都使用pull模式的原因。

常用的MQ对比

我使用过的消息队列有RabbitMQ,kafka,其他的消息队列,比如ActiveMQ,RocketMQ,这两个不太熟悉,不过大同小异。对每种消息队列的性能对比感兴趣读这篇文章:中间件对比----Kafka、ActiveMQ、RabbitMQ及RocketMQ性能对比

MQ技术选型

activemq:这个mq的优点是功能完备,单机的吞吐量是万级,延迟是毫秒级。缺点就是现在社区越来越不活跃,而且存在偶尔会丢消息的情况,目前在国内用的越来越少。

rabbitmq: 这个优点也是功能完备,有一个强大的后台管理界面,很多配置管理都可以通过这个完成,单机吞吐量也是万级,社区活跃度高,延迟是微秒级别。 缺点就是使用erlang语言写的,不容易看懂源码,很难定制化开发。

rocketmq: 这个优点是单机吞吐量达到10万级别,分布式,易于扩展,经过阿里大数据量消息吞吐的检验,质量有保证,适合高吞吐量的场景。缺点就是阿里的项目很可能就黄了,那到时候只能自己维护,需要有实力才可以使用。

kafka:这个优点是单机10万级别的吞吐量,分布式,易于扩展,高可用,在实时计算,日志处理等大数据场景非常合适。是大数据场景的规范。

MQ如何保证消息的幂等性

mq是不保证消息重复消费的,需要从业务上去保证,有两种方法,

第一种是把消息先生成一个key存到redis,然后每次消费消息的时候去redis检查一下

第二种是使用数据库的唯一索引保证

MQ消息丢失怎么处理

rabbitmq消息丢失有三种场景:

1.生产者发送消息到rabbitmq中,消息还没有存储到mq,在网络传输中消息就丢失了

解决方法:解决方法也有两种。

  • 具体使用事务的方式,在发送消息的时候开启事务,如果发送失败,会抛出异常,然后事务回滚就可以了。这个的缺点就是开启事务之后就会处于等待状态,无法发送下一条消息,变成同步发送了。api是一般是调用channal.txSelect.
  • 使用confirm机制,这个机制分为3中第一种是每发送一条消息就confirm一次,这种方式也是处于等待的状态,效率低下,api为:channel.waitForConfirms()。第二种方式是批量confirm,就是发送一批数据出去,如果mq返回说这一批都收到了,那只需要confirm一次,效率相对来说提高了,但是如果一批消息中有一个消息丢失,这批消息就需要全部重新发送一遍,api为:channel.waitForConfirmsOrDie()。第三种方式是真正的异步发送,这种方式通过回调函数实现的,就是说发送端需要维护一个发送序号列表,服务端每次回调的确认的时候需要知道确认的是那一条消息,所以就给每条消息设置了一个编号,即使1,2,3,4这样的编号,发送端收到编号之后,需要知道这些编号对应的是哪条消息,如果有异常才知道重发那一条消息,api为:channel.confirmSelect();。

具体参考:(10)RabbitMQ生产者确认:事务与confirm机制

2.rabbitmq自己挂掉了,保存到内存中的消息丢失了

解决方法:设置消息的持久化,就是将内存中的消息写到磁盘中,但是这样只是把队列的元数据写入到磁盘中,还需要发送消息的时候将deliveryMode设置为2才可以真正将消息持久化,但是这行仍然不能保证消息不丢失,比如,内存中消息还没有完全来得及写入磁盘,mq的那个节点挂了,那消息就丢失了。

3.消费者消费消息设置了自动确认,当消费了消息之后,消息还没有处理成功,就自动通知mq说已经处理完了,这个时候如何消费者挂了,消息就丢了。

解决方法:去掉自动确认机制,通过手动确认,即使等消息完全处理完之后在提交ack

RabbitMQ消息大规模积压怎么处理

这个首先第一点要保证生产环境mq不要设置消息的过期时间,如果设置了,那没办法,只能手动处理了,想办法把丢掉的消息找回来再写到mq,如果没有设置过期时间,而且积压了很多怎么处理呢?这种可以把原来mq的消费者代码修改一下,把原来队列中的消息写入多个新申请的队列中去,然后呢在多搞一点消费者从新队列中把消息处理掉。如果生产环境实在耽搁不起mq积压时间过长,那就没办法,只能直接先把积压的消息丢掉,先让mq回复正常,之后在把丢失的消息找回来。

RabbitMQ介绍

 组件介绍

Broker:也就是服务器实体

Publisher:生产者

Virtual Host:虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域,这里需要注意一下,Exchage,Queue是和Virtual Host绑定的,一个broker中可以有多个Virtual Host

Queue:存储消息的队列

Channel:信道,多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的 TCP 连接内地虚拟连接,AMQP 命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接

Consumer:消费者

Exchange:交换机,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。Exchange分为4中类型,direct,fanout,topic,headers,其中headers和direct交换器完全一致,但是性能比direct模式差很多,基本不用,所以直接看另外三种类型。

direct交换器

消息中的路由键(routing key)如果和 Binding 中的 binding key 一致,换器就将消息发到对应的队列中。它是完全匹配、单播的模式。

 

 fanout模式

这种模式叫广播模式,就是一条消息路由到多个队列,很像子网广播。这种模式是不区分路由键的。

 

 topic模式

topic 交换器通过模式匹配分配消息的路由键属性,其实这种模式和direct模式是一样的,不过direct模式是精确匹配,这个是模糊匹配,精确匹配那就只有一个队列了,模糊匹配就有可能匹配到多个队列。

 

 根据工作经验来看,使用direct和fanout模式比较多一点,第三种方式使用的不太多。

总结

总的来说rabbitmq还是挺简单的,很稳定,在中小型的服务中推荐使用,springboot中也集成了rabbitmq,使用起来更加简单。

 

参考文章:https://juejin.im/post/5b32044ef265da59654c3027

posted @ 2020-03-03 18:01  猿起缘灭  阅读(271)  评论(0编辑  收藏  举报