消息队列

使用场景:

  • 解耦:多个子系统不直接通讯,而是通过MQ
  • 异步:
  • 削峰:将同一时间过来的大量请求放入MQ里面,然后慢慢拉取消化

优点:解耦、异步、削峰

缺点

  • 如何保证高可用?(MQ系统崩溃了怎么办)
  • 系统复杂度提高(如何保证消息不被重复消费、消息不丢失、消息传递的顺序性)
  • 数据一致性问题

常用的MQ:

  • Kafka
  • ActiveMQ
  • RabbitMQ
  • RocketMQ

如何保证消息队列的高可用

  • 以Kafka为例
  1. Kafka由多个 broker 组成,每个 broker 就是一个节点
  2. 当创建一个topic(主题),这个 topic 可以划分为多个 partition(分割),每个 partition 可以存在于不同的 broker 上,每个 partition 就放一部分数据。
  3. 每个 partition 的数据都会都会通过副本机制同步到其它机器上,形成自己的多个 replica 副本。
  4. 所有 replica 会选举一个 leader 出来,那么生产和消费都跟这个 leader 打交道,然后其他 replica 就是 follower
  5. 写的时候,leader 会负责把数据同步到所有 follower 上去,读的时候就直接读 leader 上的数据即可。只能读写 leader

这就是天然的分布式消息队列,就是说一个 topic 的数据,是分散放在多个机器上的,每个机器就放一部分数据

如何保证消息不被重复消费(幂等性)

  • 一条数据重复出现两次,数据库里就只有一条数据,这就保证了系统的幂等性。
  • 比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了,update 一下好吧。
  • 比如你是写 Redis,那没问题了,反正每次都是 set,天然幂等性。
  • 比如你不是上面两个场景,那做的稍微复杂一点,你需要让生产者发送每条数据的时候,里面加一个全局唯一的 id,类似订单 id 之类的东西,然后你这里消费到了之后,先根据这个 id 去比如 Redis 里查一下,之前消费过吗?如果没有消费过,你就处理,然后这个 id 写 Redis。如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。
  • 比如基于数据库的唯一键来保证重复数据不会重复插入多条。因为有唯一键约束了,重复数据插入只会报错,不会导致数据库中出现脏数据。

如何保证消息的可靠性传输(消息丢失的问题)

  • kafka弄丢数据解决方案:
  1. 给 topic 设置 replication.factor 参数:这个值必须大于 1,要求每个 partition 必须有至少 2 个副本。
  2. 在 Kafka 服务端设置 min.insync.replicas 参数:这个值必须大于 1,这个是要求一个 leader 至少感知到有至少一个 follower 还跟自己保持联系,没掉队,这样才能确保 leader 挂了还有一个 follower
  3. 在 producer 端设置 acks=all:这个是要求每条数据,必须是写入所有 replica 之后,才能认为是写成功了
  4. 在 producer 端设置 retries=MAX(很大很大很大的一个值,无限次重试的意思):这个是要求一旦写入失败,就无限重试,卡在这里

这样配置之后,至少在 Kafka broker 端就可以保证在 leader 所在 broker 发生故障,进行 leader 切换时,数据不会丢失。

  • 生产者丢失数据:
  1. 当上面设置了 acks=all,就不存在生产者丢失数据的情况
  • 消费端丢失数据:
  1. Kafka 会自动提交 offset,那么只要关闭自动提交 offset,在处理完之后自己手动提交 offset,就可以保证数据不会丢
  2. 但是此时确实还是可能会有重复消费,比如你刚处理完,还没提交 offset,结果自己挂了,此时肯定会重复消费一次,自己保证幂等性就好了

如何保证消息的顺序性

  • 以 Kafka 为例
  1. 写 N 个内存 queue,具有相同 key 的数据都到同一个内存 queue;
  2. 然后对于 N 个线程,每个线程分别消费一个内存 queue 即可,这样就能保证顺序性。

如果让你写一个消息队列,该如何进行架构设计

  • 首先这个 mq 得支持可伸缩性吧,就是需要的时候快速扩容,就可以增加吞吐量和容量,那怎么搞?设计个分布式的系统呗,参照一下 kafka 的设计理念,broker -> topic -> partition,每个 partition 放一个机器,就存一部分数据。如果现在资源不够了,简单啊,给 topic 增加 partition,然后做数据迁移,增加机器,不就可以存放更多数据,提供更高的吞吐量了?

  • 其次你得考虑一下这个 mq 的数据要不要落地磁盘吧?那肯定要了,落磁盘才能保证别进程挂了数据就丢了。那落磁盘的时候怎么落啊?顺序写,这样就没有磁盘随机读写的寻址开销,磁盘顺序读写的性能是很高的,这就是 kafka 的思路。

  • 其次你考虑一下你的 mq 的可用性啊?这个事儿,具体参考之前可用性那个环节讲解的 kafka 的高可用保障机制。多副本 -> leader & follower -> broker 挂了重新选举 leader 即可对外服务。

  • 能不能支持数据 0 丢失啊?可以的,参考我们之前说的那个 kafka 数据零丢失方案。

参考:

  1. 消息队列

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值