消息中间件面试考点
RabbitMQ
RabbitMQ-如何保证消息不丢失
生产者确认机制:RabbitMQ提供了publisher confirm机制来避免消息发送到MQ过程中丢失。消息发送到MQ以后,会返回一个结果给发送者,表示消息是否处理成功
消息失败之后如何处理呢?
- 回调方法及时重发
- 记录日志
- 保存到数据库然后定时发送,成功发送后即刻删除表中的数据
消息持久化:MQ默认是内存存储消息,开启持久化功能可以确保缓存在MQ中的消息不丢失。交换机持久化,队列持久化,消息持久化
消费者确认:RabbitMQ支持消费者确认机制,即:消费者处理消息后可以向MQ发送ack回执,MQ收到ack回执后才会删除消息。而SpringAMQP则允许配置三种确认模式:
- manual:手动ack,需要在业务代码结束后,调用api发送ack
- auto:自动ack,由spring监听listner代码是否出现异常,没有异常则返回ack;抛出异常则返回nack
- none:关闭ack,MQ假定消费者获取消息后会成功处理,因此消息投递后立即被删除
Spring的retry和机制:在消费者出现异常时利用本地重试,设置重试次数,当次数达到了以后,如果消息依然失败,将消息投递到异常交换机,交由人工处理
RabbitMQ消息的重复消费问题如何解决
解决方案:
- 每条消息设置一个唯一的标识id
- 幂等方案:【分布式锁、数据库锁(悲观锁、乐观锁)】
RabbitMQ中死信交换机?(RabbitMQ延迟队列有了解过嘛?)
延迟队列=私信交换机+TTL
死信交换机:当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter):
- 消费者使用basic.reject或basic.nack声明消费失败,并且消息的requeue参数设置为false
- 消息是一个过期消息,超时无人消费
- 要投递的队列消息堆积满了,最早的消息可能成为死信
如果该队列配置了dead-letter-exchange属性,指定了一个交换机,那么队列中的死信就会投递到这个交换机中,而这个交换机称为死信交换机(Dead Letter Exchange,简称DLX)
TTL:Time-To-Live,如果一个队列中的信息TTL结束仍未消费,则会变为死信,ttl超市分为两种情况:
- 消息所在的队列设置了存活时间
- 消息本身设置了存活时间
延迟队列插件:DelayExchange插件,需要安装在RabbitMQ中
RabbitMQ如果有100万消息堆积在MQ,如何解决(消息堆积怎么解决)
解决消息堆积有三种思路:
- 增加更多消费者,提高消费速度
- 在消费者内开启线程池加快消息处理速度
- 扩大队列容积,提高堆积上限,采用惰性队列
惰性队列
惰性队列的特征如下:
- 接收到消息后直接存入磁盘而非内存
- 消费者要消费消息时才会从磁盘中读取并加载到内存
- 支持数百万条的消息存储
RabbitMQ的高可用机制有了解过嘛?
普通集群:标准集群,具备下列特征
- 会在集群的各个节点间共享部分数据,包括:交换机、队列元信息。不包含队列中的消息。
- 当访问集群某个节点时,如果队列不在该节点,会从数据所在节点传递到当前节点并返回
- 队列所在节点宕机,队列中的消息就会丢失
镜像集群:主从模式,具备下列特征
- 交换机、队列、队列中的消息会在各个mq镜像节点之间同步备份
- 创建队列的节点被称为该队列的主节点,备份到的其他节点叫做该队列的镜像节点
- 一个队列的主节点可能是另外一个队列的镜像节点
- 所有操作都是主节点完成,然后同步给镜像节点
- 主宕机后,镜像节点会替代成新的主
仲裁队列:是3.8版本后才有的新功能,用来替代镜像队列,具备下列特征
- 与镜像队列一样,都是主从模式,支持主从数据同步
- 使用非常简单。没有复杂的配置
- 主从同步基于Raft协议,强一致
@Bean
public Queue quorumQueue(){
return QueueBuilder
.durable("quorum.queue")//持久化
.quorum()//仲裁队列
.build();
}
Kafka
Kafka是如何保证消息不丢失
生产者发送消息到Brocker丢失
- 发送确认机制acks
确认机制 | 说明 |
---|---|
acks=0 | 生产者在成功写入消息之前不会等待任何来自服务器的响应,消息有丢失的风险,但速度最快 |
acks=1(默认值) | 只要集群首领节点收到消息,生产者就会收到一个来自服务器的响应 |
acks=all | 只有当所有参与赋值的节点全部收到消息时,生产者才会受到一个来自服务器的成功响应 |
消费者从Brocker接收消息丢失
- Kafka中的分区机制指的是将每个主题划分成多个分区(Partition)
- topic分区中消息只能由消费者组中的唯一一个消费者处理,不同的分区分配给不同的消费者(同一个消费组)
Kafka中消息的重复消费问题如何解决的
- 关闭自动提交偏移量,开启手动提交偏移量
- 提交方式,最好是同步+异步提交
- 幂等方案
Kafka是如何保证消息的顺序性
问题原因:一个topic的数据可能存储在不同的分区中,每个分区都有个按照顺序存储的偏移量,如果消费者关联了多个分区不能保证顺序性。
解决方案:发送消息时指定分区号,发送消息时按照相同的业务设置相同的key
Kafaka的高可用机制有了解过嘛
集群模式
- Kafka的服务器端被称为Broker的服务进程构成,即一个Kafka集群由多个Broker组成
- 这样如果集群中某一台机器宕机,其他机器上的Broker也依然能够对外提供服务。这其实也就是Kafka提高高可用的手段之一
分区备份机制
- 一个topic有多个分区,每个分区有多个副本,其中有一个leader,其余的时follower,副本存储不同的broker中
- 所有的分区副本的内容都是相同的,如果leader发生故障时,会自动将其中一个follower提升为leader
ISR:需要同步复制保存的follwer
如果leader失效后,需要选出新的leader,选举的原则如下:
第一:选举时优先从ISR中选定,因为这个列表中follower的数据是与leader同步的
第二:如果ISR列表中的follower都不行了,就只能从其它follower选取
Kafka数据清理机制了解过嘛
Kafka文件存储机制
存储结构
为什么要分段?
- 删除无用文件方便,提高磁盘利用率
- 查找数据便捷
数据清理机制
日志的清理策略有两个:
- 1.根据消息的保留时间,当纤细在Kafka中保存的时间超过了指定时间,就会触发清理过程
- 根据topic存储的数据大小,当topic所占的日志文件大小大于一定的阈值,则开始删除最久的消息。需手动开启
Kafka中实现高性能的设计有了解过嘛
- 消息分区:不受单台服务器的限制,可以不受限的处理更多的数据
- 顺序读写:磁盘顺序读写,提升读写效率
- 页缓存:把磁盘中的数据缓存到内存中,把对磁盘的访问变为对内存的访问
- 零拷贝:减少上下文切换及数据拷贝
- 消息压缩:减少磁盘IO和网络IO
- 分批发送:将消息打包批量发送,减少网络开销
零拷贝