Java ZooKeeper-RocketMQ 面试题

Java ZooKeeper-RocketMQ 面试题

  • 前言
  • 1、谈谈你对ZooKeeper的理解 ?
  • 2、Zookeeper的工作原理(Zab协议)
  • 3、谈谈你对分布式锁的理解,以及分布式锁的实现?
  • 4、 zookeeper 是如何保证事务的顺序一致性的?
  • 5、 zookeeper主从同步机制:
  • 6、分布式集群中为什么会有 Master?
  • 7、 zk 节点宕机如何处理?
  • 8、说几个 zookeeper 常用的命令?
  • 9、ZK 如何投票实现Leader选举?
  • MQ中间件
  • 10、什么是 RocketMq?
  • 11、什么是消息队列?
  • 12、RocketMq的路由类型和发送消息的方式?
  • 13、死信消息的生命周期?
  • 14、如何保证消息的顺序性?
  • 15、如何防止消息丢失?
  • 16、如何保证消息不被重复消费?
  • 17、MQ处理消息失败了怎么办?
  • 18、消息基于什么传输?
  • 19、RocketMQ 底层原理?
  • 20、RocketMQ为什么速度快, 吞吐量?
  • 21、什么是零拷贝?
  • 22、死信队列?
  • 总结


前言

最新的 Java 面试题,技术栈涉及 Java 基础、集合、多线程、Mysql、分布式、Spring全家桶、MyBatis、Dubbo、缓存、消息队列、Linux…等等,会持续更新。

如果对老铁有帮助,帮忙免费点个赞,谢谢你的发财手!

1、谈谈你对ZooKeeper的理解 ?

ZooKeeper 是一个开源的分布式协调服务,为分布式系统提高了一系列的服务,提供的服务包括了:服务注册与订阅、统一命名服务、集群管理、分布式锁和分布式通知等。
Zookeeper提供了三个核心功能,分别是:文件系统、监听机制和集群管理

  • 1、文件系统
    Zookeeper存储数据的结构,类似于一个文件系统,每个节点(znode)都是类似于K-V的结构,每个节点的名字相当于key,每个节点保存的数据,相当于value。
  • 2、监听机制
    客户端先向ZooKeeper服务端的某个节点注册一个 Watcher 监听,当监听的数据状态发生变化时,服务端会向指定客户端发送一个事件通知,客户端收到事件以后,调用对应的回调方法,完成事件变更的通知。
  • 3、集群管理
    Zookeeper提供了CP的模型,来保证集群中的每个节点的数据一致性。
    zookeeper本身是一个集群结构,它有3种角色:
    leader领导者:处理所有的事务请求(写请求),也可以处理读请求,集群中只有一个leader;
    follower追随者:只能处理读请求,参与leader选举
    observer观察者:只能处理读请求,不参与leader选举,作用是为了提升集群的读性能

2、Zookeeper的工作原理(Zab协议)

  • Zookeeper的工作原理核心是原子广播机制,这个机制保证了各个节点之间的数据一致性,实现这个机制的协议叫做Zab协议。
    Zab协议有两种模式,分别是恢复模式(选主)和广播模式(同步),当服务启动或者 Leader 服务器宕机,Zab就进入了恢复模式,此时不对外提供服务。
  • 首先选举出新的 Leader 服务器,然后与其他的Follower 服务器进行数据同步,当集群中超过半数机器完成数据同步之后,退出恢复模式进入广播模式,然后就可以接收客户端的事务请求了。

