美文网首页
消息队列-1 五问

消息队列-1 五问

作者: NeXt4 | 来源:发表于2020-12-05 15:35 被阅读0次

01 如何保证消息不丢失

三个阶段,发送消息,存储消息,消费消息

发送消息阶段

到消息服务器,有同步发送和异步发送两种方式,只要处理好消息服务器的ack就可以保证消息成功发送到了服务器,没有ack或者发生异常,进行重试发送。

存储消息阶段

消息服务器收到消息后,返回ack给消息生产者,这也有几种情况,一种是收到消息还没持久化就返回ack,这时如果消息服务器宕机那么就会导致消息丢失。另一种是等消息刷盘之后再返回ack给消息生产者,那么消息就不会丢失。

如果是消息集群模式,则需要配置消息至少写入两台服务器再给生产者响应。这样基本就保证了消息存储阶段的可靠性。

消费消息阶段

需要在消费者处理业务逻辑完成之后再给消息服务器响应。

消息可靠性提高了,性能就会下降,消息同步刷盘,多副本同步都会影响消息队列的性能,需要看场景选择合理的配置。

02 如何保证高可用

RabbitMQ基于主从模式实现高可用

RabbitMQ有三种模式:单机模式,普通集群模式,镜像集群模式。

单机模式:单机模式就是demo级别的,生产中不会有人使用。

普通集群模式:普通集群模式就是在多台机器上启动多个rabbitmq实例,每个机器启动一个。但是创建的queue只会放在一个rabbitmq实例上面,但是其他的实例都同步了这个queue的元数据。在你消费的时候,如果连接到了另一个实例,他会从拥有queue的那个实例获取消息然后再返回给你。

这种方式并没有做到所谓消息的高可用,就是个普通的集群,这样还会导致要么消费者每次随机连接一个实例然后拉取数据,这样的话在实例之间会产生网络传输,增加系统开销,要么固定连接那个queue所在的实例消费,这样会导致单实例的性能瓶颈。

而且如果那个放消息数据的queue的实例宕机了,会导致接下来其他实例都无法拉取数据;如果没有开启消息的持久化会丢失消息;就算开启了消息的持久化,消息不一定会丢,但是也要等这个实例恢复了,才可以继续拉取数据。 所以这个并没有提供高可用,这种方案只是提高了吞吐量,也就是让集群中多个节点来服务某个queue的读写操作。

镜像集群模式:这种模式,才是rabbitmq提供是真正的高可用模式,跟普通集群不一样的是,你创建的queue,无论元数据还是queue里面是消息数据都存在多个实例当中,然后每次写消息到queue的时候,都会自动把消息到多个queue里进行消息同步。

这种模式的好处在于,任何一台机器宕机了,其他的机器还可以使用。

坏处在于: 1、性能消耗太大,所有机器都要进行消息的同步,导致网络压力和消耗很大。2、没有扩展性可言,如果有一个queue负载很重,就算加了机器,新增的机器还是包含了这个queue的所有数据,并没有办法扩展queue。

Kafka高可用

kafka的一个基本架构:多个broker组成,一个broker是一个节点;你创建一个topic,这个topic可以划分成多个partition,每个partition可以存在于不同的broker上面,每个partition存放一部分数据。这是天然的分布式消息队列。

实际上rabbitmq并不是分布式消息队列,他就是传统的消息队列,只不过提供了一些集群、HA的机制而已,因为无论如何配置,rabbitmq一个queue的数据就存放在一个节点里面,镜像集群下,也是每个节点都放这个queue的全部数据。

kafka在0.8以前是没有HA机制的,也就是说任何一个broker宕机了,那个broker上的partition就丢了,没法读也没法写,没有什么高可用可言。

kafka在0.8之后,提过了HA机制,也就是replica副本机制。每个partition的数据都会同步到其他机器上,形成自己的replica副本。然后所有的replica副本会选举一个leader出来,那么生产者消费者都和这个leader打交道,其他的replica就是follower。写的时候,leader会把数据同步到所有follower上面去,读的时候直接从leader上面读取即可。

kafka会均匀地将一个partition的所有数据分布在不同的机器上,这样就可以提高容错性。 如果某个broker宕机了,那个broker的partition在其他机器上有副本,如果这上面有某个partition的leader,那么此时会重新选举出一个新的leader出来,继续读写这个新的leader即可。

