当前位置: 首页 > article >正文

java面试-每日随机(1014)

1、zk如何进行故障转移?

在 Zookeeper 集群中,当节点故障时,集群需要自动剔除故障节点并进行故障恢复,确保集群的高可用性和一致性。具体来说,当跟随者节点故障时,集群可以继续运行,但当领导节点故障时,需要进行领导节点的重新选举。

节点故障检测与剔除

心跳机制:

每个 Zookeeper 节点定期发送心跳消息给领导节点。

领导节点监控所有跟随者节点的心跳,如果在一定时间内未收到某个节点的心跳消息,认为该节点故障。

剔除故障节点:

领导节点将故障节点从活跃节点列表中移除,不再向其广播事务。

故障节点重新上线后,需要重新加入集群并同步数据。

领导节点故障处理

故障检测:

当跟随者节点检测到领导节点未发送心跳消息或未响应请求,认为领导节点故障。

跟随者节点进入领导选举模式。

领导选举:

所有活跃节点参与领导选举过程。

使用 ZAB 协议(Zookeeper Atomic Broadcast)进行选举,选出新的领导节点。

选举过程保证新的领导节点拥有最新的事务日志。

数据同步:

新的领导节点选出后,将其最新状态广播给所有跟随者节点。

跟随者节点与新的领导节点进行数据同步,确保数据一致性。

恢复服务:

数据同步完成后,集群恢复正常服务,新的领导节点开始处理客户端请求。

2、ZAB协议知道吗?

ZAB 协议是为分布式协调服务 Zookeeper 专门设计的一种支持 崩溃恢复 和 原子广播 协议,基于该协议,Zookeeper 实现了一种 主备模式 的系统架构来保持集群中各个副本之间数据一致性。

3、遇到过zk节点过多的情况吗?

当Zookeeper中的某个节点子节点数量过多时,使用`rmr`命令删除可能会报错。可以尝试修改操作或者通过Java代码进行删除,如使用`java -classpath ... com.xxx.server.RMRLock`来解决此问题。

4、redis集群如何故障转移?

Redis集群自身实现了高可用。 高可用首先需要解决集群部分失败的场景: 当集群内少量节点出现故障时通过自动故障转移保证集群可以正常对外提供服务。

Redis集群内节点通过ping/pong消息实现节点通信,消息不但可以传播节点槽信息,还可以传播其他状态如:主从状态、节点故障等。因此故障发现也是通过消息传播机制实现的,主要环节包括:主观下线(PFAIL-Possibly Fail)和客观下线(Fail)

主观下线:指某个节点认为另一个节点不可用,即下线状态,这个状态并不是最终的故障判定,只能代表一个节点的意见,可能存在误判情况。

客观下线:指标记一个节点真正的下线,集群内多个节点都认为该节点不可用,从而达成共识的结果。如果是持有槽的主节点故障,需要为该节点进行故障转移。

故障恢复

故障节点变为客观下线后,如果下线节点是持有槽的主节点则需要在它的从节点中选出一个替换它,从而保证集群的高可用。下线主节点的所有从节点承担故障恢复的义务,当从节点通过内部定时任务发现自身复制的主节点进入客观下线时,将会触发故障恢复流程

每个从节点都要检查最后与主节点断线时间,判断是否有资格替换故障的主节点。如果从节点与主节点断线时间超过cluster-node-time*cluster-slave-validity-factor,则当前从节点不具备故障转移资格,cluster-slave-validity-factor设置为0代表任何slave都可以被转换为master,默认为10

当从节点符合故障转移资格后,更新触发故障选举的时间,只有到达该时间后才能执行后续流程,这里之所以采用延迟触发机制,主要是通过对多个从节点使用不同的延迟选举时间来支持优先级问题。复制偏移量越大说明从节点延迟越低,那么它应该具有更高的优先级来替换故障主节点,所有的从节点中复制偏移量最大的将提前触发故障选举流程

当从节点定时任务检测到达故障选举时间(failover_auth_time)到达后,发起选举流程。