3、谈谈你对分布式锁的理解,以及分布式锁的实现?

  • 分布式锁,是一种跨进程的跨机器节点的互斥锁,它可以保证同一时刻只能有一个线程去访问共享资源。
    目前实现分布式锁最常用的中间件是 Redis 和 Zookeeper:
  • Redis:利用它提供的 SETNX 命令,如果设置key返回1,说明获取锁成功,返回0获取锁失败。然后还可以通过 EX参数来设置key的过期时间,从而避免死锁问题。
    但也可能存在一些极端情况,比如锁过期了,但是业务逻辑还没处理完。这种极端情况可以使用Redisson 客户端来实现,Redisson 中有一个 watchdog 的机制,翻译过来就是看门狗,它是基于Netty下面的一个时间轮的实现类来实现。(getLock、lock、unlock)
  • Zookeeper:利用它提供的有序节点,当线程创建节点后,如果该节点是当前目录下所有节点序号最小的节点,则认为获取锁成功。如果不是最小的节点,则对该节点序号的前一个节点添加一个监听事件,当监听的节点释放锁之后,触发回调通知,从而再次去尝试抢占锁。
    总的来说,这两种方案都有各自的优缺点:
    Redis它获取锁的方式简单粗暴,如果获取不到锁,会不断尝试获取锁,消耗性能比较大,但是实现难度比较低。
    Zookeeper如果获取不到锁,只需要添加一个监听器就可以了,消耗性能比较小,但是实现难度比较高。

4、 zookeeper 是如何保证事务的顺序一致性的?

  • zookeeper采用了全局递增的事务Id 来标识,所有的 proposal(提议)在被提出的时候都会加上 zxid,zxid实际上是一个64位的数字,高32位是epoch(时期; 纪元; 世; 新时代)用来标识leader是否发生改变,如果有新的leader产生出来,epoch会自增,然后低32位用来递增计数。
    当产生新的提议时,zookeeper会采用数据库的二阶段提交,首先会向其他的节点发出事务执行请求,如果超过半数的机器都能执行,那么就会提交事务。

5、 zookeeper主从同步机制:

  • 1、当leader 接受到消息请求后,会给消息加上一个全局的事务Id (zxid);
  • 2、leader将带有zxid的消息作为一个提案(proposal)分发给所有的follower;
  • 3、当follower接受到提案后,先把提案写到磁盘,写入成功以后再向leader回复一个ack;
  • 4、当leader 接受到半数以上ack,就会向follower发送提交commit命令,同时自己也执行;
  • 5、当follower接受到commit命令以后,就会提交该消息,从而实现数据同步。

6、分布式集群中为什么会有 Master?

在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能。

7、 zk 节点宕机如何处理?

  • 1、如果是一个 Follower 宕机,只要超过半数的节点正常,集群就能正常提供服务,否则集群就会失效;
  • 2、如果是一个 Leader 宕机,Zookeeper会进入恢复模式,重新选举出新的 Leader。
    Zookeeper本身也是集群,推荐不少于 3 个服务器,而且最好奇数个。

8、说几个 zookeeper 常用的命令?

常用命令:ls get set create delete 等。

9、ZK 如何投票实现Leader选举?

如果 Leader 节点宕机了,为了保证集群继续提供服务,Zookeeper 需要从剩下的 Follower 节点里面去选举一个新的节点作为 Leader,也就是所谓的 Leader 选举。具体的实现是:

  • 1、每一个节点都会向集群里面的其他节点发送一个票据 Vote,这个票据包括三个属性:epoch逻辑时钟,zxid事务id,myid服务器id;然后第一轮投票都会投给自己。
  • 2、每个节点把收到的票据和自己节点的票据做比较,根据 epoch、zxid、myid 的顺序逐一比较,以值最大的一方获胜,比较结束以后就把票投给获胜的节点;
  • 3、通过多轮投票以后,以少数服从多数的方式,最终获得票数最多的节点成为Leader。
    到这里,leader选举就结束啦。
    其中epoch,逻辑时钟,用来标识当前票据是否过期;zxid,事务id,用来表示当前节点最新存储的数据的事务编号; myid,服务器id,在 myid 文件里面填写的;

MQ中间件

10、什么是 RocketMq?

  • RocketMq是一个基于 AMQP 高级消息队列协议的中间件,接受并转发消息。它有4个核心组件,分别是:
  • producer生产者:负责生产和发送消息到 Broker;
  • Exchange交换机:按照一定的规则将消息路由转发到某个队列,对消息进行过虑;
  • Queue队列:用来存储消息,并把消息转发给指定的消费者;
  • consumer消费者:负责从 Broker 中获取消息,并进行相应处理;
    它的工作原理是生产者把消息发送到Exchange交换机上。Exchange交换机把收到的消息根据路由规则,转发给绑定的queue队列,队列再把消息投递给订阅了这个队列的消费者,从而完成消息的异步通讯。

