(1)为什么使用消息队列啊?
核心的有3个:解耦、异步、削峰
(2)消息队列有什么优点和缺点啊?
优点:解耦、异步、削峰
缺点:
增加系统复杂度;
增加系统故障率;
某个消费者失败会有数据一致性问题。
如何保证消息队列的高可用啊?
kafka:多个broker组成,每个broker是一个节点;每个topic是一类消息,分为多个partition在不同的broker上,每个partition就放一部分数据。
分布式消息队列,一个topic的数据分散放在多个机器上的,每个机器就放一部分数据。
kafka 提供replica副本机制保证HA。每个partition都会同步到其他机器上,形成自己的多个replica副本,提高了容错性。所有replica选举一个leader出来负责生产和消费,其他replica就是follower。leader会把写的数据同步到所有follower上去,读直接读leader上数据。
kafka会均匀的将一个partition的所有replica分布在不同的机器上,这样才可以提高容错性。
每组多副本的partition会选举一个leader
多副本+leader选举形成了高可用性。
如何保证消息不被重复消费啊(如何保证消息消费时的幂等性)?
使用消息队列如何保证幂等性,这是架构里要考虑的一个问题。需要结合具体的业务来看
rabbitmq、kafka,都有可能会出现消费重复消费的问题。mq无法自己保证的,是程序逻辑给保证的。
一条数据重复出现两次,数据库里就只有一条数据,这就保证了系统的幂等性
怎么保证消息队列消费的幂等性?
(1)消费时基于数据库的唯一键来保证重复数据不会重复插入多条
(2)消费时写redis,没问题了,反正每次都是set,天然幂等性
(3)消费时通过全局唯一id查看是否消费过,消费后写状态或redis
消费时通过全局唯一id查db或redis是否消费过,查无消费后写状态或redis
6如何保证消息的可靠性传输(如何处理消息丢失的问题)?
用mq有个基本原则,数据不能多一条,也不能少一条。不能多,就是重复消费和幂等性问题。不能少,就是数据不能搞丢了。
丢数据,mq一般分为两种,1mq自己弄丢了,2消费的时候弄丢了。
(1)rabbitmq
1)生产者弄丢了数据
生产者发送数据搞丢了。
1可以开启rabbitmq事务机制,但同步阻塞消耗性能吞吐量低。
2可以开启confirm模式,生产者确认模式,来判断成功或者重试发送。confirm机制是异步的,异步回调应答。
一般在生产者避免数据丢失,都是用confirm机制的。
Confirm 确认。证实,证明。
2)rabbitmq弄丢数据
为防止rabbitmq自己弄丢了数据,必须开启rabbitmq的持久化。极小的概率没来得及持久化就挂了,会导致内存里的一点点数据会丢失。
3)消费端弄丢了数据
刚从rabbitmq消费到,还没处理,结果进程挂了,rabbitmq认为你都消费了,这数据就丢了。
rabbitmq提供消费者ack机制,关闭自动ack,处理完消费手动调用ack。rabbitmq把消费分配给别的consumer去处理,这里要考虑幂等性问题
(2)kafka
- 消费端弄丢了数据
消费端在处理完消息后手动提交offset。如果处理完还没提交offset进程挂了,要保证幂等性。
消费到了消息,自动提交offset, kafka以为已消费,没处理就挂了,消息丢失。
关闭自动提交offset,在处理完消息手动提交offset,可以保证数据不会丢。会有重复消费,比如刚处理完没提交offset,进程挂了,要自己保证幂等性。
生产环境碰到的问题,kafka消费者消费到了数据之后是写到一个内存的queue里先缓冲一下,消费者会自动提交offset。此时重启系统,会导致内存queue里还没来得及处理的数据丢失。
2)kafka弄丢了数据
新选举的leader还没同步挂掉leader的数据,就会丢了一些数据啊。(生产会遇到过follower切换为leader之后会丢失一些数据)
进行leader切换时,数据不会丢失 设置如下4个参数:
1每个partition必须有至少2个副本,
2确保leader至少感知有一个follower,
3acks=all 所有replica副本写入才算写成功,
4一旦写入失败就不断重试,卡在这里retries=MAX
如果设置ack=all,生产者会动重试,直到所有写入
(7)如何保证消息的顺序性?
消息是有先后顺序的:增加、修改、删除;顺序变了最终结果就不一样
1 )rabbitmq:拆分多个queue,每个queue一个consumer,consumer按keyid写N个内存queue,,然后N个线程分别消费一个内存queue即可。
2)kafka:一个topic,一个partition,一个consumer,内部单线程消费,按keyid写N个内存queue,然后N个线程分别消费一个内存queue即可。
(8)如何解决消息队列的延时以及过期失效问题?
消费端不消费了,或者消费缓慢。大量消息积压在mq里。
(1)大量消息在mq里积压了几个小时了还没解决
1在数量不太多的时候修复consumer ,让程序自己缓慢恢复。
2数据量超大,修复consumer,紧急扩容 ,用以前十倍的partition 同时将consumer实例和consume queuer(内存队列)扩大十倍,消费完挤压数据恢复到原先部署架构。
(2)如果rabbitmq超时数据已经清理丢失。等过了高峰期批量重导。将丢失的数据,写个临时程序查出来,重新灌入mq里面去,把数据给他补回来。
(3)消息积压在mq里,很长时间都没处理掉,此时导致mq都快写满了,临时写程序消费一个丢弃一个,快速消费掉所有消息。然后走第二个方案,到了晚上再补数据。