当从节点收集到足够的选票之后,触发替换主节点操作:

当前从节点取消复制变为主节点。

执行clusterDelSlot操作撤销故障主节点负责的槽,并执行clusterAddSlot把这些槽委派给自己

向集群广播自己的pong消息,通知集群内所有的节点当前从节点变为主节点并接管了故障主节点的槽信息。

5、redis对大key如何处理?

Redis 中的大 key 问题通常是指一个单独的 key 占用了过多的内存,例如一个非常大的哈希表、列表、集合或有序集合。大 key 会导致一系列问题,比如执行操作时会出现延迟,甚至可能会阻塞整个 Redis 实例。

解决大 key 问题通常有以下策略:

发现大 key:使用 Redis 提供的命令比如 INFO memory、MEMORY USAGE key 或者使用 Redis 的 --bigkeys 的方式来检测和发现大 key。

分析:分析为何会产生大 key,并根据业务场景考虑是否可以通过更好的设计来避免大 key 的产生。

拆分大 key:如果大 key 是不可避免的,尝试将其拆分成更多的小 key 来分散数据。比如:对于列表、集合和有序集合,可以通过散列(hashing)某个属性,把它们分散到不同的小 key 中。对于哈希表,可以使用一致性哈希等算法将大哈希表拆分成多个小哈希表。

渐进式删除:如果要删除大 key,为了避免一次性删除所带来的长时间阻塞,可以使用 Redis 的 HSCAN、SSCAN、ZSCAN 和 SCAN 命令,配合 DEL 命令对大 key 进行渐进式删除。

使用过期时间:对于一些大 key,如果业务允许,可以给它们设置合理的过期时间(TTL),可以使用 EXPIRE 命令来设置。这样随着时间流逝,这些大 key 会被自动清理掉。

数据迁移:如果单个 Redis 实例无法处理大 key 问题,可以考虑将数据迁移到使用集群,以此来分散负载和存储。

优化数据结构:优化数据结构可能是处理大 key 最有效的方法。比如使用更加内存效率高的数据结构。如果不必使用哈希表、列表、集合或有序集合的全部特性,可以考虑使用更简单的数据结构来替代。

内存优化:对于某些数据类型,Redis 提供了内存优化选项,比如使用哈希表优化指令 HSET 的 'rehash' 机制。

监控:定期监控 Redis 实例的内存使用情况和各种 key 的大小,能够帮助及时发现并处理大 key 问题。

适当的设计和策略可以减少大 key 对 Redis 性能的影响,确保 Redis 实例运行稳定。在解决大 key 问题时,应尽量避免在高流量期间操作,以免对线上服务造成不必要的影响。

6、用redis做过延时队列吗?

Redis 本身是不支持延时队列的,但是我们可以利用 Redis 一些特定的数据结构和特性来实现延时队列。

基于 Redis 目前有三种方式可以实现延时队列:

1.利用 Redis 过期消息实现延时队列

Redis 允许我们为每一个 key 设置过期时间,在 key 过期时,Redis 可以配置为发送一个过期事件。在应用程序通过监听这个过期事件,就可以实现延迟队列了。

2.使用 Sorted Set 实现延时队列

redis的zset数据结构中的每个元素都有一个分数score和一个值value,我们可以将任务的执行时间戳作为score,

将任务数据作为value,将任务插入到zset中,每个任务有一个唯一的id(比如订单id),以及任务执行时间(比如30min),

任务内容(比如订单超时支付系统自动取消)等信息体。然后另起一个线程,该线程会周期性地从zset中取出score最小

(即最早要执行的)的任务,如果该任务的score小于当前时间戳,则执行任务,否则等待一段时间再次检查,

直到任务可以执行,执行任务后,通过Redis的remove命令删除已经成功执行的任务即可。

3.Redisson实现延迟对列

Redisson 提供的延迟队列(Delayed Queue)是它基于 Redis 的发布/订阅机制和 zset 实现的一种高级数据结构,用于处理需要延迟执行的任务。

