作用
1.应用解耦
2.异步处理
3.流量削峰
4.日志处理
5.消息通讯
不足
1.系统可用性降低: 系统可用性在某种程度上降低,为什么这样说呢?在加入MQ之前,你不用考虑消息丢失或者说MQ挂掉等等的情况,但是,引入MQ之后你就需要去考虑了!
2.系统复杂性提高: 加入MQ之后,你需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题!
3.一致性问题: 我上面讲了消息队列可以实现异步,消息队列带来的异步确实可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息怎么办?这样就会导致数据不一致的情况了!
如何保证高可用
集群 镜像模式
单纯集群只会有一条queue,多台机器访问同一台机器的queue只是提高了吞吐量。
主从复制(镜像模式)则会把消息复制到所有或者某几个queue中,单独某个或者某几个挂了不会影响可用性,只是会增加网络带宽的压力和复制时的时间。
如何保证幂等性
给消息一个唯一key
1.数据库先查询,存在直接update
2.数据库设置唯一主键
3.redis的set自带去重
4.其他情况可以存在redis,消费时先查询redis中是否存在
可靠性
https://blog.csdn.net/alinshen/article/details/80583214
1.生产者弄丢数据
transaction和confirm模式
transaction类似事务,丢失可以回滚,但是会使吞吐量下降
confirm模式用的较多,信道上面发布的消息都将会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后,rabbitMQ就会发送一个Ack给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了.如果rabiitMQ没能处理该消息,则会发送一个Nack消息给你,你可以进行重试操作。
2.消息队列丢数据
开启持久化,和confirm配合使用。
持久化成功后才返回ack。
3.消费者丢数据
自动消息确认改为手动消息确认
有序性
分析:其实并非所有的公司都有这种业务需求,但是还是对这个问题要有所复习。
回答:针对这个问题,通过某种算法,将需要保持先后顺序的消息放到同一个消息队列中(kafka中就是partition,rabbitMq中就是queue)。然后只用一个消费者去消费该队列。
有的人会问:那如果为了吞吐量,有多个消费者去消费怎么办?
这个问题,没有固定回答的套路。比如我们有一个微博的操作,发微博、写评论、删除微博,这三个异步操作。如果是这样一个业务场景,那只要重试就行。比如你一个消费者先执行了写评论的操作,但是这时候,微博都还没发,写评论一定是失败的,等一段时间。等另一个消费者,先执行写评论的操作后,再执行,就可以成功。
总之,针对这个问题,我的观点是保证入队有序就行,出队以后的顺序交给消费者自己去保证,没有固定套路。