三种常见mq的优缺点比较

共同的优缺点:
    优点:解耦系统,异步化,削峰
    缺点:系统可用性降低,复杂度增高,维护成本增高
    MQ,保证最终一致性
同时保证消息的处理的幂等性,保证broker的高可用
优点:
1.实现简单,改造成本低
2.性能高,没有全局锁
缺点
1.弱一致性,需要保证强一致性不适用
2.消费者消费失败,需要额外接口写生产者回滚逻辑

1.Rabbitmq

a.安装和启动
docker pull rabbitmq:3.8.15-management
docker run -d --name xd_rabbit -e
RABBITMQ_DEFAULT_USER=admin -e
RABBITMQ_DEFAULT_PASS=password -p 15672:15672 -p
5672:5672 rabbitmq:3.8.15-management
概念:一个开源的amqp实现,服务端使用erlang语言开发,支持多种客户端,主要用于消息的存储转发,具有较高的易用性,扩展性,高可用性
优点:RabbitMq自带延迟队列,更符合这块业务,比如定时任务,分布式事务处理
消息发送完整流程:
    生产者将消息发送到exchange,交换器将消息路由到一个或多个队列中,交换机有多个类型,交换机和队列通过路由键进行绑定,如果消息拥有的路由键和交换机匹配,消息就会被路由到队列中
基本概念:
    交换器:常见的交换机主要有Direct exchange、Fanout exchange、Topic exchange
    Direct exchange:将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配
    Fanout Exchange:只需要简单的将队列绑定到交换机上,一个发送到与该交换机绑定的所有队列都会收到消息
    不处理路由键
    Topic Exchange通配符:主题交换机是一种发布订阅模式.将路由键和某模式进行匹配,此时队列需要绑定到一个模式上, #匹配一个或多个词,* 匹配不多不少一个词
    使用场景:商家和客户订单数据冗余双写问题
    ACK机制:消费者从rabbitmq接收到消息,并处理完成后,反馈给rabbitmq,rabbitmq接收到反馈才将消息从队列中删除

 

 常见面试题

Rabbitmq为什么需要信道,为什么不TCP直接通信:
    1.TCP的创建和销毁开销特别大,创建需要三次握手,销毁需要四次挥手
    2.如果不用信道,那么应用程序会以TCP连接rabbitmq,高峰时每秒上千万的链接造成资源浪费,并且操作系统每秒处理的tcp连接数也是有限的,必将造成性能瓶颈.
    3.信道的原理是一个线程一条通道,多个线程多个通道同用一个tcp链接,一条tcp链接可以容纳无限的信道.
    
死信队列:
    死信交换机:消息成为死信消息后,会被放到新的交换机,这个交换机就是死信交换机
    几种情况会成为死信?
    1.消费者拒收消息,并且没有重新入队
    2.超时未被消费
    3.消息队列超过极限

2.Kafka

1.概念:apache软件基金会开发的一个开源流处理平台,kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理大规模的网站中的所有动作流数据(网页浏览.搜索和其他用户行为),副本集机制,实现数据冗余,保障数据尽量不丢失
支持多个生产者和消费者,不支持批量和广播消息
特点:高吞吐量,低延迟,每秒可以处理几十万消息
     高并发:支持几千万客户端同时读写
     容错性:多副本,多分区,允许集群中节点失败
     扩展性强:支持热扩展
最大优点:单机写入tps约在百万条/s,吞吐量高     

