一. RabbitMQ:
1. 模式
分三种,分别是: 单机模式、普通集群模式、镜像集群模式
- 普通集群模式(不是分布式的):
- 优点:吞吐量高,只提高了吞吐量(消费者可以连接MQ中任意一个节点,但节点上只存在元数据信息,并没有数据信息,数据信息需要从主节点上进行同步)
- 缺点:
1、会造成数据在rabbitmq中进行传输
2、可用性不能得到保障。当节点宕机后,数据会丢失 - 镜像集群:
在控制台页面新增一个策略,可以数据同步到所有节点上,也可以指定数据同步到指定节点上
2. 如何保证高可用?
使用镜像集群模式: queue元数据信息和数据信息存储在每一个节点上,不需要节点之间来回同步
rabbitMQ 一个queue的数据都是放在一个节点/镜像里,就是每个节点都放这个queue完整的数据
二.Kafka分布式消息队列
1. 基本认识
多个broker组成,每一个broker是一个节点;创建一个topic,可以根据topic划分成多个partition,每个partition可以存在于不同的broker上,每个partition存放一部分数据
2. 版本区别:
kafka0.8以前:没有HA机制(高可用机制),就是任何一个broker宕机了,那个broker上的partition上的数据就会丢失
kafka0.8以后:提供了HA机制,就是replica副本机制。每个partition的数据都会同步到其他机器上,形成自己的多个replice副本。所有的replice副本会选举一个leader出来,生产和消费都跟这个leader打交道,其他的replice副本都是follower。写的时候,leader会负责把数据同步到所有的follower上去,读的时候都是直接读取leader上的数据。(只有leader可以对外提供服务) 当leader宕机后,kafka会重新从follower中选举新的leader.
写数据的时候,生产者就写入partition的leader中,leader会将数据落入本地磁盘,其他follower会从leader中拉取数据,进行同步,一旦同步完成,会有消息确认机制,返回leader,leader收到所有的ack后,会返回给生产者。
只有当消息被所有的follower ack 之后,这条消息才能被消费者消费
3. 如何保证消息不被重复消费/如何确保消息的幂等性
数据重复消费:同一个数据/请求会被消费多次
幂等性:一条数据/一个请求重复出现,需要保证只对其处理一次,这样就保证了幂等性0
kafka 中有offset,代表消息的序号,会把消费过的消息offset提交,代表已经消费过
解决重复消费的方案(需要结合具体的业务进行分析):
可以在生产者发送每条数据时,增加一个全局的唯一的id,消费之后,可以根据id去查询,没有,则消费,否则,丢弃
自己的业务场景:我们对于数据插入是有唯一id,重复消费,也只会进行更新,并不会产生脏数据
4. 如何保证消息的可靠性传输?/如何处理消息丢失的问题?
消息丢失的阶段:
生产者弄丢了数据,解决方案?
RabbitMQ:
1、开启事务功能,生产者发送数据之前开启rabbitmq事务(channel.txSelect),在发送消息,如果消息
没有被接收到,生产者会收到异常报错,回滚事务,进行重试。rabbitmq接收到消息之后,就可以提交事务
缺点:降低了吞吐量
2、confirm机制 该机制是一个异步的方式,不会阻塞,吞吐量高。可以先把channel设置为confirm模式,发送消息,在生产者提供一个回调接口
,成功之后,调用ack接口,失败,调用 nack接口,可以在进行重发一次消息
RabbitMQ /kafka 弄丢了数据
RabbitMQ:
开启持久化,将消息持久化到磁盘上。
设置持久化的步骤:
1、创建queue时,将其设置为持久化,可以保证rabbitmq持久化queue的元数据,而不是具体的数据
2、发送消息时,将消息的deliveryMode设置为2,将消息设置为持久化
kafka:
在遇到kafka的leader宕机了,将follower切换为leader之后,会发现数据丢失
需要设置4个参数:
1、topic设置replication.fator参数,这个值必须大于1,要求每个partition必须至少有2个副本
2、kafka服务端设置 min.insync.replices参数,这个值必须大于1,要求一个leader至少有一个follower和自己联系,
这样才能确保leader挂了还有follower
3、producer端设置 acks=all,要求每条数据必须写入所有的replica后,才能认为成功
4、producer端设置retrles=MAX(无线重试),要求一旦写入失败,就无线重试
消费者弄丢了数据?
rabbitMQ:
消费者开启了autoAck机制,消费到数据后,会自动通知rabbitMQ 消息已经消费完了,但实际上还没有处理这个消息
需要关掉autoAck机制,在处理完消息之后,在发送ack给rabbitmq。即使没有处理完宕机了,
下次还是会将该数据重新发送给你
kafka:
消费者开启了autoOffset。需要关掉该机制,在处理完之后,在进行offset的提交
如何保证消息的顺序性?
rabbitMQ : 发生的原因, 一个生产者,将消息发送到queue中,多个消费者
解决方案:将需要保证顺序的数据发送到一个queue里面,一个queue对应一个消费者,并且在消费者内部做内存队列,在用多线程处理,这样消费者就能按照顺序进行消费数据,也可以提高吞吐量
kafka: 发生原因: 生产将有顺序的数据发送到kafka中,kafka会将这些数据分配到一个partition中,一个partition对应一个消费者,一个消费者中有多个线程,这样就没有办法确保数据的顺序性
对于有顺序的数据,可以在生产者指定一个key,有关这个key相关的数据都会发送到同一个partition中
解决方案:在消费者中设置一个内存队列,将有顺序的数据放入一个队列中,就能确保数据的顺序性
如何解决消息队列的延时/过期的问题?消息队列中的消息满了之后怎么处理?消息堆积问题如何解决?
快速处理积压数据?
1、先修复本身消费者的问题
2、新建一个topic,在建立原先n倍的partition,
3、写一个临时消费的程序,将原来需要处理的逻辑先替换成转发,转发到新的topic上,让新的程序进行处理
4、等积压的数据消费完成之后,在回复原来的逻辑
消息队列的延时/过期的问题?
rabbitmq 可以为消息设立过期时间,TTL,当数据过期之后,直接会丢掉
1、消息尽可能的不要设置TTL
2、手动进行补偿,将丢掉的数据,重新进行发送
消息队列满了?
消息积压在MQ里,过了很长时间都没有处理,可以先将数据丢弃,在进行补偿 还可以先将积压的数据转发到另一个队列中,在进行处理
如果让你设计一个MQ,你会怎么设计架构?
1、吞吐量:MQ得支持可伸缩性,支持扩容 可以参考kafka
2、减少数据丢失:数据需要落入磁盘,可以顺序写入,减少磁盘随机读写的寻址开销
3、可用性:可以设置选举机制
4、保障数据零丢失