11、什么是消息队列?

消息队列 Message Queue,简称 MQ。
消息队列有很多使用场景,比较常见的有3个:解耦、异步、削峰。

  • 1、应用解耦:把相关联的系统进行职责解耦,比如:生成订单会调用仓库管理系统或积分系统。
  • 2、异步处理:不需要立即处理消息,提高系统的性能,比如:用户注册发送验证码、下单短信通知、发送优惠券等。
  • 3、流量削峰:能够有效的顶住瞬间高并发,防止服务器承受不住导致崩溃,比如秒杀、限时抢购优惠券等。
    比如吞吐量低的中小型公司,一般用 ActiveMQ、RabbitMQ 较为合适,
    大数据、吞吐量高的大型公司一般选用 Kafka 和 RocketMQ。

12、RocketMq的路由类型和发送消息的方式?

它的工作原理是生产者把消息发送到Exchange交换机上,Exchange交换机把收到的消息根据路由规则,转发给绑定的queue队列,最后再把消息投递给订阅了这个队列的消费者,从而完成消息的异步通讯。
在RabbitMQ中,交换机常见的有3种类型,分别是Fanout、Direct 、Topic:

  • Fanout(扇出交换机):类似于广播机制,将消息转发给到所有绑定的队列上,与routingKey(路由键)无关;
  • Direct(直连交换机):完整匹配方式,也就是Routing key和Binding Key完全一致,才把消息发给该队列;
  • Topic(主题交换机):就是Routing Key加了通配符,符合匹配规则的Queue队列都会收到这个消息,#:代表0个或多个单词,*:代表一个单词。

13、死信消息的生命周期?

  • 1、消费者消费业务消息时发生异常,就会返回nck或者reject操作;
  • 2、那么这些消息就会被投递到死信交换机中;
  • 3、死信交换机将消息发送到相应的死信队列;
  • 4、死信队列可以定时重新投递到Broker中,也可以由死信消费者消费。

14、如何保证消息的顺序性?

这个问题是由于不同的消息都发送到了同一个 queue队列中,而这个queue队列又被多个消费者消费。
解决这个问题,我们可以给 RabbitMQ 创建多个 queue队列,每个队列对应一个消费者。比如生产者发送消息的时候,同一个订单号的消息发送到同一个 queue队列中,由于同一个 queue队列的消息是有序的,那么同一个订单号的消息就只会被一个消费者顺序消费,从而保证了消息的顺序性。

15、如何防止消息丢失?

  • 1)、使用事务消息
  • 2)、使用消息确认机制
    消息丢失的场景有下面几种:
  • 1)、生产者发送消息到MQ的过程中丢失
    解决方法: 在生产者端开启comfirm 确认模式,每个消息会分配一个唯一的 id,如果MQ写入了内存中, 就会返回一个ack,告诉你说这个消息ok了,如果MQ没有写入这个消息,会回调一个nack接口,告诉你这个消息失败了,你可以进行重试或抛弃此条消息。
  • 2)、MQ收到消息,写入到内存中,还没消费,服务挂掉了,数据都会丢失
    解决方法:将消息持久化到磁盘,有两个步骤:
    第1步:把该消息设置为持久化,即deliveryMode设置为2,第3个参数设置如下:
    channel.basicPublish(“exchange”, “routingKey”, MessageProperties.PERSISTENT_TEXT_PLAIN, " message".getBytes());
    第2步:把该queue队列设置为持久化,即durable=true,第2个参数设置为true,
    channel.queueDeclare(QUEUE_NAME, true, false, false, null);
  • 3)、消费者刚拿到消息,还没处理,服务挂掉了,MQ又以为消费者处理完了
    解决方式:首先关闭 RabbitMQ 的自动 ack,然后消费者在处理完消息之后,再手动返回ack。这样可以保证,如果你还没处理完,就不会返回ack,那队列就不会删除该消息。
    (关闭 RabbitMQ 的自动 ack,即autoAck=false,第2个参数设置为false
    channel.basicConsume(QUEUE_NAME, true, new DefaultConsumer(channel){});)

