消息队列-面试点整理

消息队列

Rabbit MQ

高可用以及分布式
  1. 单机模式

  2. 普通集群模式

      通过扩展硬件的方式,提高节点的数量,在每个节点上维护其它节点的元数据信息.生产者在生产消息时,将消息放到其中一个节点.消费者在拉取数据时,通过连接的实例存储的元数据查找queue所在的节点信息,再从对应的节点上区拉取数据.
      优点: 可以通过扩展硬件机器的方式扩大集群的吞吐量. 多个节点来服务一个queue的读写操作
      缺点: 如果存放queue的节点宕机,数据会丢失.如果开启了消息持久化,则在节点重启的这个时间段内,无法从这个节点拉取数据.

  3. 镜像集群模式

      通过在不同节点维护queue副本的方式,来达到高可用.每当创建一个queue时,会将元数据信息以及queue信息同时同步到其它的节点.每次写消息时,也会将消息同步到其它的节点.
      优点: 保证了集群的高可用性,即使其中的一个节点宕机,其它的节点因为包含了所有的元数据和数据,同样也可以提供服务.
      缺点:
       1. 集群内部的网络压力和消耗严重
       2. 无法做到分布式的存储数据,如果遇到了单机queue数据量巨大,将无法处理.

消息投递确认方式

RabbitMQ 消息投递确认由两部分组成. Producer 投递到 Broker 确认 以及 Exchange 投递到Queue 确认

  1. Producer 投递到 Broker 确认: 通过ConfirmCallback 回调重新处理生产者投递失败的情况
  2. Exchange 投递到Queue 确认: 通过ReturnCallback 回调重新处理投递失败的消息

Kafka

高可用以及分布式

  kafka的高可用是由系统的基本架构来决定的.由多个 broker 组成,每个 broker 是一个节点;你创建一个topic,这个 topic 可以划分为多个 partition,每个 partition 可以存在于不同的 broker 上,每个partition 就放一部分数据。也就是说一个Topic的数据是分布存在多个broker中的,这是一个天然的布式存储系统.
   Kafka 0.8 以前没有HA(High Available),如果其中的一个broker宕机,则存储的数据都会丢失. Kafka 0.8以后提供了partition replica的方式,每个partitio 都会生成副本发送到其它的broker,同一个partition的所有副本内部还会选举一个leader,由这个leader 来进行数据的读写操作,保证数据的一致性.
   写数据阶段: 由leader将数据落盘,各个follower主动pull数据,各自落盘并向master报告ack,当全部的follower都ack成功,leader返回客户端消息投递成功.
  读数据阶段: 客户端只会从leader那里拉取数据,在所有follower都ack前,消息对于客户端是不可见的.

消息投递确认方式

由参数 request.required.acks 控制.

  1. 配置值 0, 只管投递,不管消息的有效性
  2. 配置值 1, 系统默认值,只要partition leader ack 则确认数据已经投递成功
  3. 配置值 -1, 需要所有的follower ack后则确认数据投递成功
消息幂等性

由参数enable.idempotence控制.

  1. 消息投递幂等性

    Kafka内部会为每个Producer 创建一个ID (PID),并在内部维护一个 <PID,Partition>->sequenceNum 映射信息.

    1. 如果接受到producer消息的sequenceNum等于维护的sequenceNum + 1 则接受并处理消息
    2. 如果接受到producer消息的sequenceNum小于维护的sequenceNum + 1 则丢弃消息
    3. 如果接受到producer消息的sequenceNum小于维护的sequenceNum + N 则说明中间有消息没有接受到消息,会抛出 OutOfOrderSequenceException 异常
  2. 消息处理幂等性

    由客户端自行处理

    1. 通过消息处理备忘录的方式,在某个地方存储消息是否被已经被消费,每次消费的时候先检查是否已经被消费
    2. 数据库幂等性可以通过唯一索引,或者操作前查询的方式确认是否可以插入
    3. Redis 操作set操作天然幂等性

引入消息队列产生的问题

数据丢失

1. 生产者数据丢失
  1. RabbitMQ
    1. 开启事务(channel.txSelect channel.txCommit). 如果消息投递失败,会报异常,捕获异常,在异常处理模块重新处理消息发送.缺点是性能消耗严重,吞吐量会下降
    2. 开启confirm 机制, RabbitMQ 会为每一个消息分配值一个唯一ID ,如果失败则会回调定义的nack接口,在这个接口中重新处理消息发送.这是一个异步的过程
  2. Kafka
    1. Kafka 开启 acks = all,所有的partition replica ack后再确认消息投递成功
2. 消息队列数据丢失
  1. RabbitMQ
    1. 开启消息的持久化,RabbitMQ自己宕机恢复后会自动读取之前存储的数据.极低的可能性出现还没有持久化,RabbitMQ宕机,这时会丢失少量数据.和Producer的confirm机制结合 可以保证即使在极端情况下出现的没有持久化就宕机时Producer可以自己铳发消息
    2. RabbitMQ 开启持久化,要同时开启queue持久化,和Producer 的消息持久化 (deliveryMode = 2)
  2. Kafka
    1. 在broker宕机并重新选举新leader的时候,原leader 的一些信息还没同步到follower中,则会丢失一部分数据
    2. 开启 acks = all ,所有的follower都ack后才同志producer 消息投递成功
    3. 设置partition的最小副本数量大于1 保证leader 所在broker宕机时最少有一个follower可以作为被选leader
3. 消费者数据丢失
  1. RabbitMQ
    1. 关闭消息消费自动确认,改为手动确认
  2. Kafka
    1. 关闭自动提交offset,改为手动提交offset.如果在消费数据结束后没来得及提交offset, 需要自己保证消费数据的幂等性

消息顺序性

可能场景

  mysql binlog 同步的系统,压力还是非常大的,日同步数据要达到上亿,就是说数据从一个 mysql 库原封不动地同步到另一个mysql 库里面去(mysql ->mysql)。常见的一点在于说比如大数据 team,就需要同步一个 mysql 库过来,对公司的业务系统的数据做各种复杂的操作。
  在 mysql 里增删改一条数据,对应出来了增删改 3 条 binlog 日志,接着这三条 binlog发送到 MQ 里面,再消费出来依次执行起码得保证人家是按照顺序来的吧?不然本来是:增加、修改、删除;你愣是换了顺序给执行成删除、修改、增加,不全错了么。本来这个数据同步过来,应该最后这个数据被删除了;结果你搞错了这个顺序,最后这个数据保留下来了,数据同步就出错了。

解决方法
  1. RabbitMQ 拆分queue 一个消费者对应一个queue,在queue内保持顺序
  2. Kafka producer在发送消息时指定规范的key值,消费者用内部队列分配N个队列存储不同的规则Key, 使用N个线程对数据进行消费

消息过期

Consumer 消费数据缓慢,导致数据在有效期内没被消费,消息丢列丢弃数据.最后数据丢失. 在高峰期过后,写程序将丢失的数据重新导入到消息队列中,让消息重新消费

消息堆积

可能场景

消费端每次消费之后要写 mysql,结果 mysql 挂了,消费端 hang 那儿了,不动了;或者是消费端出了个什么岔子,导致消费速度极其慢。

解决方法
  1. 修复出错的消费端代码
  2. 新增N个queue,将堆积的消息无耗时的转移到新建立的queue中
  3. 新增临时的消费端数量,对新增的queue进行消费
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码ge寂寞

谢谢老板,老板大气,老板入大厂

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值