写消息: 写数据的时候,生产者就写leader,然后leader将数据落到磁盘上之后,接着其他follower自己主动从leader来pull数据。一旦所有follower同步好了数据,就会发送ack个leader,leader收到了所有的follower的ack之后,就会返回写成功的消息给消息生产者,这只是一种模式,可以调整。

读数据: 消费数据的时候,只会从leader进行消费。但是只有一个消息已经被所有follower都同步成功返回ack的时候,这个消息才会被消费者读到。

03 如何处理重复消息

消息为什么会重复?

发送消息失败,比如接收ack时网络问题导致消息生产者重试发送。或者,消息消费者处理完业务逻辑,执行ack失败或者消费者自己宕机了,那么这条消息又会发送给另一个消费者,消息重复。

如何处理?

使用幂等,比如我们给每条消息都设置一个全局唯一的id,消费者处理完这条消息同时存储这条消息的全局id,可以存储到redis或者mysql中,每次消费消息时都找查询一下,如果有记录也说明已经处理过了,直接丢弃即可。

04 如何保证消息的有序性

有序分为全局有序和部分有序

如果要保证消息的全局有序,首先只能由一个生产者往Topic发送消息,并且一个Topic内部只能有一个队列(分区)。消费者也必须是单线程消费这个队列。这样的消息就是全局有序的!

不过一般情况下我们都不需要全局有序,即使是同步MySQL Binlog也只需要保证单表消息有序即可。

因此绝大部分的有序需求是部分有序,部分有序我们就可以将Topic内部划分成我们需要的队列数,把消息通过特定的策略发往固定的队列中,然后每个队列对应一个单线程处理的消费者。这样即完成了部分有序的需求,又可以通过队列数量的并发来提高消息处理效率。

05 如何处理消息堆积

水平扩容,增加Topic的队列数和消费者数量,队列数一定要增加。一个Topic中,一个队列只会分配给一个消费者。

当然你消费者内部是单线程还是多线程消费那看具体场景。不过要注意上面提到的消息丢失的问题,如果你是将接受到的消息写入内存队列之后,然后就返回响应给Broker,然后多线程向内存队列消费消息,假设此时消费者宕机了,内存队列里面还未消费的消息也就丢了。

相关文章

  • 消息队列-1 五问

    01 如何保证消息不丢失 三个阶段,发送消息,存储消息,消费消息 发送消息阶段 到消息服务器,有同步发送和异步发送...

  • 消息队列如何解决消息丢失问题?如何保证消息的顺序性?消息积压问题

    消息队列经典十连问: 1.什么是消息队列? 2.消息队列的应用场景? 3.消息队列如何解决消息丢失问题? 4.消息...

  • 消息队列1:消息队列概述

    最近在看消息队列,找了好多资料。终于能够简单的理解了消息队列。 维基百科定义 消息队列(英语:Message qu...

  • java消息机制

    1.什么是消息队列? 1.消息队列是一个队列,先进先出,你无法读取消息队列中间的消息,只能按照顺序,从消息队列的头...

  • 消息队列对比

    引用: 常用消息队列对比消息队列及常见消息队列介绍 常用消息队列 1. RabbitMQ 用erlang语言开发的...

  • 消息队列1

    什么是队列系统? 可以把队列和栈还有堆想象成一个容器, 队列其实就是我们通常说的排队,可以想象成一个两端开口的容器...

  • PHP消息队列实现及应用

    1. 消息队列概念 消息队列其实就是队列结构的中间件 (1). 队列结构的中间件 (2). 消息放入后,不需要立即...

  • 信息队列

    消息队列 (1)为什么使用消息队列啊?消息队列有什么优点和缺点啊?kafka、activemq、rabbitmq、...

  • 面试官心理分析+面试题剖析:消息队列+Redis 缓存+分布式系

    消息队列 1、为什么使用消息队列?消息队列有什么优点和缺点?Kafka、ActiveMQ、RabbitMQ、Roc...

  • RabbitMQ 之 安装配置用户权限

    1. 消息队列(Message queue) 消息队列是在消息传递过程中保存消息的容器,通过消息队列可以使用消息将...

网友评论

      本文标题:消息队列-1 五问

      本文链接:https://www.haomeiwen.com/subject/orjgwktx.html