目录
- 1. 请谈谈你对微服务架构的理解?
- 2. 集群、分布式、节点的区别是什么?
- 3. 什么是服务注册与发现?为什么需要它?
- 4. 什么是负载均衡?常见的策略有哪些?
- 5. 什么是配置中心?它的作用是什么?
- 6. 什么是服务熔断和降级?它们有什么区别?
- 7. 请介绍你使用的微服务技术栈(以SpringCloud Alibaba为例)
- 8. Nacos 的选型与优势
- 9. Nacos的核心概念(namespace, group, dataId)?
- 10. OpenFeign如何实现远程调用?如何配置超时和日志?
- 11. Sentinel的流控规则有哪些?熔断降级的策略是什么?
- 12. Sentinel 的“熔断”与“降级”实现
- 13. Spring Cloud Gateway的核心概念(Route, Predicate, Filter)?
- 14. 深化 Spring Cloud Gateway 的实践
- 15. 如果注册中心宕机了,服务还能调用成功吗?
- 16. 分布式事务 Seata 的 AT 模式原理
1. 请谈谈你对微服务架构的理解?
微服务架构是一种将单一应用程序开发为一套小型服务的方法,每个服务运行在独立的进程中,服务之间通过轻量级的通信机制(通常是HTTP/JSON API)进行交互。这些服务围绕业务能力进行构建,可以独立部署、独立扩展,并且可以使用不同的编程语言和数据存储技术。
核心思想是“拒绝大单体”,通过服务拆分实现业务解耦,提升系统的可维护性、可扩展性和开发效率。但同时也带来了分布式系统的复杂性,如服务发现、配置管理、远程调用、容错、监控等问题。
2. 集群、分布式、节点的区别是什么?
- 集群 (Cluster):是一个物理形态,指将多台服务器集中在一起,共同对外提供同一个服务,以实现高可用和负载均衡。例如,将用户服务部署在多台机器上形成一个集群。
- 分布式 (Distributed):是一种工作方式,指将一个大型系统的不同业务模块分布在不同的物理节点(服务器)上,这些节点协同工作,共同完成整个系统的功能。例如,京东系统由用户、订单、商品等多个分布式服务构成。
- 节点 (Node):指的是集群或分布式系统中的单个服务器实例。
关键区别:分布式强调“不同业务分布”,而集群强调“相同业务集中”。分布式系统中的每一个服务(节点)都可以做集群化部署。
3. 什么是服务注册与发现?为什么需要它?
- 服务注册 (Service Registration):当一个微服务启动后,它会将自己的网络地址(IP、端口)、服务名等信息注册到一个中心化的组件——注册中心。
- 服务发现 (Service Discovery):当一个服务A需要调用服务B时,它不再直接通过硬编码的IP和端口去访问,而是向注册中心查询“服务B”的地址列表,然后选择其中一个实例进行调用。
为什么需要:在动态的微服务环境中,服务实例的IP和端口可能会频繁变化(如弹性伸缩、故障重启)。服务注册与发现机制让服务调用方能动态感知服务提供方的地址变更,避免了因服务下线或迁移导致的调用失败,是微服务架构的基石。
4. 什么是负载均衡?常见的策略有哪些?
负载均衡是指将客户端的请求均匀地分发到后端多个服务实例上,避免单个实例过载,从而提高系统的整体性能和可用性。
- 客户端负载均衡:在发起调用的客户端(如使用
RestTemplate
+@LoadBalanced
或OpenFeign
)内置负载均衡逻辑,从注册中心获取服务列表后,根据策略选择一个实例。 - 服务端负载均衡:通过独立的负载均衡器(如Nginx、F5、Gateway)接收请求,再根据策略转发给后端服务。
常见策略:
- 轮询 (Round Robin):依次将请求分发给每个服务实例。
- 随机 (Random):随机选择一个服务实例。
- 最少连接 (Least Connections):优先将请求分发给当前连接数最少的实例。
- 权重 (Weighted):根据实例的配置权重分配流量,性能更好的机器可以承担更多请求。
- 哈希/一致性哈希 (Hashing):根据请求的某些特征(如用户ID、IP)进行哈希,确保相同特征的请求总能路由到同一个实例,常用于需要会话保持的场景。
5. 什么是配置中心?它的作用是什么?
配置中心是一个集中管理微服务配置信息的组件。
- 集中管理:避免配置散落在各个服务的代码或配置文件中,便于统一维护。
- 动态刷新:可以在不重启服务的情况下,动态修改配置并实时生效(如使用
@RefreshScope
或ConfigurationProperties
)。 - 环境隔离:通过
namespace
实现开发、测试、生产等不同环境的配置隔离。 - 统一视图:提供一个可视化的界面来管理所有服务的配置。
6. 什么是服务熔断和降级?它们有什么区别?
服务熔断 (Circuit Breaker):
- 目的:防止“雪崩效应”。当某个服务出现故障或响应过慢时,快速失败,不再继续调用该服务,直接返回一个预设的“兜底”响应。
- 机制:类似于电路中的保险丝。当错误率达到阈值时,熔断器“跳闸”,后续请求直接走降级逻辑。经过一段时间后,会尝试“半开”状态,允许少量请求通过,如果成功则关闭熔断,恢复正常调用;如果失败则继续保持熔断。
- 实现:通常由
Sentinel
、Hystrix
等组件实现。
服务降级 (Service Degradation):
- 目的:在系统资源紧张或高峰期,牺牲非核心功能,保证核心业务的稳定运行。
- 方式:可以是关闭某些非关键接口、返回缓存数据、返回默认值或空值、简化处理逻辑等。
- 场景:不仅在服务调用失败时触发,也可以在系统负载过高时主动触发。
区别:熔断是被动的容错机制,针对下游服务不可用;降级是主动的取舍策略,可以是系统自身压力大,也可以是下游服务调用失败。熔断通常会触发降级,但降级不一定是因为熔断。
7. 请介绍你使用的微服务技术栈(以SpringCloud Alibaba为例)
我通常使用 Spring Cloud Alibaba (SCA) 作为微服务解决方案,它与 Spring Cloud 生态无缝集成,提供了生产级的组件。
- 注册/配置中心:Nacos。它集成了服务发现和配置管理两大功能,替代了 Eureka 和 Spring Cloud Config,功能更强大,管理更方便。
- 远程调用:OpenFeign。它是一个声明式的HTTP客户端,通过定义接口和注解的方式进行远程调用,代码简洁,可读性强。配合
@LoadBalanced
的RestTemplate
也可实现。 - 流量控制与熔断降级:Sentinel。由阿里巴巴开源,以流量为切入点,提供实时的监控、流量控制、熔断降级、系统保护、热点防护等功能。规则可以动态配置,实时生效。
- API网关:Spring Cloud Gateway。基于 Spring 5、Project Reactor 构建的响应式网关,性能优秀。提供路由、断言(Predicate)、过滤器(Filter)、限流、熔断、跨域处理等能力。
- 分布式事务:Seata。解决微服务架构下的分布式事务问题,支持 AT、TCC、Saga、XA 等多种模式,其中 AT 模式对业务代码侵入性较小。
8. Nacos 的选型与优势
- 对比说明:可以简要对比 Nacos 与 Eureka、Consul、ZooKeeper。
- Eureka: Netflix 开源,功能单一(仅服务发现),2.x 版本已闭源,社区活跃度下降。
- Consul: HashiCorp 开源,功能全面(服务发现、配置、健康检查、KV存储),但配置中心功能相对 Nacos 较弱,且使用 Go 语言,与 Java 生态集成稍逊。
- ZooKeeper: Hadoop 生态,强一致性,但作为配置中心使用复杂,性能开销大,Watch 机制有缺陷。
- Nacos: 阿里巴巴开源,定位为“更易于构建云原生应用的动态服务发现、配置管理和服务管理平台”,集成了服务发现和配置中心两大核心功能,与 Spring Cloud Alibaba 无缝集成,提供丰富的 API 和控制台,是当前国内微服务架构的主流和推荐选择。
9. Nacos的核心概念(namespace, group, dataId)?
- Namespace (命名空间):用于实现多环境隔离(如 dev, test, prod)或多租户隔离。不同 namespace 下的配置和服务互不影响。
- Group (分组):对服务或配置进行分组管理。通常建议将同一个微服务的所有配置放在同一个 group 下(如
ORDER_GROUP
),方便管理。 - Data ID (配置集ID):配置的唯一标识。命名规则通常为
${prefix}-${spring-profile-active}.${file-extension}
。prefix
默认为spring.application.name
。spring-profile-active
是当前激活的环境(如 dev)。file-extension
是配置格式(如 properties, yaml)。- 例如,
service-order-dev.yaml
。
推荐用法:namespace
区分环境,group
区分微服务,dataId
定义具体配置文件。
10. OpenFeign如何实现远程调用?如何配置超时和日志?
实现调用:
- 引入
spring-cloud-starter-openfeign
依赖。 - 在启动类上添加
@EnableFeignClients
注解。 - 定义一个接口,在接口上使用
@FeignClient("服务名")
注解。 - 在接口方法上使用
@RequestMapping
等注解定义请求路径和参数。 - 在需要调用的地方
@Autowired
该接口即可。
- 引入
超时控制:
spring: cloud: openfeign: client: config: default: # 全局配置 connect-timeout: 5000 # 连接超时时间 read-timeout: 5000 # 读取超时时间 service-product: # 针对特定服务配置 connect-timeout: 3000 read-timeout: 5000
日志配置:
logging: level: com.atguigu.order.feign: debug # 设置Feign客户端接口的日志级别
@Bean public Logger.Level feignLoggerLevel() { return Logger.Level.FULL; // 日志级别:NONE, BASIC, HEADERS, FULL }
11. Sentinel的流控规则有哪些?熔断降级的策略是什么?
流控规则 (Flow Control):
- QPS:每秒请求数。当QPS超过阈值时,进行限流。
- 并发线程数:当前请求的并发线程数超过阈值时,进行限流。
- 流控模式:直接(单机)、关联(当资源A被限流时,也限流资源B)、链路(只针对特定调用链路的入口资源)。
- 流控效果:快速失败、Warm Up(预热)、排队等待。
熔断降级策略 (Sentinel):
- 慢调用比例 (SLOW_REQUEST_RATIO):统计周期内,请求的平均RT(响应时间)超过阈值的比例达到设定值,则触发熔断。
- 异常比例 (ERROR_RATIO):统计周期内,异常请求占总请求数的比例达到阈值,则触发熔断。
- 异常数 (ERROR_COUNT):单位统计窗口内的异常数目超过阈值,则触发熔断。
12. Sentinel 的“熔断”与“降级”实现
- OpenFeign + Sentinel: 重点强调
fallback
和fallbackFactory
的使用。fallback
: 指定一个实现了 Feign Client 接口的类,当调用失败时,执行该类的兜底方法。局限性:无法获取到触发熔断的具体异常。fallbackFactory
: 指定一个工厂类,可以获取到Throwable
异常,能更精细地处理不同类型的异常。这是更推荐的做法。
@FeignClient(value = "service-product", fallbackFactory = ProductFeignClientFallbackFactory.class) public interface ProductFeignClient { @GetMapping("/product/{id}") Product getProductById(@PathVariable("id") Long id); } @Component public class ProductFeignClientFallbackFactory implements FallbackFactory<ProductFeignClient> { @Override public ProductFeignClient create(Throwable cause) { return new ProductFeignClient() { @Override public Product getProductById(Long id) { log.error("调用商品服务失败,原因: {}", cause.getMessage()); // 返回兜底数据 return new Product(id, "降级商品", BigDecimal.ZERO, 0); } }; } }
- BlockExceptionHandler: 可以自定义 Sentinel 限流或熔断时的返回内容(如返回 JSON 格式的错误信息),而不是默认的
Blocked by Sentinel
页面。
13. Spring Cloud Gateway的核心概念(Route, Predicate, Filter)?
- Route (路由):网关的基本单元,由一个ID、一个目标URI、一组断言和一组过滤器组成。如果断言匹配,则路由生效。
- Predicate (断言):Java 8 的 Predicate。输入类型是
ServerWebExchange
,用于匹配HTTP请求中的各种属性(如路径、请求方法、Header、参数等)。只有当所有断言都匹配时,路由才被匹配。例如Path=/api/order/**
。 - Filter (过滤器):可以在请求被路由前或后对请求和响应进行修改。分为
GatewayFilter
(局部,作用于特定路由)和GlobalFilter
(全局,作用于所有路由)。例如AddRequestHeader
、StripPrefix
、RewritePath
。
14. 深化 Spring Cloud Gateway 的实践
- 全局过滤器 (GlobalFilter):强调其重要性,用于实现跨切面的功能,如:
- 统一日志记录:记录请求的耗时、参数、响应等。
- 权限认证:在路由前校验 JWT Token。
- 请求体缓存:解决 WebFlux 中
ServerHttpRequest
只能读取一次的问题(CacheRequestBodyFilter
)。 - 请求头处理:添加、修改、删除请求头。
- 路径重写 (RewritePath):这是最常用的过滤器之一,用于在请求转发到后端服务前修改请求路径。
- 作用:对外隐藏内部服务的真实路径,统一API前缀,实现路径映射。
- 配置示例:
spring: cloud: gateway: routes: - id: order_route uri: lb://service-order predicates: - Path=/api/order/** filters: # 将 /api/order/xxx 重写为 /xxx 再转发给 service-order - RewritePath=/api/order/(?<segment>.*), /$\{segment}
- 动态路由:可以通过
RouteDefinitionWriter
API 动态地添加、修改、删除路由规则,实现路由的热更新,而无需重启网关。
15. 如果注册中心宕机了,服务还能调用成功吗?
这取决于服务的调用历史和缓存机制:
- 从未调用过:如果调用方从未调用过目标服务,那么在注册中心宕机后,调用方无法获取到服务地址列表,调用会立即失败。
- 调用过且注册中心宕机:如果调用方之前调用过目标服务,其本地通常会缓存一份服务实例列表。即使注册中心宕机,调用方仍然可以使用缓存的地址列表进行负载均衡调用,因此调用会成功。
- 调用过但目标服务也宕机:如果调用方缓存了地址,但目标服务实例本身已经宕机,那么请求会因为连接被拒绝(Connection Refused)而失败。
因此,注册中心的高可用性至关重要,但客户端的本地缓存机制也能在一定程度上提高系统的容错能力。
16. 分布式事务 Seata 的 AT 模式原理
- 一阶段 (Phase 1):
- Seata 会拦截业务 SQL。
- 在执行 SQL 前,先根据
WHERE
条件查询出要修改的数据的前镜像 (Before Image)。 - 执行业务 SQL,修改数据。
- 在执行 SQL 后,再查询出修改后的数据的后镜像 (After Image)。
- 将
前镜像
、后镜像
和业务 SQL
一起组装成一条undo_log
记录,插入到undo_log
表中。 - 提交本地事务。此时,业务数据已经提交!
- 二阶段 (Phase 2):
- 成功 (Commit):全局事务成功,异步删除
undo_log
记录。 - 失败 (Rollback):全局事务失败,Seata 服务端会通知所有分支事务进行回滚。回滚时,通过
undo_log
中的前镜像
生成INSERT
、UPDATE
、DELETE
语句,将数据恢复到一阶段之前的状态。
- 成功 (Commit):全局事务成功,异步删除
- 核心优势:对业务代码无侵入,开发人员只需关注业务 SQL,Seata 自动完成分布式事务的协调。
Seata 还支持其他模式:
- XA 模式:强一致性,两阶段提交,依赖数据库的 XA 协议,性能较低,锁持有时间长。
- TCC 模式:通过编写
Try
、Confirm
、Cancel
三个业务方法来实现,灵活性高,性能好,但对业务代码有侵入性。 - Saga 模式:长事务解决方案,将一个大事务拆分为多个顺序执行的子事务,每个子事务有对应的补偿操作(逆向操作),适用于业务流程长且需要保证最终一致性的场景。
总而言之,Spring Cloud Alibaba 提供了一套非常成熟和强大的微服务解决方案。Nacos、Sentinel、OpenFeign、Gateway、Seata 这些组件各司其职,共同解决了微服务架构中的核心挑战。但技术只是手段,更重要的是理解其背后的设计思想和解决的问题。在实际项目中,我们还需要结合 监控告警、日志追踪、容器化部署 等手段,构建一个可观测、易维护、高可用的云原生微服务系统。同时,也要警惕微服务带来的复杂性,避免过度拆分,平衡好架构的先进性与团队的维护成本。