Java 后端高频 20 题超详细解析 ①

张开发
2026/4/16 18:42:22 15 分钟阅读

分享文章

Java 后端高频 20 题超详细解析 ①
本文整理后端开发面试核心考点涵盖Redis、MySQL、Spring、JVM、高并发、分布式等内容答案详细严谨、原理清晰适合面试复习、知识梳理与技术博客发布。1. Redis 是多线程还是单线程的Redis 的线程模型需按版本与模块区分不能简单判定为单线程或多线程Redis 6.0 之前核心命令执行全程单线程网络 IO、命令处理、定时器、过期键清理均由唯一主线程串行执行仅 RDB 持久化、AOF 重写等后台任务使用子线程不影响主线程执行。Redis 6.0 及以后引入多线程 IO 模型多线程仅负责网络数据读取、协议解析、响应写回核心命令执行依旧保持单线程确保命令原子性与执行稳定性。综上Redis 采用命令执行单线程 网络 IO 多线程 后台任务多线程的混合架构单线程执行命令是其无锁、高效、稳定的核心原因。2. 单线程为什么快呢Redis 单线程仍能支撑 10W QPS核心优势来源于四点完全基于内存操作所有数据读写都在内存中完成响应延迟达到微秒级别完全规避磁盘 I/O 带来的毫秒级性能损耗。无锁竞争与线程切换开销多线程架构存在锁竞争、上下文切换、线程调度等额外开销Redis 单线程天然避免这些损耗CPU 利用率极高。IO 多路复用模型基于epoll/kqueue/select实现高并发网络模型单线程可同时监听海量客户端连接只处理活跃请求不阻塞、不轮询空连接并发处理能力极强。高效数据结构与精简指令底层使用 SDS、跳表、压缩列表、哈希表等高度优化的数据结构命令执行逻辑简单、计算量极小进一步提升执行效率。3. Redis 的过期策略指的是什么Redis 过期策略用于管理带过期时间的键保证内存及时回收。Redis不使用定时删除CPU 消耗过高实际采用惰性删除 定期删除组合策略。定时删除理论方案Redis 不采用为每个过期键创建定时器到期立即删除。优点是内存释放及时缺点是大量定时器会严重占用 CPU高并发下会导致 Redis 阻塞。惰性删除被动删除仅在客户端访问某个键时才检查该键是否过期若过期则立即删除并返回null。优点是不浪费 CPU 资源缺点是冷数据会长期占用内存。定期删除主动删除Redis 后台任务默认每秒执行 10 次逻辑如下随机抽取 20 个带过期时间的键删除其中已过期的键若过期键比例 25%则继续抽取单次执行时间不超过 25ms避免阻塞主线程。最终 Redis 以惰性删除为主、定期删除为辅平衡 CPU 占用与内存利用率。4. Redis 持久化机制有哪些Redis 提供三种持久化方案RDB 快照、AOF 日志、混合持久化4.0。RDB快照持久化原理通过fork子进程将内存数据全量生成二进制dump.rdb文件。优点文件体积小、数据恢复速度极快、对主线程性能影响小。缺点两次快照之间的数据可能丢失不适合对数据安全性要求极高的场景。AOF追加文件持久化原理记录所有写命令并追加到.aof日志文件。三种刷盘策略always每次写都刷盘最安全、性能最低everysec每秒刷盘性能与安全性平衡生产推荐no由操作系统控制刷盘性能最高、最不安全。优点数据安全性高丢失概率极低。缺点文件体积大、恢复速度慢、高写入场景下影响 QPS。混合持久化Redis 4.0 推荐AOF 重写时前半段以 RDB 格式存储全量数据后半段以 AOF 格式记录增量命令。兼顾恢复速度与数据安全性是生产环境默认最佳方案。5. 缓存穿透、击穿、雪崩怎么处理1缓存穿透定义大量请求查询数据库中根本不存在的数据缓存永远无法命中所有流量直接打到数据库极易导致数据库崩溃。解决方案使用布隆过滤器过滤不存在的 key从源头拦截非法请求对不存在的数据缓存null值并设置较短过期时间避免重复查询数据库。2缓存击穿定义某个极高热点 key过期瞬间大量并发请求同时击穿缓存直接访问数据库。解决方案使用SETNX实现互斥锁只允许一个线程重建缓存采用逻辑过期方案不设置 Redis 过期时间将过期时间存在 value 中后台异步重建缓存核心热点 key 设置为永不过期由后台定时任务刷新。3缓存雪崩定义大量 key同一时间集中过期或 Redis 节点宕机导致全部流量压到数据库。解决方案给过期时间添加随机值避免批量 key 同时失效搭建 Redis 哨兵/集群保证高可用启用多级缓存本地缓存 Redis接口限流、熔断、降级保护数据库。6. 分布式锁实现方式Redis 分布式锁用于解决分布式环境下共享资源竞争问题必须保证互斥、防死锁、防误删、可重入。基础原子实现使用原子命令保证加锁安全性SET lock_key unique_value NX EX 30NX仅 key 不存在时设置保证互斥EX设置过期时间防止死锁唯一值避免线程误删其他线程持有的锁。安全解锁必须通过 Lua 脚本保证“判断锁归属 删除锁”的原子性防止并发场景下误删锁。生产级核心要求防死锁、防误删、锁自动续期看门狗、可重入、高可用。成熟方案推荐直接使用Redisson客户端内置可重入锁、公平锁、红锁、自动续期、联锁等完整实现稳定可靠无需手写。7. Redis 常见数据结构有哪些Redis 支持 9 种常用数据结构覆盖绝大多数业务场景String底层 SDS用于缓存对象、计数器、分布式 ID、Session 共享Hash底层压缩列表/哈希表用于存储结构化对象用户信息、商品信息List底层快速列表用于消息队列、栈、时间线、评论列表Set底层哈希表用于去重、共同好友、点赞、交集/并集计算Sorted Set底层跳表哈希表用于排行榜、延时任务、范围查询Bitmap用于用户签到、状态标记、布隆过滤器HyperLogLog用于 UV、日活统计极低内存实现高精度去重计数GEO用于地理位置存储、附近的人、距离计算Stream用于持久化消息队列、消费组、消息回溯。8. 主从和分片集群各自的工作流程以及适用场景1主从复制工作流程从节点发送PSYNC命令向主节点请求数据同步主节点执行bgsave生成 RDB 快照文件主节点将 RDB 发送至从节点加载主节点将 RDB 生成期间的增量命令异步发送给从节点重放后续主节点持续将写命令异步同步至从节点。适用场景读多写少业务读写分离分担主节点读压力数据备份、故障容灾。2Redis Cluster分片集群工作流程所有数据映射到16384 个哈希槽客户端通过CRC16(key) % 16384计算槽位定位对应节点每个主节点负责一部分槽位数据从节点用于故障备份支持主从自动故障转移去中心化架构可水平扩容。适用场景海量数据存储单机内存不足高并发写入场景需要水平扩展与自动故障迁移。9. Redis 和数据库的一致性怎么保证Redis 作为缓存层不追求强一致性仅保证最终一致性强一致需引入分布式事务性能损耗极高一般不使用。最优方案先更新数据库再删除缓存先执行数据库更新操作更新成功后删除缓存下次查询缓存不命中时从数据库加载并回种缓存。增强保证方案延迟双删删除缓存后等待几百毫秒再次删除规避并发脏数据监听 binlogCanal数据库变更后异步更新缓存给缓存设置较短 TTL作为兜底一致策略。不推荐“更新缓存”原因并发更新易产生脏数据、缓存未必被访问、浪费系统资源。10. 内存淘汰策略当 Redis 内存使用达到maxmemory上限时触发内存淘汰机制共 6 种策略noeviction默认策略不淘汰任何数据内存满时直接返回错误allkeys-lru对所有键使用 LRU最近最少使用算法淘汰生产最常用volatile-lru仅对设置了过期时间的键使用 LRU 淘汰allkeys-random随机淘汰所有键volatile-random随机淘汰设置了过期时间的键volatile-ttl淘汰剩余存活时间最短的键。生产环境推荐配置allkeys-lru。11. Nginx 集群的方式Nginx 集群分为负载均衡集群与高可用集群两类。负载均衡集群通过upstream配置后端服务列表实现请求分发支持策略轮询默认ip_hash保证会话一致性least_conn转发至连接数最少的节点weight权重轮询url_hash按请求路径路由。高可用集群Nginx Keepalived主备节点共用虚拟 VIP主节点宕机时 VIP 自动漂移至备节点保证入口高可用多 Nginx 节点 DNS 轮询云环境直接使用厂商 SLB 云负载均衡。12. 如何快速导入千万数据的实现思路千万级数据导入核心思路减少 I/O、减少事务、关闭索引、并行导入。关闭事务自动提交采用批量提交导入前临时关闭索引、外键约束导入完成后重建使用批量INSERT每 1000~5000 条为一批减少网络交互使用 MySQL 原生LOAD DATA INFILE速度比普通INSERT快 10~100 倍将数据文件分片多线程/多进程并行导入先写入消息队列异步消费落库不阻塞业务适当调大innodb_buffer_pool_size提升写入效率。13. 一条 INSERT 语句执行过程中日志的顺序InnoDB 执行 INSERT 严格遵循两阶段提交保证redo log与binlog一致性顺序如下记录undo log用于事务异常回滚执行插入操作更新内存数据页写入redo log标记为prepare状态写入binlog日志写入redo log标记为commit状态事务完成。该顺序可保证数据库崩溃恢复、主从复制时数据绝对一致。14. 数据库死锁问题如何定位和避免定位死锁开启死锁日志innodb_print_all_deadlocks 1执行命令查看SHOW ENGINE INNODB STATUS;分析内容事务持有锁、等待锁、执行 SQL、锁类型、事务隔离级别。避免死锁所有事务按固定顺序访问资源如按 ID 从小到大更新事务尽可能小、短、快减少锁持有时间避免长事务与热点行并发更新使用 RC提交读隔离级别减少间隙锁降低死锁概率优先使用乐观锁替代悲观锁。15. 数据库表设计数据库表设计遵循规范、性能、扩展三大原则范式设计满足 1NF、2NF、3NF减少数据冗余保证数据一致性复杂查询场景可适度反范式提升查询效率。主键设计推荐使用自增 ID 或雪花算法禁止使用 UUID避免索引分裂、查询性能下降。索引设计高频查询字段建立索引联合索引遵循最左前缀原则避免冗余索引不在低基数字段建索引。字段设计使用最小合适类型优先数字与定长字符串大字段text/blob单独分表冷热数据分离存储。通用字段必须包含id、create_time、update_time、is_deleted。16. 如果让你设计一个高并发系统 你会先从哪些点入手高并发系统设计按流量分层、架构解耦、存储优化、高可用保障逐步推进流量分层拦截CDN → 网关限流 → 本地缓存 → Redis 缓存 → 数据库层层削减流量。应用无状态化应用不依赖本地存储便于水平扩容。异步化解耦使用消息队列削峰填谷异步处理非核心流程。缓存体系优化多级缓存、热点缓存、过期时间打散、主动刷新。数据库优化索引优化、读写分离、分库分表。集群与高可用服务集群、Redis 集群、数据库主从/集群。限流、熔断、降级保护核心链路防止级联故障。池化技术线程池、数据库连接池、HTTP 连接池。全链路压测与监控提前定位瓶颈实时监控告警。17. 自定义注解怎么实现Java 自定义注解通过元注解 反射 AOP完整实现。定义注解使用interface声明注解。配置元注解Target指定注解作用位置类、方法、字段等Retention指定生命周期运行期使用设为RUNTIMEDocumented生成 API 文档Inherited允许子类继承父类注解。解析与增强通过反射读取注解信息结合 AOP 实现切面增强如日志打印、权限校验、接口限流、事务控制等。注解本质是接口运行时通过反射获取信息配合动态代理完成功能扩展。18. 双亲委派是什么双亲委派是 JVM 类加载器的标准工作机制。规则类加载时子类加载器先委托父类加载器尝试加载父类加载器无法加载时子类加载器才自行加载委托顺序自底向上查找顺序自顶向下。类加载层次启动类加载器Bootstrap加载 JVM 核心类库扩展类加载器Extension加载jre/lib/ext包应用类加载器App加载项目classpath下类。作用保证核心类不被恶意篡改、确保类全局唯一、避免重复加载、规范类加载行为。19. 讲讲 Spring 里面的事务传播行为Spring 事务传播行为控制多个事务方法相互调用时的事务策略共 7 种REQUIRED默认存在事务则加入不存在则新建事务REQUIRES_NEW新建独立事务原有事务挂起SUPPORTS有事务则加入无事务则以非事务方式运行MANDATORY必须在已有事务中运行否则抛出异常NOT_SUPPORTED始终非事务运行已有事务挂起NEVER必须非事务运行否则抛异常NESTED嵌套事务支持保存点回滚外层事务回滚则内层一并回滚。20. 反射常见有哪几种方式什么是反射机制AOP 呢反射机制Java 反射允许程序在运行时获取类的完整结构信息并动态操作对象获取类、父类、接口信息获取字段、方法、构造器动态调用方法、修改属性无需在编译期确定目标对象。获取 Class 对象的三种方式对象.getClass()类名.classClass.forName(全限定类名)。AOP面向切面编程AOP 是一种编程范式用于横向抽取通用逻辑日志、事务、权限、异常、限流不侵入业务代码。底层实现JDK 动态代理面向接口、CGLIB面向类核心概念切面、切点、通知、连接点典型场景声明式事务、统一日志、权限校验、接口限流。

更多文章