1. Spring Cloud 组件都用过哪些?
详细回答:
实际项目中常用的 Spring Cloud & Spring Cloud Alibaba 组件如下:
- Nacos:服务注册发现、配置中心
- Gateway:API 网关,路由转发、限流、鉴权
- OpenFeign:声明式服务调用
- Ribbon:客户端负载均衡(现已内置进 OpenFeign / LoadBalancer)
- Sentinel:限流、熔断、降级、热点参数限流
- Seata:分布式事务(AT/TCC/SAGA/XA)
- Sleuth + Zipkin:链路追踪
- SkyWalking:分布式链路追踪与性能监控
- MyBatis-Plus / MyBatis:ORM 持久层
- RabbitMQ / RocketMQ / Kafka:消息队列,异步解耦、削峰
- Spring Cloud Config:配置中心(传统方案,现多用 Nacos)
2. Gateway 主要是用来做什么?
详细回答:
Spring Cloud Gateway 是 API 网关,核心功能:
- 路由转发
根据请求路径、域名、Header 等将请求路由到对应微服务。 - 统一入口
所有外部请求先经过网关,屏蔽内部服务架构。 - 权限认证
统一登录校验、Token 解析、身份鉴权。 - 限流熔断
内置限流过滤器,配合 Sentinel 实现限流、降级。 - 日志与监控
统一日志打印、请求耗时统计、异常捕获。 - 跨域处理
全局配置 CORS,避免每个服务单独处理跨域。 - 请求转发与重写
路径重写、Header 增删改、超时控制。
一句话总结:网关是微服务的统一入口、门卫、调度中心。
3. 跨域问题怎么解决?
详细回答:
跨域是浏览器同源策略限制:协议、域名、端口任一不同即跨域。
常见解决方案:
- Gateway 全局配置 CORS (推荐)
网关统一配置跨域,下游服务无需处理。 - @CrossOrigin
局部注解,适合单体或测试环境。 - WebMvcConfigurer 配置跨域
全局配置类,对整个服务生效。 - Nginx 配置跨域
在反向代理层添加 Header。 - JSONP
仅支持 GET,已淘汰。
核心跨域 Header:
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers
Access-Control-Allow-Credentials
4. Nacos 是 AP 还是 CP 系统?
详细回答:
Nacos 支持切换 AP / CP 模式。
- 服务发现(默认 AP 模式)
满足 CAP 中的 AP:高可用、分区容错,允许暂时数据不一致,保证服务可用性。 - 配置中心(CP 模式)
满足 CP:强一致性,配置必须同步一致才能响应。
结论:
- 服务注册发现:AP
- 配置中心:CP
5. 服务注册的底层原理
详细回答:
以 Nacos 为例:
- 服务启动
服务通过NacosDiscoveryClient向 Nacos Server 发送注册请求(IP、端口、服务名)。 - 心跳机制
客户端每 5s 发送心跳。 - 健康检查
超过 15s 没心跳标记不健康,30s 剔除。 - 服务列表拉取
消费者定时拉取服务列表并缓存本地。 - 故障剔除 & 动态扩缩容
服务下线自动剔除,新增自动同步。
核心机制:注册 + 心跳 + 健康检查 + 本地缓存 + 动态更新。
6. explain 关注哪些信息?
详细回答:
重点看这几列:
- id:执行顺序,id 越大越先执行
- select_type:查询类型(SIMPLE、SUBQUERY、DERIVED、UNION 等)
- table:涉及表
- type :最重要
最优到最差:
system > const > eq_ref > ref > range > index > ALL
至少要达到 range ,最好 ref 以上 - possible_keys:可能用到的索引
- key:实际用到的索引
- key_len:索引长度
- rows:扫描行数,越小越好
- Extra :额外信息
出现Using filesort、Using temporary必须优化
7. ABA 问题是什么?怎么解决?(version 机制)
详细回答:
ABA 问题
CAS 机制中:
- 线程1将 A → B
- 线程2将 B → A
- 线程3再 CAS:A 没变,更新成功
值虽然是 A,但中间被改过,业务可能出错。
解决方案
版本号机制(version)
每次修改版本号 +1,CAS 时不仅比较值,还要比较版本。
典型应用:
- MySQL 乐观锁
- AtomicStampedReference(Java 版本号原子引用)
8. JDK8 和 JDK17 各自特性
详细回答:
JDK 8 核心特性
- Lambda 表达式 & 函数式接口
- Stream 流式编程
- Optional 空指针安全
- 新日期 API(LocalDateTime)
- 默认方法
- Metaspace 替代永久代
- Nashorn JS 引擎
- 并行流
JDK 17 核心特性
- Sealed Class(密封类,限制继承)
- Pattern Matching(模式匹配)
- Record 数据类(简化 POJO)
- Text Block 文本块(""" 多行字符串 """)
- ZGC 正式成熟(低延迟垃圾回收)
- 移除 Security Manager、Applet
- 封装内部 API,无法直接访问 sun.misc 等
- 虚拟线程(JDK19 正式,17 预览)
9. Spring 事务失效场景(高频)
详细回答:
- @Transactional 加在非 public 方法上
- 同类内部方法调用(this.方法())
没走代理,事务失效 - 异常被 catch 吃掉了
不抛异常 → 不回滚 - 抛出非 RuntimeException
默认只回滚运行时异常 - 传播行为配置错误
如 NOT_SUPPORTED、NEVER - 数据库引擎不支持事务(MyISAM)
- 没有被 Spring 管理(未加 @Service/@Component)
- 多线程调用
新线程不在原有事务中
10. ThreadLocal 使用场景
详细回答:
ThreadLocal 是线程本地变量,每个线程独立副本。
典型场景:
- 存储用户登录信息
拦截器存入,Controller/Service 直接获取,避免层层传递。 - 数据库连接/会话管理
保证一个线程一个连接。 - 请求上下文
日志 traceId、请求ID。 - 线程安全的简单工具
如 SimpleDateFormat 替换为 ThreadLocal 副本。
注意:线程池必须 remove,否则内存泄漏、数据错乱。
11. 复制算法为什么快?
详细回答:
复制算法(Java 新生代 From/Eden 区):
- 内存连续
只移动存活对象,无内存碎片。 - 避免标记-整理
不用移动大量对象,不用内存压缩。 - 只需复制存活对象
新生代对象朝生夕死,存活率极低,复制量小。 - 分配简单
存活对象挪到 To 区,指针碰撞分配,极快。
所以复制算法适合存活对象少的场景,速度远超标记清除、标记整理。
12. Redis 主从集群扩容之后,数据怎么同步?
详细回答:
如果是主从(主从复制)扩容:
- 新从节点启动,发送 PSYNC
- 主节点 bgsave 生成 RDB
- 发送 RDB + 增量命令
- 完成全量同步 → 进入增量同步
如果是 Redis Cluster 集群扩容:
- 新节点加入集群
- 手动分配槽(reshard)
- 槽对应数据从旧节点迁移到新节点
- 迁移过程对客户端透明
- 迁移完成后更新集群拓扑
整个过程不宕机、可平滑扩容。
下面是我补的 8 道题,凑齐 20 道完整篇
13. ZSet 底层结构是什么?适用场景?
详细回答:
底层:压缩列表(ziplist)+ 跳表(skiplist)+ 哈希表。
跳表优点:
- 有序
- 查找近似二分,O(logN)
- 实现比红黑树简单
场景:
排行榜、延时队列、范围查询、带权重排序。
14. 分布式事务 Seata AT 模式原理
详细回答:
AT 模式是无侵入分布式事务:
- 拦截 SQL,生成前镜像
- 执行业务 SQL
- 生成后镜像
- 注册分支事务
- TC 协调 commit/rollback
- 回滚时用前后镜像恢复数据
核心:两阶段提交 + 镜像自动回滚。
15. 消息队列重复消费怎么解决?
详细回答:
- 业务幂等
唯一主键、状态机、版本号。 - 全局唯一 ID + 去重表
消费前先查是否已处理。 - Redis 记录消费标识
消费成功 set 标记。 - 消息队列提供Exactly Once语义(如 Kafka 事务)
核心思想:保证幂等性。
16. 强一致、最终一致、顺序一致性区别
详细回答:
- 强一致:任何时刻所有节点数据一致(CP 系统)
- 最终一致:允许短暂不一致,最终一致(AP 系统)
- 顺序一致:不保证绝对一致,但保证所有节点看到操作顺序相同
Redis 最终一致;ZooKeeper / etcd 强一致;Kafka 顺序一致。
17. 微服务接口限流算法
详细回答:
- 计数器
简单粗暴,临界突刺问题 - 滑动窗口
细分窗口,解决突刺 - 漏桶算法
匀速出水,削峰 - 令牌桶算法
允许突发流量(Guava/Sentinel 都用)
生产常用:令牌桶。
18. MySQL 索引最左前缀原则
详细回答:
联合索引(a,b,c),能命中的情况:
- a
- a,b
- a,b,c
跳过前面字段则失效:
- b
- b,c
- a,c
本质:B+ 树按索引从左到右排序。
19. JVM 内存结构(JDK8+)
详细回答:
- 堆:新生代 + 老年代
- 元空间 Metaspace(本地内存)
- 虚拟机栈:方法栈帧
- 本地方法栈
- 程序计数器
- 方法区(逻辑概念,落地为 Metaspace)
20. 怎么定位线上 OOM?
详细回答:
- 开启 OOM 自动 dump
- 用 MAT/JProfiler 分析堆 dump
- 看大对象、集合泄漏、线程泄漏
- 检查 FullGC 频率
- 定位代码:静态集合、ThreadLocal 未 remove、连接未关闭
- 优化:对象池、缩短生命周期、及时释放资源