16、如何保证消息不被重复消费?

我们为了消息的可靠性,采用了手动ack机制;如果消费者在处理完一个消息之后,还没有手动调用ack,服务就挂了,MQ以为你还还没处理,就把这个消息投递给其他的消费者,就导致了消息被重复消费。
我觉得这个问题可以分为2种场景来对待:

  • 第1种幂等性场景:就是说消息重复消费和消费一次产生的影响是一样的,可以不用处理,比如Redis的set操作,它是天然幂等性的;
  • 第2种非幂等性场景:把消息唯一id保存到 mysql 或者 redis 里面,在处理消息之前先去 mysql 或者 redis 里面,判断一下是否已经消费过了。

17、MQ处理消息失败了怎么办?

一般生产环境中,都会在使用MQ的时候设计两个队列:一个是核心业务队列,一个是死信队列。核心业务队列,就是比如专门用来给订单系统发送订单消息的,然后另外一个死信队列就是用来处理异常情况的。

18、消息基于什么传输?

RabbitMQ 使用channel通道的方式来传输数据,通道是建立在真实的 TCP 连接内的虚拟连接,且通道数量没有限制,大大提升了MQ的处理性能。

19、RocketMQ 底层原理?

RocketMQ 架构主要包含以下四个部分:

  • 1、NameServer:是一个简单的Topic路由注册中心,支持Broker的注册与发现,主要有两个功能:Broker管理(提供心跳检测机制)和路由信息管理(保存Broker的路由信息和用于客户端查询的队列信息);
  • 2、BrokerServer:RocketMQ 的核心组件,主要负责消息的
    1、存储:CommitLog(存储消息的文件);
    2、投递:ConsumeQueue(消息消费队列);
  • 3.查询:IndexFile(索引文件);
  • 4.以及维护消费者的Topic订阅信息和保证服务高可用;
    1、Producer:消息生产者,往Broker发送指定Topic的消息。
    2、Consumer:消息消费者,主动拉取消息来消费,支持集群方式(同一Topic下的一条消息只会发送到同一消费组中的一个消费者)和广播方式(所有的消息会广播发送到所有的消费者)。

20、RocketMQ为什么速度快, 吞吐量?

因为使⽤了顺序存储、页缓存(Page Cache)和异步刷盘;我们在写⼊commitlog的时候是顺序写⼊的,这样⽐随机写⼊的性能就会⾼很多,而且它不是直接写⼊磁盘,⽽是先写⼊页缓存,开启一个异步线程通过零拷贝机制,定时的将缓存中的数据刷到磁盘中,从而保证消息的快速读写。

21、什么是零拷贝?

  • 传统⽂件复制方式:需要对⽂件在内存中进⾏四次复制(内核态到用户态的来回复制)。
  • 零拷⻉:就是减少内核态到用户态的来回复制,它是通过内存映射的机制,直接把内核态里的数据映射到用户态,对文件的操作转化为对内存地址的操作;
    通常有两种⽅式,mmap(RocketMq)和sendfile(kafka)。
    在这里插入图片描述

22、死信队列?

当一条消息消费失败时,经过多次重试依然失败,为了保证消息数据不丢失,需要将消息投入到死信队列中。
死信的来源:

  • 1、消息 TTL(存活时间)过期
  • 2、队列满了,无法再添加数据到队列中
  • 3、消息被拒绝(消费方拒绝应答:basic.reject 或 basic.nack)并且不放回队列中( requeue=false)

总结

都已经看到这里啦,赶紧收藏起来,祝您工作顺心,生活愉快!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/506168.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[vscode] 1. 在编辑器的标签页下显示文件目录(标签页显示面包屑) 2. 在标题栏上显示当前文件的完整路径