kafka2.4之后,kafka提供了有限的读写分离,也就是说follower副本能够提供读服务,为啥没有?
1.场景不适用,读写分离适用于读负载很大,而写操作相对不频繁的场景.可kafka不属于这样的场景
2.数据同步机制,kafka采用pull 方式实现follwer的同步,因此Follwer与leader存在不一致性窗口,如果允许读follwer副本,就势必要处理消息滞后的问题
基本概念:
    ConsumerGroup消费者组:一个消费者组只有一个comsumer可以消费topic下的消息
    Topic:
    Partition分区:kafka数据存储的基本单元,每个topic下至少一个partion,是有序的,以文件夹的形式存储在具体broker本机上.消费者数量小于等于partition数量
    Replication副本:同个partition会有多个副本replication,多个副本的数据是一样的,当broker挂掉以后,系统可以主动用副本提供服务
        ReplicationLeader:该partition扶着和生产者消费者交互
        ReplicationFollower:提供数据备份,同步leader数据
        ReplicationManager:负责broker所有分区副本信息,副本状态切换
    offset:每个comsumer实例需要为消费的partition维护自己消费的偏移offset
    LEO:表示每个partition的log最后一条message的位置
    HW:每个partition各个replicas数据同步且一致的offset位置。HW之前的数据才是commit后的对消费者可见
    ISR:leader会维持一个与其保持同步的replica集合
    Segment:每个partition由多个segment file组成,分为index file 和data file也称log file,分别表示索引文件和数据文件
    Kafka高效文件存储设计特点:
        1.kafka把topic中的一个partition大文件分成多个小文件段,通过多个小文件段,容易定期清楚或删除已经消费完的文件,减少磁盘占用
        2.通过索引文件可以快速定位message
        3.写数据通过顺序写


生产者发送消息到broker的分区策略:
    1.如果指定partitionId 则PR被发送到指定partition
    2.未指定id,但指定了key,PR会按照hash发送到对应partition
    3.两者均未指定.PR会按照round-robin轮训模式发送到每个partition
生产者发送消息到broker的流程:
    kafka的客户端发送数据到服务器,先经过内存缓冲区默认16KB,通过kafkaProducer发送出去的消息都是先进入到客户端本地的内存缓冲区中,然后把很多消息收集到batch里面,再一次性发送到broker上去的,这样性能才可能提高,提高效率,减少请求
生产者两个关键配置:
batch.size
linger.ms

Kafka的消费者机制(模式):
    消费者采用pull模式.而不是broker主动push
    pull模式可以根据comsumer的消费能力进行调整,不能的消费者性能不一样,如果broker没有数据,comsumer可以配置timeout时间,阻塞等待一段时间之后再返回
    如果采用broker主动push,优点是可以快速处理消息,但是容易造成消费者处理不过来,造成消息堆积和延迟
消费者分区策略:
    1.顶级接口:org.apache.kafka.clients.comsumer.internals.AbstractPartitionAssignor
    2.RoundRobinAssignor轮训,
    按照消费者组进行轮训分配,把所有的partition和所有的consumer都列出来,主题不一样则会出现分配不均的问题,实例如下

RangeAssignor默认策略:
  按照主题进行分配,将该topic的所有可用的partition和订阅该topic的所有comsumer展开,如果分配不均,会导致消费者分配过多分区,消费的分区过多会导致性能有所下降

Kafka消费者重新分配策略:
Rebalance操作:
  平衡:Kafka怎么均匀的分配某个topic下的所有partition给消费者,从而使消息的消费速度达到最快。具体策略主要才去Range范围分区和RoundRobin轮训分区,也支持自定义分区策略
  重平衡(Rebalance):重新进行partition的分配,从而使得partition的分配重新达到平衡状态
该知识点常见面试题:
    1.例如70个分区,10个消费者,但是先启动一个消费者,后续再启动一个消费者,这个时候如何分配?
    kafka会进行一次分区分配操作,即Kafka消费者端的重平衡操作
    2.触发重平衡的条件:
        a.当消费者组内的消费者数量发生变化,就会产生重新分配partition
        b.分区数量发生变化时
    3.当消费者早消费过程中突然宕机了,重新恢复后是从哪里消费,会有什么问题?
    消费者会记录offset,故障恢复后从这里开始消费,旧版offset记录在zk喝本地,新版默认offset保存在kafka的内置topic中,名称是_comsumer_offsets    
    假设topic默认的partition数量是50个,每个partition有3个副本,分区的数量由offset.topic.num.partition配置
    首先通过groupid的哈希值和该参数取模来确定消费者组已经消费的offset保存到_comsumer_offsets主题的哪个分区中
    再由消费者组名+主题+分区,来确定唯一的offset的key,从而获取对应的值