其实现原理是:Redisson 将任务按照预定的执行时间存储在 zset 中,任务的执行时间作为 score,任务本身序列化后的数据作为 member。同时,Redisson 会在后台持续监控这个 ZSET,一旦发现有符合执行条件(当前时间 >= score)的任务,就会自动将这些任务转移到另一个 RQueue(Redisson 的队列实现)中,应用程序只需要从 RQueue 中取出任务执行即可。

7、有一种说法,mysql单表超过2000W,性能会降低,为什么?

这种说法的原因主要是根据mysql在innodb引擎下一般支持的最大行树来说的,假设我们是三层B+树,每个页默认的大小是16kB,抛去页头、页目录、页尾,剩余的数据区大概有15kB的大小。

同时再假设我们一行的数据包括索引和页号算1KB,能大概计算出mysql在单表的情况下支持的上限是在2400W行左右。那么当数据超过这个之后,可能会因为在内存中读不全页的索引,导致磁盘的IO操作,进而导致性能的极剧下降。

8、假如有个大表,用的自增,如何拆分成多个表?

水平分割(Sharding 或 Horizontal Partitioning)

按范围分割:可以根据日期或ID范围来分割数据。例如,可以创建几个表,每个表存储不同范围内的ID数据。

按哈希分割:根据某个字段的哈希值来决定数据存储的位置。例如,可以使用MOD运算符根据自增主键值对某个数取模,得到的结果决定了记录应该存放在哪个表中。

垂直分割(Vertical Partitioning)

按列分割:将一个表中的某些列移动到另一个表中。这种方法适用于某些列访问频率较高而其他列较少被访问的情况。但是,对于自增主键来说,这种分割方式并不常见,因为主键通常是表的一部分,且是每个记录的唯一标识符。

注意事项:

保证唯一性:如果新表仍然需要自增主键,那么你需要确保每个表中的主键是唯一的。可以通过不同的起始点设置,或者在生成主键时加上前缀或其他标识来区分。

应用逻辑修改:拆分后,应用程序需要知道如何访问这些新的表。这可能涉及到修改应用程序代码,或者使用存储过程、视图等手段来抽象表的逻辑。

维护关联关系:如果有外键关联,则需要特别注意拆分后如何维持这些关联关系。

性能考虑:拆分后,查询可能变得复杂,尤其是当需要从多个表中获取数据时。因此,设计时要考虑查询效率的问题。

实施步骤:

规划拆分方案:确定拆分的原则,比如按日期、地区、用户等。

备份数据:在任何数据操作之前,确保数据的安全性。

创建新表结构:根据拆分原则,创建相应的表结构。

迁移数据:将数据从原始表迁移到新表中。这可以通过SQL语句批量操作完成。

调整应用程序:更新应用程序,使其能够正确地与新的表结构交互。

测试验证:确保所有功能正常工作,并且性能有所提升。

9、spring声明式事务,方法前加final会失效吗,原理是什么?

在Spring框架中,使用声明式事务管理通常通过@Transactional注解来实现。这个注解可以应用于类级别或方法级别,用来标记需要事务管理的方法或整个类的所有公共方法。

关于final关键字的作用以及它是否会影响@Transactional注解的行为,我们可以这样理解:

final关键字的作用:

final关键字用于声明一个类、方法或变量为不可更改的。对于类来说,表示该类不能被继承;对于方法来说,表示该方法不能被子类覆盖;对于变量来说,表示该变量一旦赋值就不能改变其值。

Spring AOP的工作机制:

Spring使用AOP(面向切面编程)来实现声明式事务管理。当使用@Transactional注解时,Spring会在目标方法调用前后添加事务管理的逻辑。这是通过创建代理对象来实现的,代理对象拦截了目标方法的调用,并在其前后执行事务相关的代码。

final方法与Spring AOP的关系:

如果一个方法被声明为final,则该方法不能被子类覆盖。然而,Spring AOP主要是通过动态代理或者CGLIB字节码生成技术来创建代理对象的。对于普通的方法(非private),Spring默认使用JDK动态代理;对于final方法或者private方法,则使用CGLIB来创建代理。

使用CGLIB创建代理时,实际上是创建了一个子类来继承原始类,并重写(或说是增强)其中的方法。但是,由于final方法不能被子类覆盖,所以如果一个方法被声明为final,那么Spring就无法直接通过CGLIB来增强这个方法,从而导致@Transactional注解可能不起作用。

10、死信队列了解吗,什么情况下会变成死信?

死信队列(Dead Letter Queue, DLQ)是一种处理无法被正常消费的消息的机制。在消息队列系统中,当一条消息无法被正确处理时,这条消息就会被发送到一个专门的队列中,这个队列就是死信队列。死信队列的主要目的是防止消息在原队列中无限循环,同时也便于对问题消息进行排查和分析。

以下是一些常见的消息会变成死信的情况:

消息过期:如果消息在队列中等待的时间超过了设定的有效期(TTL,Time To Live),那么这条消息就会成为死信。

达到最大尝试次数:消费者在处理消息时如果多次尝试失败(如达到预设的最大重试次数),这条消息也会被视为死信。

消费者拒绝消息:消费者在接收到消息后显式地拒绝消息,并且设置了不再重新入队(requeue=false),那么这条消息就会被丢弃,成为死信。

队列满了:如果目标队列已满,而生产者继续发送消息,那么新消息可能会被丢弃,成为死信。

消息格式错误:如果消息格式不符合消费者的预期,导致无法解析,也可能成为死信。

如何配置死信队列?

以RabbitMQ为例,配置死信队列通常涉及以下几个步骤:

创建具有TTL的队列:通过设置队列级别的TTL属性,使得超过生存时间的消息自动成为死信。

设置消息TTL:在发布消息时可以指定每条消息的TTL,使得消息在过期后成为死信。

设置最大重试次数:可以在消费者端实现逻辑,当达到最大重试次数后,将消息发送到DLQ。

拒绝消息时设置不重试:消费者在拒绝消息时,需要设置requeue=false,以确保消息不会重新入队,而是被发送到DLQ。

绑定死信队列:在声明原队列时,通过x-dead-letter-exchange和x-dead-letter-routing-key参数指定死信队列的交换机和路由键。


http://www.kler.cn/a/354888.html

相关文章:

  • 高仿CSDN编辑器,前端博客模板
  • 面向微服务的Spring Cloud Gateway的集成解决方案:用户登录认证与访问控制
  • Linux:进程概念
  • 19_HTML5 Web Workers --[HTML5 API 学习之旅]
  • 面向对象编程概念
  • 条款17 理解特殊成员函数的生成
  • 接口测试常用工具及测试方法
  • Android 第5种启动模式:singleInstancePerTask
  • Leetcode 单词规律
  • 15分钟学Go 实战项目一:命令行工具
  • JavaWeb合集02-Vue基础内容
  • 虚拟化桌面
  • Parasoft C/C++test CT 荣获TÜV SÜD认证,在安全关键应用开发与验证方面达到最佳实践标准
  • 空间解析几何 3:空间点到线段和平面的距离【附MATLAB代码】
  • 面对专利档案管理难题,我们该怎么办?
  • 用Java爬虫API,轻松获取电商商品SKU信息
  • 怎么在地图导航上添加自己的店面定位?
  • Centos7默认的python版本是2.7,现在很多新开发的python均需要3.X以上。下面升级centos的预装python版本到最新。
  • Python123练习题
  • Python网络爬虫:分析淘宝商品热度与销量[进阶深度优化]
  • 查看SQL执行计划 explain
  • learn C++ NO.26——哈希应用
  • 低代码可视化-uniapp购物车页面-代码生成器
  • Scala中reduce函数
  • 每天一个数据分析题(五百零七)- 集成学习算法
  • 【牛客刷题】笔记1