原文:https://adjava.netlify.app/#/./docs/high-concurrency/why-mq
为什么要用MQ队列?
1.解耦
比如消息推送,中台配置好后把消息推送到MQ,谁需要消费就谁去MQ里拿,如app或者微信
2.异步
比如发送邮件,点击批量发送之后发送MQ同时返回成功给前端,节省等待时间
3.削峰
请求量过大会导致数据库挂掉,这时候可以用MQ接收,每次只给数据库一部分,多余的先积压在MQ里
但是用MQ也有缺点,多了一个外部组件就要维护它,会使系统的复杂度提高,而且异步会直接返回成功给前端,但实际还没成功,而且MQ挂了也会让系统奔溃
市面上主流的MQ有什么优缺点:
1.ActiveMQ:吞吐量万级,时效性秒级,基于主从架构实现高可用,社区不活跃,基本弃用
2.RabbitMQ:吞吐量万级,时效性毫秒级,基于主从架构,社区活跃,基于erlang开发
3.RocketMQ:吞吐量十万级,时效性秒级,分布式架构,可支持多topic,扩展性较强,但已捐给Apache,基于java语言
4.Kafka:吞吐量十万级,时效性秒级,分布式架构,topic太多会导致吞吐量下降,功能较为简单,基于scala和java语言
如何保证消息队列的高可用
RabbitMQ有三种策略模式:单机模式、普通集群模式、镜像集群模式
单机模式:自己写Demo的时候用用,在生产上不会用到
普通集群模式(无高可用):就是在多台服务器都部署同样的MQ,但是创建的队列只会在一个MQ实例上,如果那个MQ宕机了,其他实例就获取不到那个实例的数据了
镜像集群模式(高可用):创建的队列会同步到所有的MQ实例上,每个MQ节点都有完整的镜像,也就是所有的数据。好处是一台服务器宕机了还有其他服务器可用,缺点是开销太大,每台服务器都要同步,而且不是分布式的,扩展性较差
Kafka的高可用:是分布式的,broker、topic、partition
如何保证消息不被重复消费(幂等)
1.插数据之前用数据库表的主键去查一下,如果有了就不重复消费
2.用Redis,Redis的set天然能保证幂等
3.生产者的每条数据都生成唯一的id,消费过了就记录这个id
如何保证消息的可靠性传输
弄丢数据有3种可能:
1.生产者弄丢了:开启confirm模式,发送成功或者失败都有个响应,保证传输失败之后可以重发
2.RabbitMQ弄丢了:消息持久化,挂了之后重启也能重新发送
3.消费者弄丢了:关闭MQ的自动ack机制,让消费者确认消费完了消息再通知MQ删除消息
如何保证消息的顺序性
一个队列对应一个消费者,在消费者内部进行排队
如何解决消息队列的延时以及过期失效问题?
从根本上来看都是consumer引发的问题
1.大量消息积压在MQ里几小时还没解决:consumer临时扩容,先在多个服务器上多部署几个consumer,加快消耗消息的速度
2.mq 中的消息过期失效了:只能手动重新导入数据到MQ
优化方案:跳过非重要消息