目录
一、为什么使用消息队列?消息队列有什么优点/缺点?介绍下Kafka、ActiveMQ、RabbitMQ、RocketMQ有什么优点缺点,如何取舍?
1.公司业务场景是什么,这个业务场景有什么挑战,如果不用MQ有什么麻烦,现在用了MQ有什么好处
4.Kafka、ActiveMQ、RabbitMQ、RocketMQ有什么优点缺点,如何取舍?
中小型公司用rabbitmq,社区活跃,基本满足需求;大型公司研发能力雄厚,可用rocketmq;大数据实时领域用kafka很标准;
镜像集群模式,是每个节点上都有queue和数据。写消息到queue时,会自动把消息同步到多个实例的queue上。
broker,topic,partition,repilication
三、如何保证消息不被重复消费?如何保证消费消息的幂等性?(全局唯一标识ack /offset)
1.消息自己该有全局唯一标识,rabbitmq是ack,kafka是offset,记录下来每次消费到哪个号码了
2.结合业务,避免重复消费产生影响。比如数据库的唯一键/主键,比如搭配redis
三个可能性,生产者发送给MQ时丢失了;MQ自己丢失了;MQ发给消费者丢失了
brocker宕机,重新选举partition的leader,但其他follower还没同步好数据,就会有数据丢失的问题
消息是顺序性有两个方面,一个是写入消息的顺序,一个是读取的顺序
写入时要保证顺序,key来确认分配到哪个partition,一个partition对应一个消费者,
kafka 一个topic,一个partition,一个consumer,内部单线程消费,这种吞吐低。
六、消息如果延时了或者处理过慢或者积压了几百万消息或者过期了怎么解决
Topic、Partition、Segment、.log、.index、Message
消息队列
一、为什么使用消息队列?消息队列有什么优点/缺点?介绍下Kafka、ActiveMQ、RabbitMQ、RocketMQ有什么优点缺点,如何取舍?
1.公司业务场景是什么,这个业务场景有什么挑战,如果不用MQ有什么麻烦,现在用了MQ有什么好处
- 进行投后业务场景后端从sqlServer无感知切花u你Mysql其中的数据校验。这个业务场景的挑战点就在于如何在真实场景中验证业务逻辑(写操作)的正确性,并保证不影响运营数据的维护,确保上线无问题。这就需要一套前端,一个操作,触发两个请求,一个是原有sqlserver 的请求,另一个是对Mysql数据库操作,主要利用了消息队列实现了双写操作,确保了原有运营数据的正常维护并且后端人员能在最真实最全面的待上线系统中实时进行数据对比
2.消息队列优点:
解耦(担心挂)
- 通过发布订阅消息这个模型,使系统与系统之间解耦,挂了也不影响整体,
异步
- Mysql双写
削峰
- 有些时间段业务繁忙,但实际并不需要非常快速响应,可以利用消息队列实现均匀处理消息,保证节点不会挂
3.消息队列缺点:
整个系统可用性降低(外部依赖变多,MQ挂了,系统挂了);复杂度变高(需要注意消息重复,消息遗漏,消息顺序);引入了一致性问题(A系统完成返回成功,用户以为成功,但B/C/D系统哪里某个失败了,那就数据不一致了)
系统复杂度提高,可用性下降,还需要保证一致性
所以需要额外的架构来规避上述问题
4.Kafka、ActiveMQ、RabbitMQ、RocketMQ有什么优点缺点,如何取舍?
中小型公司用rabbitmq,社区活跃,基本满足需求;大型公司研发能力雄厚,可用rocketmq;大数据实时领域用kafka很标准;
二、如何保证消息队列的高可用性?
RabbitMQ(主从架构)
- 有几种模式,第一种普通集群模式,是一个元数据queue存储信息,消费者拉数据访问到其他节点时,其他节点到queue所在节点拉数据,复制到其他节点再返回。
镜像集群模式,是每个节点上都有queue和数据。写消息到queue时,会自动把消息同步到多个实例的queue上。
- 网络传输开销大;而且这样对于大消息是存储不了的,存储方面有瓶颈
Kafka(切分消息+replica副本机制)
broker,topic,partition,repilication
- kafka由多个broker构成,每个broker是一个节点;一个topic可以划分为多个partition,每个partition可以存在于不同的broker上,每个partition就放一部分数据。(切分消息了,真正的分布式)
- kafka0.8以后,多了replica(复制品)副本机制。每个partition的数据都会同步到其他broker上,并且选举leader,leader负责同步data到follower;生产和消费都只跟leader沟通,保证数据一致性。
- 写数据时,生产者写leader,leader将数据落入本地磁盘,接着其他follower自己主动到leader来Pull数据,一旦所有follower同步好数据,就会发送ack给leader,leader收到所有follower的ack后,就会返回写成功的消息给生产者。
- 读数据时,读leader,leader如果挂了,就重新选举leader,读新leader;但是只有当一个消息已经被所有follower都同步成功返回ack的时候,才会被消费者读到。
三、如何保证消息不被重复消费?如何保证消费消息的幂等性?(全局唯一标识ack /offset)
1.消息自己该有全局唯一标识,rabbitmq是ack,kafka是offset,记录下来每次消费到哪个号码了
2.结合业务,避免重复消费产生影响。比如数据库的唯一键/主键,比如搭配redis
四、如何保证消息不会丢失?
三个可能性,生产者发送给MQ时丢失了;MQ自己丢失了;MQ发给消费者丢失了
生产端弄丢了数据(事务机制 offset)
- rabbitmq(事务机制)
- 生产者开启事务机制,得到确认才commit,否则rollback(同步的)
- 吞吐量下来,耗性能
- 生产者开启confirmed机制,每个消息有唯一id,一段时间没有得到ack就重发该消息。(异步的)
- 生产者开启事务机制,得到确认才commit,否则rollback(同步的)
- kafka
- offset,发送到哪记录下
- rabbitmq(事务机制)
MQ弄丢了数据(元数据持久化+confirmed机制)
- rabbitmq
- 开启rabbitmq元数据queue的持久化和消息的持久化,持久化到磁盘
- confirmed机制和持久化搭配起来,只有消息被持久化到磁盘,才发送ack通知生产者
- rabbitmq
消费端弄丢了数据(关闭自动提交offset)
- kafka
关闭自动提交offset,重复消费保证幂等性
brocker宕机,重新选举partition的leader,但其他follower还没同步好数据,就会有数据丢失的问题
- 1.给topic的partition设置副本数要大于等于2
- 2.在producer端设置acks=all,要求每条数据必须写入所有replica后,才能认为是写成功了
- acks=0,1,all 分别代表的情况
- 3.在producer端设置reties=MAX,要求一旦写入失败则无限充实
- 4.给kafka服务端设置min.insync.replicas>=1,要求一个leader感知到治沙一个follower还跟自己保持联系没掉队,这样才能确保Leader挂了还有一个follower
- kafka
五、如何保证消息的顺序性?(写入的顺序、读取的顺序)
消息是顺序性有两个方面,一个是写入消息的顺序,一个是读取的顺序
写入时要保证顺序,key来确认分配到哪个partition,一个partition对应一个消费者,
rabbitmq queue
- 拆分为多个queue,每个queue对应一个consumer;或者就一个queue,一个consumer,该consumer内部用内存队列排队,分发给不同的worker来处理
kafka 一个topic,一个partition,一个consumer,内部单线程消费,这种吞吐低。
- 一个topic,一个partition,一个consumer,内部单线程消费,这种吞吐低。
- 写N个内存queue,具有相同key的数据都到同一个内存queue,但是对于N个线程,每个线程分别消费一个内存queue即可。(多个queue,多个线程,但是queue与线程1V1)
六、消息如果延时了或者处理过慢或者积压了几百万消息或者过期了怎么解决
1.解决消费端报错,回复consumer消费速度
- 2.征用机器,扩大partition到十倍,consumer到十倍,十倍速度进行快速消费(临时分发数据的consumer程序中,消费之后不做耗时处理,直接均匀轮询写入临时建立好的10倍数量的的queue)
- 3.快速消费后,恢复原先部署的架构
- 过期:设置过期实践ttl;写代码捞丢失的数据
- 快写满了:先用1,2,3进行快速消费数据,然后晚上再补捞数据
七、如果让你写一个消息队列如何进行架构设计?
系统可拓展性
- 分布式的,便于快速拓展,数据切分,数据副本机制
- kafka的设计理念:broker->topic->partition,每个partition存放一个机器,存一部分数据,资源不够,给topic增加partition,做数据迁移,增加机器
数据落地磁盘
- 顺序写,避免磁盘随机读写的寻址开销。磁盘顺序读写的性能高
mq的高可用性
- replica副本机制->leader&follewer->broker挂了重新选举Leader即可对外服务
- 消费端Rebalance,某消费者实例挂掉后,再均衡分配实例
数据0丢失
- 数据多了怎么办,大了怎么办,丢了怎么办,重复消费了怎么办,过期了怎么办,保证顺序怎么办
Kafka
基本概念
- 高吞吐的分布式发布/订阅消息系统,即 为不同系统之间传递消息的
- 存储系统,得益于 其消息持久化功能和多副本机制
- 分布式流处理平台,有完整的流式处理类库
角色术语
Broker
- 数据存储中心。每个kafka集群包含一个或多个服务器,每个服务器被称为broker
Topic
- 每条发布到Kafka集群的消息都有个分类,类别即为Topic(主题),用来区分具体业务
Record
- 消息
Partition
- 每个Topic包含一个或多个Partition,每个Partition都是有序不变的队列,Partition中的每条消息都会被分配一个唯一ID (称为offset)
Offset
- 每条消息的位置信息,单调递增且不变的量
Replica
- 副本,数据冗余,高可用
Producer
- 消息的生产者,负责发布消息push到kafka broker
Consumer
- 消息的消费者,负责到broker去pull消息来消费
Consumer Offset
- 消费者位移,代表消费进度
Consumer Group
- 消费者组,可以给每个consumer指定消费者组,若不指定,则为默认的group。同时消费多个Partition以实现高吞吐
Rebalance
- 再平衡。消费者组内某个消费实例挂掉后,其他消费者实例自动重新分配订阅主题分区的过程。Rebalance是Kafka消费者端实现高可用的重要手段。
ISR
- In-Sync Replica Set.ISR集合代表每个分区的一组同步集合,处于 ISR 集合中的副本,意味着 follower 副本与 leader 副本保持同步状态,只有处于 ISR 集合中的副本才有资格被选举为 leader
HW
- HightWatermark,水位线,指的是消费者能见到的最大的offset,ISR队列中最小的LEO
LEO
- Log End Offset, 指的是每个副本最大的offset;
- Log End Offset, 指的是每个副本最大的offset;
拓扑架构
- 多个producer,多个broker,多个 consumer group,外加一个zookeeper。zookeeper来进行管理集群配置,选举Leader,在Consumer Group发生变化时进行rebalance。
- Producer push 消息 发布到broker,consumer使用pull模式从broker订阅并消费消息。
- 生产者将消息分布到不同broker上的不同partition上,消费者可以消费集群中多个节点的多个partition。
- 写消息时,允许多个生产者写道同一个partition中
- 但读消息时,一个partition只能被一个消费者组的一个消费者读,但是可以同时被其他消费组读取。(消费者组内的消费者读partition互斥)
- 支持消息持久化存储。持久化数据存储在log日志文件中。(先缓存在内存,到达一定阈值再统一写入磁盘,减少磁盘IO调用次数)
- 消息写入Partition,是顺序写入磁盘的,避免随机读写的 “寻头”磁头不停移动(磁盘的性能瓶颈之一,SSD例外)
Topic、Partition、Segment、.log、.index、Message
- topic的partition数字决定了组成topic的log的数量,>=同时运行的consumer,>集群broker的数量,尽可能均匀分布在broker中
- kafka是基于文件存储的,partition可用来拆分topic,将大量消息分成多批写到不同节点上,均衡负载。
- 每个partition对应一个文件夹,存储该partition的消息,以大小相等的segment文件夹为单位,内容为 消息索引(.index)和消息数据(.log)。partition命名为topic+序号(0,1,...)
- Partition文件夹的命名,Segment文件夹的命名,.index 和 .log的切分和命名
- Message的物理结构
Kafka分布式集群构建
- kafka2.8.0版本中移除了对Zookeeper的依赖,通过KRaft进行自己的集群管理。
- 一些配置参数:
- brocker.id
- 若服务器ip地址变化时,只要brocker.id没有变,就不会影响consumer的消费
- log.dirs
- 配置kafka保存数据的位置
- num.partitions
- topic的分区数,过小会影响性能
- logs.segment.bytes
- 配置每个segment数据文件的大小,默认是1G,超过这个大小会自动创建一个新的segment
- delete.topic.enable
- 在0.8.2版本之后,kafka提供的删除topic 的功能,但是默认不会物理删除topic数据。如果需要物理删除,设为true
- acks
- 指定必须多少个分区副本收到消息,生产者才会认为写入消息是成功的。(对消息丢失的可能性有重大影响)
- acks=0:写入消息之前不会等待任何来自服务器的响应,容易丢消息,但是吞吐量高
- aks=1(leader):只要集群的leader节点收到消息,生产者就会收到来自服务器的成功响应。可靠性中等,leader如果发生问题,follower未来得及同步,就会丢失部分数据
- acks=-1(all):只有当所有参与复制的节点都收到消息,生产者才会收到一个来自服务器的成功响应。延迟高。
- 指定必须多少个分区副本收到消息,生产者才会认为写入消息是成功的。(对消息丢失的可能性有重大影响)
- brocker.id
核心设计原理
- 存储机制
- 备份和副本机制
- 日志设计
- Controller控制器
- Rebalance
- 可靠性设计
- 延迟、死信、重试队列等