再次总结RabbitMQ和Kafka(重点)

目录

Kafka基本组件概念

kafka基本架构图

partition

Kakfa怎么保证其高可用?

Kafka消息重复怎么解决?

消息丢失怎么办(主要针对RabbitMQ和Kafka)?

保证生产者不丢失消息:

保证MQ不丢失消息:

保证消费者不会丢失消息:

怎么保证MQ中的消息按顺序进行消费?

RabbitMQ

Kafka

消息队列其他问题

如何快速处理挤压过多的消息?

如果消息队列满了怎么处理?

如果让你开发消息队列中间件,如何来设计?

参考:https://github.com/doocs/advanced-java.git

Kafka基本组件概念

  1. broker:Kafka 服务器,负责消息存储和转发
  2. topic:消息类别,Kafka 按照 topic 来分类消息
  3. partition:topic 的分区,一个 topic 可以包含多个 partition,topic 消息保存在各个partition 上
  4. offset:消息在日志中的位置,可以理解是消息在 partition 上的偏移量,也是代表该消息的唯一序号
  5. Producer:消息生产者
  6. Consumer:消息消费者
  7. Consumer Group:消费者分组,每个 Consumer 必须属于一个 group
  8. Zookeeper:保存着集群 broker、topic、partition 等 meta 数据;另外,还负责 broker 故障发现,partition leader 选举,负载均衡等功能

kafka基本架构图

partition

当存在多副本的情况下,会尽量把多个副本,分配到不同的broker上。kafka会为partition选出一个leader,之后所有该partition的请求,实际操作的都是leader,然后再同步到其他的follower。当一个broker崩掉后,所有leader在该broker上的partition都会重新选举,选出一个leader。(这里不像分布式文件存储系统那样会自动进行复制保持副本数)

Kakfa怎么保证其高可用?

生产者发布消息后,对应的每个消息队列都有一个leader和follower,当leader宕机后kafka会自动识别出宕机的机器,然后通过选举将对应的follwer选举成leader这时候可以继续,因为follower和leader的数据是一样的所以可以继续为消费者进行提供消息进行消费,不会影响后续的系统流程。

Kafka消息重复怎么解决?

首先要了解出现消息重复的场景:

Kakfa内部的每一条消息都有一个offset唯一顺序号,当消费者消费某一条记录后被重启了,而这时被消费的消息的offset并没有被提交给MQ。重启后有接着从MQ中获取消息继续消费下去,这时获取的就是刚才已经消费过的消息。

通常幂等性的解决思路:(如何解决密等性需要结合具体业务来看)

  1. 在每次消费了一条MQ之后需要往一个地方插入一条消息进行记录,基于内存的数据结构(set去重)或者redis都可以,然后下一次消费MQ的时候就进行一次去重操作,重复了就不再进行消费。
  2. 基于数据库的唯一键保证数重复数据不会重复插入多条。(对上线系统,就有这个问题,就是拿到数据的时候,每次重启可能会有重复的,因为kafka消费者消费之后还没来得及提交offset,重复的数据拿到以后进行插入,因为有唯一键的约束,所以重复数据只会插入报错,不会导致数据库中出现脏数据。)

 

 

消息丢失怎么办(主要针对RabbitMQ和Kafka)?

保证生产者不丢失消息:

RabbitMQ:

  1. 使用事务(不推荐)。发生异常就进行回滚,重新发送消息,存在问题:事务是同步机制,降低吞吐量。
  2. 使用confirm模式(推荐)。使用的是回调的机制,异步的模式,不会造成阻塞,生产者可以继续发送下一条消息,这样吞吐量不会受到影响。

Kafka:

  1. 设置acks = all,这时生产者一定不会丢失消息,因为必须leader接受到消息并且所有的follower同步了消息才会认为这次的消息是发送成功的。如果没有满足条件生产者会重试无限次发送。

保证MQ不丢失消息:

