Spring Cloud 与微服务|java知识点
服务注册与发现
在微服务架构中,服务之间通信需要知道对方的地址和健康状态。服务注册与发现机制解决了这个问题:
- 注册:微服务启动后,将自己的信息(服务名、IP、端口等)发送到注册中心(如 Nacos、Eureka)。注册中心收到后将该服务上线,并开启心跳检测。
- 发现:当微服务需要调用其他服务时,从注册中心获取目标服务的实例列表,通过负载均衡选择一个实例进行调用。
- 心跳检测:注册中心通过心跳机制持续监测服务健康状态。如果某个服务长时间不应答,注册中心会将其下线。心跳时间不宜过快(增加资源消耗)也不宜过慢(不能及时发现故障),剔除时间通常比心跳时间长,允许丢失几次心跳才判定下线。
- 动态扩缩容:服务可以动态注册和注销实例,实现水平扩缩容。
消费者如何获取服务列表
服务消费者启动时从注册中心拉取一份服务列表并缓存到本地。后续通过长连接(如 WebSocket)接收增量更新,同时还有定时刷新作为兜底。调用时直接从本地缓存获取实例列表,通过负载均衡算法选择实例发起请求,整个调用过程不经过注册中心。
CP 与 AP 模式
根据 CAP 定理,分布式系统在分区容错性(P)的前提下,只能在一致性(C)和可用性(A)之间二选一:
- CP 模式(强一致性):保证数据一致,但可能在某些时刻拒绝服务。适合对数据一致性要求高的场景,如数据库操作、消息队列的元数据管理。
- AP 模式(高可用性):保证服务可用,允许短暂的数据不一致。大多数微服务场景选择 AP 模式,因为只有服务高可用,才能保证整个调用链的正常工作。
Nacos 同时支持 CP 和 AP 两种模式:临时实例走 AP(Distro 协议),持久实例走 CP(Raft 协议),开发者可根据业务场景选择。
OpenFeign 远程调用
OpenFeign 是 Spring Cloud 中声明式的 HTTP 客户端,使用流程:
- 通过
@FeignClient注解声明目标服务的接口。 - 调用时,Feign 通过动态代理拦截接口方法调用,构建 HTTP 请求。
- 从本地缓存的服务列表中,通过负载均衡算法选择一个目标实例。
- 发送 HTTP 请求并处理响应。
整个调用过程中注册中心不参与,它只是在服务启动时提供服务列表。负载均衡默认使用轮询算法,可以通过配置更换为随机、加权等策略。
Spring Cloud Gateway
Gateway 是 Spring Cloud 的 API 网关,核心能力包括路由转发、负载均衡、限流、鉴权等。
过滤器机制
Gateway 的过滤器通过 order 值确定执行顺序,数字越小越靠前:
- 路由过滤器(Route Filter):针对特定路由的过滤器,负责请求转发、URL 重写、Header 处理等。
- 全局过滤器(Global Filter):对所有请求生效,可实现限流、熔断、鉴权、日志记录等功能。
- 默认过滤器(Default Filter):对所有路由生效的过滤器。
Gateway 过滤器的本质是责任链 + WebFlux 异步流式调用。请求进入网关后,依次经过 Pre 过滤器(前置处理)→ 路由转发 → 目标服务处理 → Post 过滤器(后置处理)→ 返回客户端。这种设计保证了良好的扩展性和非阻塞性能。
网关限流
限流是为了防止过多请求对服务造成压力,保障服务高可用。常见的限流算法:
- 计数器:最简单的限流方式,请求进来时计数器加一,达到阈值后直接拒绝。实现简单但存在临界突变问题。
- 漏桶算法:以固定速率处理请求,超出速率的请求在队列中排队。请求平滑但无法应对突发流量。
- 令牌桶算法:以固定速率生成令牌,请求需要获取令牌才能通过。支持一定程度的突发流量,是最常用的算法。
分布式场景下,多个网关节点需要借助外部组件实现全局限流,常见方案有 Redis + Lua 脚本、ZooKeeper 等。
常见网关限流实现差异
| 方案 | 原理 | 优势 | 适用场景 |
|---|---|---|---|
| Nginx + limit_req | 漏桶算法 | 高性能、无需额外组件 | 入口层粗粒度限流 |
| Gateway + RequestRateLimiter | 令牌桶 + Redis | 与 Spring 生态集成好 | 网关层精确限流 |
| Sentinel | 滑动窗口 + 集群流控 | 支持熔断降级一体化 | 复杂微服务治理 |
| Redis + Lua | 自定义算法 | 灵活性最高 | 自定义限流策略 |
分布式事务
单体应用的事务只能保证本地数据一致性。在微服务架构中,一个业务操作可能跨越多个服务和数据库,传统事务无法保证跨服务一致性,需要引入分布式事务方案。
常见分布式事务方案
| 方案 | 原理 | 一致性 | 性能 | 适用场景 |
|---|---|---|---|---|
| 2PC(两阶段提交) | 准备阶段 + 提交阶段 | 强一致 | 低(阻塞) | 数据库层面,强一致要求 |
| TCC(Try-Confirm-Cancel) | 业务层面三阶段 | 最终一致 | 中 | 业务侵入性强,适合核心链路 |
| Saga | 正向操作 + 补偿操作 | 最终一致 | 高 | 长事务、跨多服务 |
| 本地消息表 | 本地事务 + 消息投递 | 最终一致 | 高 | 异步场景 |
| RocketMQ 事务消息 | 半消息 + 回查 | 最终一致 | 高 | 消息驱动的业务 |
幂等设计
幂等性是指同一个操作不管执行多少次,结果都是一致的。在微服务中,由于网络重试、消息重投等原因,同一个请求可能被重复发送,幂等设计可以防止重复扣款、重复消费等问题。
常见的幂等实现方式:
- 请求唯一 ID:每次请求携带唯一 ID,服务端先检查是否已处理。
- 分布式锁:对相同业务 key 加锁,防止并发重复执行。
- 数据库唯一索引:利用数据库的唯一约束防止重复插入。
- Redis 前置过滤:在 Redis 中记录已处理的请求 ID,快速过滤重复请求。高并发场景下 Redis 做前置过滤,数据库做最终一致性保障。
服务雪崩、熔断与降级
服务雪崩
服务雪崩是指某个服务因大量请求或热点数据而响应变慢甚至下线,导致调用它的上游服务线程阻塞,进而引发连锁反应,整个调用链大面积不可用。例如秒杀场景中,支付服务变慢导致订单、库存、消息等一系列服务阻塞。
熔断
熔断机制类似电路中的保险丝:当某个服务的错误率或响应时间超过阈值时,自动”熔断”对该服务的调用,直接返回错误或降级结果,避免持续调用加剧故障。熔断器通常有三种状态:关闭(正常调用)、打开(直接拒绝)、半开(试探性放行部分请求)。
降级
降级是在系统压力过大时,将非核心服务降级到备用逻辑(如返回排队页面、缓存数据、默认值),保障核心链路可用。降级可以是自动触发(达到阈值)或手动开关。
秒杀系统综合设计
设计一个微服务秒杀系统,需要综合考虑以下方面:
高可用架构:
- 选择 AP 模式的注册中心,尽可能水平扩展各服务节点。
- 各个链路节点保持多实例部署,消除单点故障。
防止超卖:
- 使用分布式锁(Redis 或 ZooKeeper)保证库存扣减的原子性。
- Redis 预扣库存,异步消息通知数据库最终扣减。
链路保护:
- 在网关层添加限流,防止超量请求进入后端服务。
- 对核心链路添加熔断和降级,非核心操作(如发短信、记录日志)快速失败。
异步削峰:
- 使用消息队列将耗时操作(如扣款、发短信、订单入库)异步化。
- 设置请求队列,将同步操作转化为异步处理,削平流量峰值。
数据一致性:
- 使用分布式事务(如 RocketMQ 事务消息或 TCC)保证扣库存和创建订单的原子性。
- 引入幂等设计,防止消息重复消费导致的数据错误。
用户体验:
- 服务降级时返回排队提示或友好错误页面。
- 请求结果通过轮询或 WebSocket 推送,避免长连接阻塞。
本文内容整理自 Spring Cloud 与微服务学习笔记,涵盖服务注册发现、OpenFeign、Gateway、限流、分布式事务、幂等和熔断降级等核心知识点。
