skill实战:从零构建高可用微服务架构的避坑指南

8次阅读
没有评论

共计 2477 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

背景痛点:为什么需要微服务

最近在维护公司老项目时,每次上线新功能都像在走钢丝——明明只改了订单模块,支付功能却莫名其妙挂了。这种单体架构(Monolithic Architecture)的典型问题,在用户量突破 10 万后彻底爆发:

skill 实战:从零构建高可用微服务架构的避坑指南

  • 凌晨促销活动时,商品详情页的 CPU 占用直接飙到 90%,连带拖垮整个系统
  • 所有功能打包部署,每次迭代需要全量回归测试,发布周期长达 3 小时
  • 技术栈被老旧框架绑架,想引入 Redis 缓存都得考虑兼容性问题

这时候才真正体会到微服务(Microservices)的价值:把电商系统拆分成订单、支付、库存等独立服务,每个服务可以:

  1. 独立开发部署,用最适合的技术栈(比如用 Go 写高并发库存服务)
  2. 根据业务重要性差异化扩容(促销时给商品服务多分配服务器)
  3. 故障隔离,某个服务崩溃不影响核心链路

技术选型:Alibaba 还是 Netflix?

刚开始调研时,发现 Spring Cloud 有两个主流生态:

  • Netflix 系:Eureka(服务发现)+Hystrix(熔断)+Zuul(网关)
  • Alibaba 系:Nacos(服务发现)+Sentinel(熔断)+Seata(事务)

经过两周的对比测试,最终选择 Alibaba 方案,关键原因:

  1. Nacos 的配置管理(Configuration Management)比 Eureka 的纯注册中心更实用
  2. Sentinel 的流量控制规则支持动态生效,而 Hystrix 需要重启
  3. Seata 的 AT 模式对代码侵入性小,适合老系统改造

特别提醒:如果已经用了 Consul 做服务发现,可以单独引入 Sentinel 做熔断,不必整套替换。

核心实现三步走

1. Nacos 服务注册发现

在父 pom 引入 Spring Cloud Alibaba 依赖后,服务注册只需两步:

  1. 在 application.yml 添加配置(注意 namespace 用于环境隔离):
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.1.100:8848
        namespace: dev
  application:
    name: order-service
  1. 启动类添加 @EnableDiscoveryClient 注解

实测发现服务列表有延迟?调整心跳间隔(默认 30 秒):

spring.cloud.nacos.discovery.heart-beat-interval: 10

2. Sentinel 熔断降级

以支付服务调用银行接口为例,配置 QPS 阈值为 100 的流控规则:

@RestController
@RequestMapping("/payment")
public class PaymentController {

    // 资源名需唯一
    @SentinelResource(value = "bankApi", blockHandler = "handleFlowLimit")
    @PostMapping("/create")
    public Result createPayment(@RequestBody Order order) {// 调用银行 API 逻辑}

    // 触发流控时执行的方法
    public Result handleFlowLimit(Order order, BlockException ex) {return Result.error("当前交易人数过多,请稍后重试");
    }
}

在 Sentinel 控制台配置规则:

  1. 资源名填写bankApi
  2. 阈值类型选 QPS,单机阈值设为 100
  3. 流控模式选直接(Direct)

3. Seata 分布式事务

处理跨服务的订单创建→扣库存→支付流程,使用 AT 模式:

sequenceDiagram
    participant Client
    participant OrderService
    participant StorageService
    participant PayService

    Client->>OrderService: 创建订单
    OrderService->>Seata: 开启全局事务(XID=123)
    OrderService->>StorageService: 扣减库存(XID=123)
    StorageService->>Seata: 注册分支事务
    OrderService->>PayService: 发起支付(XID=123)
    PayService->>Seata: 注册分支事务
    Seata->>OrderService: 提交 / 回滚(XID=123)

关键配置:

# 使用 MySQL 作为事务日志存储
seata.store.mode=db
seata.store.db.datasource=druid
seata.store.db.url=jdbc:mysql://127.0.0.1:3306/seata

性能压测数据

用 JMeter 模拟 1000TPS 并发,持续 30 分钟的测试结果:

组件 CPU 占用 内存消耗 网络 IO
Nacos 集群 45% 2.3GB 8MB/s
Sentinel 12% 500MB 3MB/s
Seata-Server 28% 1.2GB 5MB/s

发现 Nacos 内存泄漏?升级到 2.0.4 版本后稳定在 1.8GB 以内。

生产环境避坑指南

Nacos 集群脑裂问题

现象:三个节点间网络分区后,出现多个 Leader 写入冲突。

解决方案:

  1. 使用至少 3 个节点(Quorum 机制)
  2. 配置数据库持久化(不依赖本地文件)
  3. 设置心跳超时时间:
nacos.naming.clean.initial-delay-ms=30000

Sentinel 规则持久化

默认规则存在内存中,重启后丢失。推荐两种方案:

  • 推模式:通过 Nacos 配置中心同步规则
  • 拉模式:在应用启动时调用 Sentinel API 初始化

Seata 全局锁冲突

高并发下可能出现 Global lock wait timeout 错误,优化方向:

  1. 减少全局锁持有时间(避免事务内远程调用)
  2. 修改默认锁超时时间(默认 30 秒):
seata.tm.degrade-check-period=2000

思考题

当用户重复提交订单时,如何保证:
1. 订单服务生成唯一订单号
2. 支付服务防止重复扣款
3. 库存服务避免超卖

欢迎在评论区分享你的分布式幂等性设计方案。

正文完
 0
评论(没有评论)