Java面试之消息中间件

本文详细探讨了消息队列如Kafka、RocketMQ和RabbitMQ的优缺点,包括解耦异步、系统可用性、性能比较、消息一致性问题、重复消费处理以及刷盘策略。还涉及了Netty和高可用性实现的关键技术。
摘要由CSDN通过智能技术生成

消息队列

    • 优缺点
      • 特点
        • 解耦
        • 异步
        • 削峰
      • 缺点
        • 系统可用性降低
          • 兜底:代码中try、catch 异常捕捉后直接进行数据库操作,或者 搭建高可用集群,Kafka集群、RocketMQ集群
        • 提高复杂度
          • 消息重复(消费端的幂等性设计)、消息丢失(主要集中RabbitMQ)、消息的顺序(业务:1,下单 2,支付 3,发送物流 4,通知)
        • 一致性问题
          • a,b,c三个系统,a、b两个写入数据库成功了,c系统写库失败?使用分布式事务来控制。RocketMQ提供了,其他的seta方式
      • 特点
        • 解耦
        • 异步
        • 削峰
      • 缺点
        • 系统可用性降低
          • 兜底:代码中try、catch 异常捕捉后直接进行数据库操作,或者 搭建高可用集群,Kafka集群、RocketMQ集群
        • 提高复杂度
          • 消息重复(消费端的幂等性设计)、消息丢失(主要集中RabbitMQ)、消息的顺序(业务:1,下单 2,支付 3,发送物流 4,通知)
        • 一致性问题
          • a,b,c三个系统,a、b两个写入数据库成功了,c系统写库失败?使用分布式事务来控制。RocketMQ提供了,其他的seta方式
    • RabbitMQ、Kafka、RocketMQ 对比
      • 性能角度
        • RabbitMQ 1.2w
        • Kafka 100w
        • Rocket MQ 10w
      • 集群扩展支持
        • Rabbit MQ集群很弱(确保高可用 不能扩展性能)
        • Kafka 天生分布式,支持动态扩展
        • Rocket MQ 天生分布式,支持动态扩展
      • 功能
        • Rabbit MQ比较丰富(死信消息、延迟消息)
        • Kafka比较弱
        • Rocket MQ比较丰富(死信、延迟、消息回溯、消息过滤)
    • 常见问题及解决方案
      • 重复消费
        • 死信消息
        • MVCC(多版本控制)
          • 对整体业务改动较大,使用很不便利,代价较高
        • 去重表(MySQL、Redis)
          • 表上构建唯一性索引
          • try{处理业务:插入数据/判断是否存在}catch(exception e){return xxx (直接返回)}
      • 消费失败
        • 补偿机制(如 catch中处理)
      • 购买电影票,选座位未支付,锁定座位等场景
        • 延迟消息
      • 如何设计一个消息队列
        • 存储层:高可用--磁盘存储,顺序读写、零拷贝技术
        • 可伸缩:分布式,参考kafka    broker—》topic->partition
        • 消息的丢失:多主多从、多副本、raft协议 一台主服务器 宕机 选举机制
        • 网络框架:Netty 高效NIO框架
    • 核心技术原理分析
      • 零拷贝机制
        • Rabbit MQ
          • 磁盘-》文件读取缓冲区(内存)-》应用缓冲区(Buffer)-》套接字发送缓冲区-》网卡-》消费者
          • DMA拷贝----------------------------》CPU拷贝------------》CPU拷贝------------------》DMA拷贝->拉去消息进行消费
        • Rocket MQ(MMAP)
          • 磁盘-》文件读取缓冲区(内存)-》应用缓冲区(Buffer)-》套接字发送缓冲区-》网卡-》消费者
          • DMA拷贝-----》调用操作系统的mmap函数内存映射--》CPU拷贝---------》DMA拷贝->拉去消息进行消费
        • Kafka (sendfile)
          • 磁盘-》文件读取缓冲区(内存)-》应用缓冲区(Buffer)-》套接字发送缓冲区-》网卡-》消费者
          • DMA拷贝-----》文件描述符传递(类似指针)-------》文件描述符传递---------》DMA拷贝->拉去消息进行消费
          • 磁盘-》文件读取缓冲区(内存)- - - - 》共享- - - - -》套接字发送缓冲区-》网卡-》消费者
      • DMA拷贝
        • direct Memory Access 直接内存读取
        • 一般是 驱动(内核、操作系统)
        • 没有DMA 通过CPU的大量中断来负载,性能会很慢
        • 对比性能:CPU中断及DMA技术,相差大概100倍左右
      • MMAP的零拷贝技术
        • 内存映射
        • 数据不会到应用层,无法做死信消息、延迟消息等需要利用数据流转来进行的功能
    • 三大消息队列原理分析
      • Kafka
        • rebalance机制
          • 消费者分区分配策略
            • Range范围分区(默认的)
            • RoundRobin轮询分区
            • Sticky策略
          • 触发Rebalance的时机
            • 组成员个数发生变化。例如 有新的consumer实例加入该消费者组或者离开组
            • 订阅的Topic个数发生变化
            • 订阅Topic的分区数发生变化
          • Coordinator协调过程
            • 消费者如何发现协调者
            • 消费者如何确定分配策略
        • 消息丢失问题分析
          • 消息丢失场景
            • 生产者在生产过程中的消息丢失
            • Broker在故障后的消息丢失
            • 消费者在消费过程中的消息丢失
          • ACK机制
            • ack=0
              • 生产者在生产过程中的消息丢失,简单说就是 produce发送一次就不再发送了,不管是否发送成功
            • ack=1
              • Broker在故障后的消息丢失。
              • 简单说就是 produce只要收到一个分区副本成功写入的通知就认为推送消息成功了,需注意该副本必须是leader副本,只有leader副本成功写入,produce才会认为消息发送成功
              • 默认值,该值就是吞吐量与可靠性的一个折中方案
            • ack=-1
              • 生产侧和存储侧不会丢失数据
              • 简单说 producer 只有收到分区内所有副本的成功写入的通知才认为推送消息成功
            • offset机制
              • at-most-once:最多一次,可能丢数据
              • al-least-once:最少一次,可能重复消费消息
              • exact-once-message:精确一次
        • Kafka中ZK的作用
          • kafka中使用了zookeeper的分布式锁和分布式配置及统一命名的分布式协调解决方案
          • 在kafka的broker集群中的controller的选择,是通过zk的临时节点争抢获得的
          • brokerId等如果自增的话也是通过zk的节点version实现的全局唯一
          • kafka中broker中的状态数据也是存储在zk中,不过这里要注意,zk不是数据库,所以存储的属于元数据,新旧版本变化中,就把曾经的offset从zk中迁移出了zk
        • kafka中高性能如何保障
          • broker在持久化数据时使用了磁盘的顺序读写
          • 零拷贝技术(sendfile)
          • 可靠性与可用性的权衡,ack的0,1,-1取值
      • Rabbit MQ
        • AMQP架构
          • Broker:提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线,保证数据能按照指定的方式进行传输
          • Exchange:消息交换机,指定消息按什么规则,路由到哪个队列
          • Queue:消息的载体,每个消息都会被投到一个或多个队列
          • Binding:它的作用就是把exchange和queue按照路由规则绑定起来
          • Routing Key:路由关键字,exchange根据这个关键字进行消息投递
          • vhost:虚拟主机,一个broker里可以有多个vhost,用作不同用户的权限分离
          • Producer:消息生产者
          • Consumer:消息消费者
          • Channel:消息通道,在客户端的每个连接里,可建立多个channel
        • 核心概念
          • 在mq领域中,producer将msg发送到queue,然后consumer通过消费queue完成 P.C解耦
          • kafka是由producer决定msg发送到哪个queue
          • rabbitmq是由Exchange决定msg应该怎么样发送到目标queue,这就是binding及对应的策略
        • Exchange
          • Direct Exchange:直接匹配,通过Exchange名称+RountingKey来发送与接收消息
          • Fanout Exchange:广播订阅,向所有的消费者发布消息,但是只有消费者将队列绑定到该路由器才能接收到消息
          • Topic Exchange:主题匹配订阅,这里的主题指的是RoutingKey,可以通过采用通配符 * 或 #等。RoutingKey命名采用 . 来分隔多个词,只有消息者将队列绑定到该路由器且指定RoutingKey符合匹配规则时才能收到消息
          • Headers Exchange:消息头订阅,消息发布前,为消息定义一个或多个键值对的消息头,然后消费者接收消息同时需要定义类似的键值对请求头(如:x-match=all或x_match=any),只有请求头与消息头匹配,才能接收消息
          • 默认的exchange:如果用空字符串去声明一个exchange,那么系统就会使用 “amq.direct”这个exchange,我们创建一个queue时,默认的都会有一个和新建queue同名的routingKey绑定到这个默认的exchange上去
        • 事务消息
          • 发送方事务
            • 开启事务,发送多条数据
          • 消费方事务
            • 消费行为会触发queue中msg是否删除、是否重新放回队列等行为,类增删改。消费方的ack是要手动提交的,且最终确定以事务的提交或回滚决定
        • 消息发送及消息接收
          • 消息发送
            • ConfirmCallback方法
              • 是一个回调接口,消息发送到Broker触发回调,确认消息是否到达Broker服务器,也就是只确定是否正确到达Exchange中
            • ReturnCallback
              • 通过实现ReturnCallback接口,启动消息失败返回,此接口是在交换器路由不到队列时触发回调,该方法可以不使用,因为交换器和队列是在代码里默认绑定的
          • 消息接收
            • ACK机制,默认是自动确认
            • 消息确认模式
              • AcknowledgeMode.None:自动确认
              • AcknowledgeMode.Auto:根据情况确认
              • AcknowledgeMode.MANUAL:手动确认
            • 手动确认消息命令
              • Basic.Ack:用于确认当前消息
              • Basic.Nack:用于否定当前消息(注意:这是 AMQP 0-9-1的RabbitMQ扩展
              • Basic.Reject:用于拒绝当前消息
        • 死信队列、延迟队列
          • 死信队列
            • DLX(Dead Letter Exchange) 死信交换器,当队列中的消息被拒绝、或者过期会变成死信,死信可以被重新发布到另一个交换器,这个交换器就是DLX,与DLX绑定的队列称为死信队列
            • 造成死信的原因
              • 信息被拒绝
              • 信息超时
              • 超过了队列的最大长度
            • 过期消息的设置方式
              • 队列设置:在队列申明的时候使用 x-message-tt 参数,单位为 毫秒,设置后,该队列中所有的消息都存在相同的过期时间
              • 单个消息设置:设置消息属性 expiration 参数的值,单位为毫秒
              • 同时使用以上两种方式,会以过期时间小的那个数值为准,当消息达到过期时间还没有被消费就会成为死信消息
          • 延迟队列
            • 延迟队列存储的是延迟消息
            • 延迟消息指 当消息被发布出去后,并不立即投递给消费者,而是在指定时间后投递
            • RabbitMQ 不直接支持延迟队列,可通过死信队列实现。在死信队列中,可以为普通交换器绑定多个消息队列,假设绑定过期时间为5分钟,10分钟和30分钟,3个消息队列,然后为每个消息队列设置DLX,为每个DLX关联一个死信队列,当消息过期后,被转存到对应的死信队列中,然后投递给指定的消费者消费
      • Rocket MQ
        • 刷盘策略
          • 同步刷盘
            • 生产者发送消息->Memory(Master1)->同步到Disk(Master1)-》返回
          • 异步刷盘
            • 生产者发送消息->Memory(Master1)->异步到Disk(Master1) 并返回
        • Rocket MQ中Broker的部署方式
          • 单机Broker模式
          • 多Master模式
          • 多Master多Slave模式(一般用于生产环境)
        • 几百万的消息积压如何解决
          • 消费者端临时扩容
          • 队列临时扩大10倍、消费端服务器扩大10倍
        • 性能高的原因
          • 网络通信层:使用Netty NIO框架
          • 使用大量多线程、异步
          • 使用零拷贝技术(MMAP)
          • 采用文件存储,顺序读写
          • 锁优化(CAS机制 无锁化)
          • 存储设计:读写分离
        • 存储机制
          • 生产者发送的消息-》Commit Log文件
          • 异步线程监听 Commit Log文件,Commit Log文件主要用来写文件
          • 异步线程会将Commit Log文件内容的索引信息存储在Comsumequeue队列中
          • 消息的消费从Comsumequeue队列中获取索引后再获取数据
          • 增加 Comsumequeue 的目的在于防止大并发情况下消息topic增多产生的线程IO切换频繁问题
        • 如何保证高可用
          • master节点与slave节点之间 同步复制
          • master内部 Memory与Disk之间 异步刷盘
          • 多主多从模式

 

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

远方的、远方的、、、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值