RabbitMQ:开启持久化,就是消息写入后持久化到磁盘,哪怕是MQ挂掉也可以读取之前的持久化数据。

Kafka:

存在丢失情况:主要是在生产者在发送消息给broker1时,broker1主要是还没来得及同步就挂掉了,这时重新选举broker2为leader,但是broker2没有这条数据,导致消息丢失。

 

解决方案:一般要求起码设置4个参数

  1. 给topic设置replication.factor参数:必须大于等于2,要求每个partioion必须至少有2个副本,一个副本即一份数据,如果设置参数为1则总共只有1份数据。
  2. 在kafka服务端设置min.insync.replication参数:这个值必须大于等于1,这个是要求leader至少感知到有1个follower还跟自己保持联系,这样才能确保leader挂了有一个follower能替代
  3. 在producer端设置acks = all:这个是要求每条数据,必须序入所有的replication之后,才能认为写入是成功的。
  4. 在producer端设置retries = MAX(无限重试):要求一旦写入失败,就无限重试。

保证消费者不会丢失消息:

RabbitMQ:关闭消费者的autoAck机制,消费者通过自己判断消息是否处理完成,处理完成后发送ack给MQ

kafka:取消自动提交(类似RabbitMQ),手动提交offset。

怎么保证MQ中的消息按顺序进行消费?

RabbitMQ

  • 出现数据顺序错误的场景:一个queue,多个consumer,这不明显乱了
  • 即当生产者发送的消息顺序是message1,message2,message3,都会发给queue1,然后再交给不同的消费者,这时消费者消费的速度不一样可能导致message2先消费完成,造成message2先插入数据库。
  • 解决方案:
    • 拆分多个queue,每个queue一个consumer,就是多一些queue而已,确实麻烦一点;或者就一个queue和一个consumer,然后这个consumer内部用内存队列做排队,然后分发给底层不同的woker来处理。

 

Kafka

  • Kafka消息错乱的场景:一个topic,一个partion,一个consumer,内部多线程,这不也明显乱了

 

  • 解决方案:
    • 一个topic,一个partition,一个consumer,内部单线程消费,写N个内存queue,然后N个线程分别消费一个内存queue即可

 

消息队列其他问题

如何快速处理挤压过多的消息?

  • 情景:消费者挂掉后再重启,这时会有很多已经挤压了的消息在MQ中,所以需要快速的处理之前已经挤压了的消息。
  • 解决方案:可以将原由的消费者进行修改,不再直接对数据库进行操作,只对MQ的数据进行并将处理得到的数据再发给新的partition(可以创建很多来进行过度),然后再由很多消费者进行同时的消费,并写入数据库。这是处理速度就会很快。因为第一次的消费者处理之后并不用写入数据库就可以给MQ反馈已经消费了;后续的消费者继续处理需要消费的数据并不会影响之前的消费者处理的速度。

 

如果消息队列满了怎么处理?

类似上述问题:修改消费者消费方式(不直接进行消费,转发给另外的MQ),然后再由其他消费者进行消费。

如果让你开发消息队列中间件,如何来设计?

  1. 考虑mq的伸缩性,就是需要的时候快速扩容,就可以增加吞吐量和容量,那怎么搞?设计个分布式的系统呗,参照一下kafka的设计理念,broker -> topic -> partition,每个partition放一个机器,就存一部分数据。如果现在资源不够了,简单啊,给topic增加partition,然后做数据迁移,增加机器,这样就可以存放更多数据,提供更高的吞吐量了。
  2. 考虑mq数据要不要持久化?需要写入磁盘,这样才能保证挂了之后不会造成数据的丢失。写入时怎么进行写入磁盘?顺序写入,这样既保证了消息的顺序性,还减少了寻址的开销,达到提高性能的目的。
  3. 考虑mq的可用性?参考kafka的高可用的保障机制。多副本--》leader&follwer--》broker挂了重新选举leader即可。
  4. 保证数据的0丢失?参考kafka的0丢失的机制。

你可能感兴趣的:(中间件)