1. 标签页显示面包屑 view->Appearance->Breadcrumbs 2. 在标题栏上显示当前文件的完整路径 搜索 window.title将原来的值activeEditorShort 修改为 activeEditorMedium 参考: vscode在编辑器的标签页下显示文件目录(标签页显示面包屑&#xf…

【Java数据结构】——二叉搜索树

目录 🎈概念 🎈操作-查找 🎈操作-插入 🎈操作-删除(难点) 🎈概念 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树 : 若它的左子树不为空&a…

编码器原理图

操作 旋转编码器提供两种交互方式: 每次用户旋转旋钮时,都会在 DT 和 CLK 引脚上产生低电平信号: 顺时针旋转会先使CLK引脚变为低电平,然后DT引脚也变为低电平。 逆时针旋转会使 DT 引脚首先变为低电平,然后 CLK 引脚…

力扣● 1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零

● 1049. 最后一块石头的重量 II 题目要把石头分成两堆,这两堆的重量差值最小。相撞之后剩下的石头重量就最小。其实就是要尽量把石头分为差不多重量的两堆,和昨天的● 416. 分割等和子集相似,这样就转换成了01背包问题。 和416题一样&…

医疗行业数据分析,为医疗提质增效提供科学支持

信息化时代的到来,医疗行业数据分析已成为提升医疗服务质量和效率的重要手段。医院拥有大量的医疗数据,医疗数据中包含着很多宝贵的信息与规律,通过深入的数据分析,能够为决策者提供直观、深入的数据洞察,帮助医疗服务…

docker 转为docker-compose(composerize 命令)

可以使用Composerize将Docker命令转换为Docker Compose文件。 例如:将docker run命令转换为Docker Compose格式,只需用Composerize运行它,如下所示: composerize docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/…

【Django】执行查询——查询JSONField

JSONField 本篇的例子以下面这个模型为基础: from django.db import modelsclass Dog(models.Model):name models.CharField(max_length200)data models.JSONField(nullTrue)def __str__(self):return self.name保存和查询None值 在使用JSONField时&#xff0c…

CI/CD笔记.Gitlab系列.`gitlab-ci.yml`中的头部关键字

CI/CD笔记.Gitlab系列 gitlab-ci.yml中的头部关键字 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netMy WebSite:http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.ne…

JVM(2)

JVM类加载 指的是java进程运行时,需要把.class文件从硬盘加载到内存,并进行一系列校验解析的过程. 核心: .class文件>类对象; 硬盘>内存. 类加载过程 在整个JVM的执行流程中,和程序员关系最密切的就是类加载的过程了,所以我们来看一下类加载的执行流程. 对于一个类…

MySQL NDB Cluster 分布式架构搭建 自定义启动与重启Shell脚本

此次NDB Cluster使用三台虚拟机进行搭建,一台作为管理节点;而对于另外两台服务器,每一台都充当着数据节点和SQL节点的角色。注意不是MGR主从复制架构,而是分布式MySQL架构。 创建 /var/lib/mysql-cluster/config.ini Cluster全局…

Matlab 机器人工具箱 Link类

文章目录 1 Link类1.1 机械臂Link类1.2 构造函数1.3 信息/显示方法1.4 转换方法1.5 操作方法1.6 测试方法1.7 重载操作1.8 属性(读/写)1.9 例子2 Link.Link2.1 创建机器人连杆对象2.2 OPTIONS2.3 注意2.4 旧语法2.5 例子3 Link的其他函数3.1 Link.A3.2 Link.char3.3 Link.displ…

【StarryCoding P99】三角形数字的位置 题解(动态规划+组合数学+滚动数组)

[P99] 三角形数字的位置 我们都知道著名的杨辉三角,长下面这个样子: 11 11 2 1 1 3 3 1 ...将他们从上往下可以排列为:1,1,1,1,2,1,1,3,3,1,... 这样一个数列。 有 q q q次询问,每次询问请你求出数字 N N N第一次在数列中出现的…