京东-CHO一面(Java校招)主要围绕简历技术栈展开,涉及ZooKeeper、Redis、JVM、MySQL、MQ等技术领域,同时穿插项目相关问题及扩展技术问题。具体内容如下:
一、ZooKeeper相关问题- ZooKeeper集群如何进行故障转移ZooKeeper集群通过ZAB协议(ZooKeeper Atomic Broadcast)实现故障转移。当Leader节点故障时,Follower节点会发起选举,通过投票选出新的Leader。选举过程中,节点会进入LOOKING状态,通过比较zxid(事务ID)和myid(节点ID)确定优先级,最终选出拥有最新zxid且myid最大的节点作为新Leader,恢复集群服务。
- ZooKeeper是否遇到节点过多的情况ZooKeeper集群节点数量通常建议为奇数(如3、5、7个),以避免脑裂问题。节点过多(如超过7个)会导致选举时间延长、网络通信开销增大,反而降低性能。实际场景中,需根据业务规模和性能需求权衡节点数量。
二、Redis相关问题- Redis集群如何进行故障转移Redis集群通过Sentinel或Cluster模式实现故障转移。Sentinel模式中,Sentinel节点监控主从节点状态,当主节点故障时,Sentinel会选举新的主节点,并通知从节点切换。Cluster模式则通过Gossip协议传播节点状态,故障转移由集群内多数节点协商完成。
- Redis如何保证高可用通过主从复制(数据冗余)、Sentinel监控(自动故障转移)、Cluster分片(负载均衡)实现高可用。同时,持久化机制(RDB/AOF)防止数据丢失。
- Redis主从同步的过程主从同步分为全量同步和增量同步。全量同步时,主节点生成RDB快照并发送给从节点,从节点加载后,主节点将后续写命令通过缓冲区同步给从节点。增量同步则通过复制缓冲区(repl_backlog_buffer)记录主节点写命令,从节点通过偏移量(offset)获取缺失数据。
- RDB是什么RDB是Redis的持久化方式之一,通过定时生成数据快照(二进制文件)保存到磁盘。优点是恢复速度快、适合备份;缺点是可能丢失最后一次快照后的数据,且大文件生成可能影响性能。
- 项目Redis淘汰策略常见策略包括:
volatile-lru:淘汰最近最少使用的过期键。
allkeys-lru:淘汰所有键中最近最少使用的。
volatile-ttl:淘汰即将过期的键。
noeviction:不淘汰,内存不足时返回错误(默认)。需根据业务场景(如缓存命中率、数据重要性)选择策略。
- Redis大Key应对方案大Key(如大Hash、大List)会导致内存不均、阻塞请求。解决方案包括:
拆分大Key为多个小Key(如按时间分片)。
使用压缩算法(如Snappy)减少存储空间。
避免存储大文本或二进制数据,改用外部存储(如OSS)。
- 是否用Redis做过延时队列可通过Redis的Sorted Set(ZSET)实现延时队列:将消息作为成员,到期时间作为分数,通过ZRANGEBYSCORE查询到期消息并处理。需配合定时任务扫描队列。
三、JVM相关问题- G1相对于CMS的进步
分区管理:G1将堆划分为Region,避免全堆扫描,减少GC停顿时间。
可预测停顿:通过设置目标停顿时间(MaxGCPauseMillis),优先回收垃圾最多的Region。
并发标记:与CMS类似,但G1在整理阶段会压缩内存,避免碎片化。
适应不同堆大小:G1更适合大堆(如6GB以上),CMS在堆较大时易产生浮动垃圾。
- JDK8之后的新垃圾回收器
ZGC:基于染色指针技术,实现低延迟(毫秒级),适用于大堆(TB级)。
Shenandoah:类似ZGC,通过读屏障实现并发压缩,减少停顿时间。
G1(JDK7引入,JDK8优化):成为默认GC,替代Parallel Scavenge+CMS组合。
- 项目用的JDK版本需根据实际项目回答(如JDK8、JDK11),并说明选择原因(如LTS版本、新特性支持)。
- 是否治理过大数据及OOM问题
大数据治理:通过分库分表、缓存、异步处理降低单节点压力。
OOM解决:
分析堆转储文件(Heap Dump)定位内存泄漏(如未关闭的连接、静态集合)。
调整JVM参数(如Xmx、Xms)扩大堆空间。
优化代码(如减少大对象创建、及时释放资源)。
四、MySQL相关问题- 项目表数据量及索引优化需根据实际项目回答(如单表千万级),并说明优化措施:
添加合适索引(如联合索引覆盖查询条件)。
避免索引失效(如使用函数、OR条件导致索引失效)。
定期分析慢查询日志(slow_query_log),优化SQL语句。
- 为什么用索引索引通过B+树结构加速数据检索,减少全表扫描,提高查询效率。但索引会占用存储空间,并降低写性能(增删改需维护索引)。
- 单表数据量超过2000万性能下降的原因
InnoDB的B+树索引层数增加,查询需更多I/O。
缓冲池(Buffer Pool)命中率降低,需频繁从磁盘加载数据。
锁竞争加剧(如行锁升级为表锁)。
- 大表分表方案原表使用自增主键且查询依赖主键时,可采用水平分表:
按范围分表:如按时间范围(月/年)拆分。
哈希取模分表:对主键哈希后取模,均匀分布数据。
需同步修改查询逻辑,通过分表中间件(如ShardingSphere)或应用层路由实现。
五、MQ相关问题- MQ如何保证消息不丢失
生产者:启用事务消息或确认机制(如RabbitMQ的publisher confirms)。
Broker:持久化消息到磁盘(如Kafka的ISR机制、RocketMQ的CommitLog)。
消费者:手动提交偏移量(如Kafka的enable.auto.commit=false),处理完成后确认。
- 消费者宕机时消息是否丢失若消费者未提交偏移量且未处理完消息,重启后会重新消费(至少一次语义)。若已提交偏移量但未处理完,消息可能丢失(需结合业务设计幂等逻辑)。
- 死信队列了解死信队列(DLQ)用于存储无法正常消费的消息(如超时、重试次数达到上限)。需配置死信交换机(Dead Letter Exchange)和路由键,将消息路由到DLQ供后续分析。
六、项目相关问题七、扩展技术问题(Spring)- 声明式事务失效场景
方法修饰符:方法为private/final时,Spring无法通过AOP代理事务(CGLIB基于继承实现)。
异常处理:方法捕获异常后未抛出,导致事务无法回滚(需配置rollbackFor)。
传播行为:如PROPAGATION_NOT_SUPPORTED开启非事务方法,事务不生效。
- 方法前加final是否导致事务失效及原理是。Spring默认使用JDK动态代理(基于接口)或CGLIB代理(基于继承)实现AOP。若方法为final,CGLIB无法重写方法,导致事务切面无法织入,事务失效。