Kafka日志清理
1.内部有个定时任务检测删除日志,默认是5分钟
 根据配置策略对数据清理
 根据segment单位进行定期清理
2.基于时间删除日志说明
3.基于大小超过阈值删除日志说明,超过阈值的部分必须要大于一个日志段的大小

Kafka数据存储流程和log日志
数据存储主要采取分片和索引机制,将每个partition分为多个segment,每个segment对应2个文件,index和log
index文件并没有为每一条message建立索引,采用了稀疏存储的方式,每隔一定字节的数据建立一条索引,避免索引文件占用过多的空间和资源,从而可以将索引文件保留在内存中
缺点:没有建立索引的数据在查询过程中需要小范围的顺序扫描操作

常见面试题

Kafka高性能:
1.存储模型,topic下分多分区,每个分区多segment段
2.index索引文件查找,利用分片和稀疏索引
3.磁盘顺序写入
4.异步操作少阻塞main线程和sender线程,批量操作
5.页缓存,Page cache,没利用JVM内存
6.零拷贝 sendFile

RocketMQ:

 1.消息中间件,纯java开发,具有高吞吐量,高可用性,适合大规模分布式系统应用的特点,性能强劲(零拷贝技术),支持海量堆积,支持指定次数和时间间隔的失败消息重发,支持comsumer端tag过滤,延迟消息等
 2.缺点.成熟资料相对另外几种不多,社区处于新生状态但是热度高


消息队列的发送方式:
1.SYNC:同步发送,应用场景,重要邮件发送,报名短信通知等
2.ASYNC:异步发送,应用场景,对RT时间敏感,可以支持更高的并发,回调成功触发相应的业务,应用场景:注册成功通知积分系统发放优惠券
3.ONEWAY:无需要等待响应,应用场景:适用于某些耗时非常短,但是对可靠性要求不高的场景,例如日志服务

如何保证消息队列的消息生成和消费的顺序性
1.顺序消息的概念:
    消息的生产和消费顺序一致
2.分类:
    全局顺序:topic下⾯全部消息都要有序(少⽤),性能要求不⾼,所有的消息严格按照 FIFO原则进⾏消息发布和消费的 场景,并⾏度成为消息系统的瓶颈, 吞吐量不够
    局部顺序:只要保证⼀组消息被顺序消费即可,性能要求⾼
    
3.举例:Rocketmq
    顺序发布:对于指定的一个topic,客户端将按照一定的先后顺序发送消息
    根据messageQueueSelector里面的自定义策略select方法里,根据同个业务id放置到相同queue里面
    顺序消费:对于指定的一个topic,按照一定的先后顺序接收消息
    消费端要在保证同个topic里面的同个队列,不应该使用MessageListenerConcurrently,而应该使用
    MessageListenerOrderly,自带单线程消费,不能在comsuer端多线程消费,消费端分配到的queue数量是固定的,集群消费会锁住当前正在消费的队列集合的消息,所以保证顺序消费

如何保证消息的可靠性传输吗?
消息的可靠性传输主要从三个方面答:
    1.producer端:不采用oneway发送,使用异步或者同步发送,并做好重试,投递的日志需要保存,关键字段,投递时间,投递状态,重试次数,请求体和响应体等
    2.broker端:多主多从架构,多机房部署,同步双写,异步刷盘,同步刷盘消息不丢失具体根据业务选择
    3.comsumer端:消息队列一般提供ack机制,发送者为了保证消息肯定消费成功,只有消费者明确表示消费成功,队列才会认为消息消费成功,中途断电,抛异常等不会认为成功
    消息消费务必保留日志,即消息的元数据和消息体