2.1 java面试题:说一说springcloud 的组件作用和各个组件之间是如何写作的。
好的,根据你最近的深入学习(Nacos、Sentinel、OpenFeign、Gateway等)和银行核心背景,我为你准备了四个版本的答案。面试官通过这个问题,表面上问组件协同,实际上在考察你对微服务架构的整体理解深度。
一、初级回答(会用框架,能说清基本流程)
回答要点:能说出各个组件是干什么的,以及一个请求的基本流转路径。
“我用过 Spring Cloud Alibaba 这套微服务框架。各个组件是这样协同的:
首先,服务提供者启动时会把自己的服务名、IP 和端口注册到Nacos 注册中心。服务消费者启动时去 Nacos 订阅它需要的服务,拉取提供者的地址列表,并缓存到本地。
当消费者需要调用提供者时,它不用写具体的 IP,而是通过OpenFeign声明一个接口,用服务名去调用。OpenFeign 会从本地缓存的服务列表里,通过Ribbon(或 LoadBalancer)的负载均衡策略(比如轮询)选出一个具体的提供者实例,然后把 HTTP 请求发过去。
外部的请求是先经过Gateway 网关的,网关从 Nacos 拿到所有路由的服务列表,也做一次负载均衡,然后把请求转发给对应的微服务。网关还负责鉴权、限流这些公共功能。
总结就是:注册中心负责管理地址,网关负责统一入口,OpenFeign 负责简化调用,Ribbon 负责负载均衡。”
二、中级回答(能讲清细节,结合实际配置)
回答要点:能讲出具体的配置方式、负载均衡策略,以及能解决什么生产问题。
“我们银行核心系统用的是 Spring Cloud Alibaba 全套,我来结合一个典型的交易链路说一下。
1. 服务注册与发现
所有的微服务(比如存款服务、贷款服务)启动时,通过spring.cloud.nacos.discovery配置,自动注册到 Nacos 集群。我们会配置namespace做环境隔离,group做业务分组,还会给实例打上cluster-name实现就近调用。2. 网关层路由与负载均衡
外部请求先到Spring Cloud Gateway。Gateway 本身也是从 Nacos 拉取服务列表,它内置的ReactiveLoadBalancerClientFilter会用 Spring Cloud LoadBalancer 做第一次负载均衡。我们在这里配了限流(Sentinel 集成)和鉴权(GlobalFilter)。3. 内部服务间调用
比如网关把请求转发给deposit-service,deposit-service需要调用loan-service时,我们使用OpenFeign。定义@FeignClient(name = "loan-service", fallbackFactory = ...)接口,OpenFeign 代理内部会调用 LoadBalancer 做第二次负载均衡,选出一个loan-service的实例,发 HTTP 请求。我们配置了超时、重试,并且写操作禁用重试,防止资金风险。4. 负载均衡是谁做的?
负载均衡分两层:服务端负载均衡在网关层,客户端负载均衡在服务间调用。都是通过 Spring Cloud LoadBalancer 实现的,策略默认是轮询,我们可以通过配置文件改成加权、随机,或者自定义基于权重的策略来配合灰度发布。5. 高可用与容错
如果某个loan-service实例挂了,Nacos 的心跳检测会把它剔除,推送更新给所有消费者。同时我们集成了Sentinel,当调用失败率过高时自动熔断,返回兜底数据,保护系统。”
三、高级回答(能剖析原理,结合源码和异常处理)
回答要点:能讲出底层原理(如 OpenFeign 动态代理、Nacos 心跳机制),并能画出调用链的异常处理策略。
“我深入看过 Spring Cloud Alibaba 的核心源码,可以讲一下协同运作的底层原理。
注册中心 Nacos 的 AP/CP 双模式
我们的核心服务使用持久实例(CP 模式,Raft 协议),保证服务列表强一致;非核心服务使用临时实例(AP 模式,Distro 协议),依靠心跳上报。Nacos 客户端每 5 秒发送心跳,服务端 15 秒无心跳标记不健康,30 秒剔除。消费者通过定时拉取(6秒)和 UDP 推送来同步变更。OpenFeign 的动态代理机制
当调用@FeignClient接口时,Spring 容器生成 JDK 动态代理对象。代理内部将方法调用构造成RequestTemplate(URL、参数、请求体),然后交给 LoadBalancer 选择实例,替换服务名为真实 IP。底层 HTTP 客户端我们替换成了OkHttp,支持连接池和 HTTP/2,提升性能。负载均衡的源码级细节
LoadBalancer 的ServiceInstanceListSupplier从 Nacos 拿到列表后,经过RoundRobinLoadBalancer(默认)或我们自定义的GrayLoadBalancer做选择。我们的灰度路由是通过 Nacos 元数据version实现的,网关和服务间调用都支持。异常处理与自愈
我们自研了一个HealthChecker服务,定时扫描所有实例的/actuator/health,连续失败时通过 Nacos API 将实例下线(enabled=false),实现自动摘流。再配合 Sentinel 的降级规则,比如慢调用比例超过 50% 就熔断,返回缓存数据。分布式事务的协调
在放款流程这种跨服务调用中,我们用Seata TCC保证一致性。Feign 调用作为分支事务参与全局事务,由 Seata Server 协调。通过@GlobalTransactional发起,各个服务的 Try/Confirm/Cancel 接口通过 Feign 调用,保证资金安全。”
四、资深回答(能从架构角度对比选型,讲出设计理念和权衡)
回答要点:能跳出单一框架,讲出 Dubbo 与 Spring Cloud 的选型决策依据,以及架构演进中的取舍和实际挑战。
“你这个问题本质是在问微服务治理体系的架构设计,我结合我们银行真实演进来谈。
1. 架构选型:为什么内部 RPC 用 Dubbo,对外用 Spring Cloud?
我们核心交易链路(存款、贷款、账务)全部采用Dubbo + Zookeeper(后期迁到 Nacos)。Dubbo 的自定义二进制协议 + Netty 长连接,比 HTTP 性能高数倍,而且服务治理能力更强(动态路由、权重、分组)。ZK 提供强一致的注册中心,保证服务列表绝对正确。
而对外合作方的 OpenAPI,我们用Spring Cloud Gateway + OpenFeign,因为 HTTP 普适性好,易于对接。这是典型的“内循环高性能,外循环标准化”的架构。2. 负载均衡的分层设计
我们设计了四层负载:
- L4 层:F5/云 SLB,对外入口。
- 网关层(L7):Spring Cloud Gateway 的 LoadBalancer,做跨服务的路由和灰度引流。
- 客户端层:Dubbo 的
RandomLoadBalance(加权随机,避免热点)或LeastActiveLoadBalance(最小活跃数,均衡耗时)。- 数据层:Redis Cluster 的 slot 分片,也是一种负载。
3. 协同运转的核心挑战与解决
- 注册中心脑裂:ZooKeeper 靠过半机制;Nacos CP 模式用 Raft。我们为 ZK 配置了奇数节点,并定期演练故障切换。
- 推送延迟:Nacos 1.x UDP 推送可能丢包,2.x 用 gRPC 双向流彻底解决。我们在交易服务中强制要求升级到 Nacos 2.x,保证变更通知秒级生效。
- 雪崩预防:即使有 Sentinel 熔断,我们仍为核心接口(如扣款)配置了内存级限流,防止刚重启时 Sentinel 规则未加载的窗口期被打挂。
4. 架构演进中的思考
早期我们用 Spring Cloud Gateway + OpenFeign 全部微服务,后来发现内部调用的延迟和吞吐无法满足核心交易要求,于是将核心链路下沉到 Dubbo,网关层仍保留 HTTP。这就是“多协议、分级治理”的思路。现在也在尝试 Service Mesh(Istio),将负载均衡、重试、熔断等能力下沉到 Sidecar,让应用更轻量。”
面试建议:你可以根据面试官的层次和职位要求,选择合适的版本。但无论哪个版本,都要结合自己银行的实际案例,让回答有血有肉。比如“我们放款流程中,通过 Feign 调核心账务,配置了超时和 Sentinel 降级,防止雪崩”,这样最具说服力。
在微服务和分布式架构中,负载均衡的策略决定了请求如何被分配到不同的服务实例上。下面我从策略分类、典型算法、适用场景、以及 Dubbo/Spring Cloud 中的落地,帮你梳理清楚。
一、常见负载均衡策略一览
| 策略 | 核心思想 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 轮询 (Round Robin) | 按顺序依次分配 | 简单、绝对均衡 | 不考虑服务器性能差异 | 同规格实例、无状态服务 |
| 随机 (Random) | 完全随机挑选 | 简单,统计上均衡 | 可能短期内分配不均 | 同轮询,略有概率倾斜 |
| 加权轮询/加权随机 | 给不同实例配权重,按权分配 | 能根据性能分配流量 | 权重需要人工维护 | 实例配置不同(如 CPU、内存) |
| 最小活跃数 (Least Active) | 选择当前处理请求最少的实例 | 动态均衡,避免堆积 | 需实时统计每个实例的活跃数 | 长连接、耗时不一的接口 |
| 一致性哈希 (Consistent Hash) | 将请求参数(如用户ID)哈希到固定节点 | 相同请求总是落到同一实例,扩缩容影响小 | 可能负载不均衡 | 有状态服务、缓存、需要粘性 |
| 最快响应时间 (Weighted Response Time) | 统计平均响应时间,给快的实例更高权重 | 自动适应性能变化 | 统计窗口可能引起波动 | 服务质量波动较大的场景 |
二、在 Dubbo 和 Spring Cloud 中的对应实现
1. Dubbo 中的负载均衡
Dubbo 提供了四种内置策略,可以通过@DubboReference(loadbalance = "xxx")或 XML 配置。
| Dubbo 策略 | 对应算法 | 说明 |
|---|---|---|
random(默认) | 加权随机 | 按权重随机,权重相同则纯随机 |
roundrobin | 加权轮询 | 平滑加权轮询,避免简单加权轮询的突刺问题 |
leastactive | 最小活跃数 | 优先选活跃数最小的,差值相同时按加权随机选 |
consistenthash | 一致性哈希 | 按方法参数(默认第一个参数)做哈希,相同参数总发同一实例 |
2. Spring Cloud 中的负载均衡
早期用 Ribbon,现在默认是Spring Cloud LoadBalancer,Feign、Gateway 均集成它。
| LoadBalancer 实现 | 对应策略 |
|---|---|
RoundRobinLoadBalancer(默认) | 轮询 |
RandomLoadBalancer(需自定义) | 随机 |
自定义ReactorServiceInstanceLoadBalancer | 加权、最小活跃、一致性哈希等 |
配置示例(修改 Feign 的负载均衡策略):
spring:cloud:loadbalancer:ribbon:enabled:false# 关闭 Ribbon,使用 LoadBalancerdiscovery:client:simple:instances:loan-service:-uri:http://10.0.0.1:8080metadata:weight:8-uri:http://10.0.0.2:8080metadata:weight:2然后编写自定义LoadBalancer实现加权随机。
三、银行场景下的策略选择
在银行核心系统中,我们根据交易类型和实例性能做了精细化的负载均衡:
- 无状态查询(余额、利率):使用加权轮询。因为实例性能经基准测试已明确,提前配好权重,稳定且均衡。
- 耗时波动大的接口(征信、反洗钱):使用最小活跃数。避免某些实例因第三方调用卡顿而堆积请求。
- 需要粘性的场景(合约状态机、会话缓存):使用一致性哈希,以用户ID或合同号作为哈希键,保证同一用户的多次请求落到同一实例,提高缓存命中率。
- 灰度发布:自定义基于元数据的路由。通过在 Nacos 元数据中标记
version=2.0,让网关或 LoadBalancer 只把特定用户流量引导到新版本实例上。
四、面试话术
“负载均衡的常用策略有轮询、随机、加权、最小活跃数和一致性哈希。Dubbo 默认是加权随机,Spring Cloud LoadBalancer 默认是轮询。在银行核心系统里,无状态查询我们用加权轮询,长耗时接口用最小活跃数避免堆积,需要粘性的会话或状态机用一致性哈希。灰度发布则是自定义了基于元数据的路由策略。选型关键是看接口特性:有无状态、耗时是否稳定、要不要粘性。”
这样回答,既全面又具体,还能结合你的实际工作场景。
