学习笔记:MQ的一些面试题的思考
MQ的一些面试题
1、为什么要用消息中间件
1.1系统解耦合
假如A系统的一些信息,下游有系统需要使用,难道每次都开发新的接口?这时候明显不合理,这个时候就把数据发送到MQ,有需要的系统自己去取,不需要的取消订阅/消费就行了。
1.2异步调用
假设你有一个系统调用链路,是系统A调用系统B,一般耗时20ms;系统B调用系统C,一般耗时200ms;系统C调用系统D,一般耗时2s,如果A调用之后是同步调用,那么一次请求就非常耗时,我们可以将C调用D的请求做成异步的,用MQ去通知,这样对于A来说,感官上没有区别,但是实际却减少了系统负担,提高执行性能。
1.3流量削峰
如果业务场景允许异步削峰,高峰期积压一些请求在MQ里,然后高峰期过了,后台系统在一定时间内消费完毕不再积压的话
2、如何保证消息不丢失
MQ丢消息一般是2种情况,一个是消费超时,一个是MQ丢消息了。下面总结一下rabbitmq和kafka的这种场景是如何处理的。
2.1 rabbitmq
开启持久化到磁盘,这样如果mq挂了,恢复之后会自动读取之前存储的数据,一般数据不会丢失。除非极其罕见的情况,rabbitmq还没来得及持久化自己就挂了,这样可能导致一部分数据丢失。
消费者这边,将autoAck关闭
// 监听队列,手动返回完成
channel.basicConsume(QUEUE_NAME, false, consumer);
确定自己处理完了之后再发送ack给生产者
// 返回确认状态 channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
2.2 kafka
A:丢失数据的情况:
生产者弄丢了数据
生产者没有设置相应的策略,发送过程中丢失数据。
B:kafka弄丢了数据
比较常见的一个场景,就是kafka的某个broker宕机了,然后重新选举partition的leader时。如果此时follower还没来得及同步数据,leader就挂了,然后某个follower成为了leader,他就少了一部分数据。
C:消费者弄丢了数据
消费者消费到了这个数据,然后消费之自动提交了offset,让kafka知道你已经消费了这个消息,当你准备处理这个消息时,自己挂掉了,那么这条消息就丢了。
如何避免?
A:消费端弄丢了数据
关闭自动提交offset,在自己处理完毕之后手动提交offset,这样就不会丢失数据。
B:kafka弄丢了数据
一般要求设置4个参数来保证消息不丢失:
①给topic设置 replication.factor参数:这个值必须大于1,表示要求每个partition必须至少有2个副本。
②在kafka服务端设置min.isync.replicas参数:这个值必须大于1,表示 要求一个leader至少感知到有至少一个follower在跟自己保持联系正常同步数据,这样才能保证leader挂了之后还有一个follower。
③在生产者端设置acks=all:表示 要求每条每条数据,必须是写入所有replica副本之后,才能认为是写入成功了
④在生产者端设置retries=MAX(很大的一个值,表示无限重试):表示 这个是要求一旦写入事变,就无限重试
C:生产者弄丢了数据
如果按照上面设置了ack=all,则一定不会丢失数据,要求是,你的leader接收到消息,所有的follower都同步到了消息之后,才认为本次写成功了。如果没满足这个条件,生产者会自动不断的重试,重试无限次。
参考文档:https://www.jianshu.com/p/8ed16edc73e4