系统架构设计:分层架构、微服务拆分、服务注册与发现、API网关设计

好,咱们直接进入正题。抢单系统这种高并发场景,架构设计要是没想清楚,后面全是坑。我见过太多团队一上来就撸代码,结果压测一跑,服务直接雪崩。今天我就把这几年的实战经验掰开揉碎了讲给你听。

一、分层架构:别把代码写成大泥球

分层架构,说白了就是让代码各司其职。我习惯把抢单系统分成四层:

  • 接入层:负责流量入口,处理限流、鉴权、防重放
  • 业务层:核心抢单逻辑,订单生成,库存扣减
  • 服务层:封装原子能力,比如用户服务、商品服务、订单服务
  • 数据层:数据库、缓存、消息队列的读写操作

你可能会问,为什么非要分这么细?我在项目中遇到过一件事:有个同事把库存扣减逻辑直接写在Controller里,结果后来要加个预扣库存功能,改得那叫一个痛苦。分层的好处就是——改一层,不影响其他层。

核心原则:上层依赖下层,下层不依赖上层。接入层不能直接操作数据库,业务层不能处理HTTP请求。

二、微服务拆分:拆得不好,比不拆还惨

微服务不是拆得越细越好。我见过一个项目,把用户模块拆成了「用户基本信息服务」「用户地址服务」「用户积分服务」……结果一个简单的用户详情页要调5个接口,延迟直接爆炸。

抢单系统我建议这样拆:

服务名称 职责 拆分理由
抢单核心服务 处理抢单请求、库存扣减、订单生成 核心链路,需要独立扩缩容
用户服务 用户信息、黑名单、风控 与抢单逻辑解耦,方便复用
商品服务 商品信息、库存查询 库存操作频繁,需要独立优化
订单服务 订单持久化、状态流转 写压力大,需要异步处理
通知服务 推送抢单结果、短信、站内信 非核心链路,允许降级

我的经验:拆分时先看「变更频率」和「资源消耗」。经常一起改的,别拆;资源消耗差异大的,必须拆。

三、服务注册与发现:别让服务互相找不到

微服务之间怎么互相找到?你想想看,如果每个服务都硬编码对方的IP地址,那扩缩容的时候不得改死你?

我一般用Nacos或者Consul。抢单系统里,我推荐Nacos,原因很简单:它同时支持配置中心和注册中心,少维护一个组件。

核心流程是这样的:

  1. 服务启动时,把自己的IP和端口注册到Nacos
  2. 服务每隔几秒发一次心跳,告诉Nacos「我还活着」
  3. 调用方从Nacos拉取服务列表,然后负载均衡调用
  4. 服务挂了,Nacos踢掉它,调用方自动感知
// 伪代码示例:服务注册
@Service
public class OrderService {
    @PostConstruct
    public void register() {
        // 注册到Nacos
        nacosClient.registerInstance("order-service", 
            InetAddress.getLocalHost().getHostAddress(), 8080);
    }
}

避坑指南:我曾经遇到过一个问题——服务注册成功了,但调用方就是调不通。查了半天,原来是服务注册的IP是内网IP,但调用方在另一个网段。所以注册时一定要确认网络可达性。

四、API网关设计:流量入口的把关人

网关是系统的第一道防线。我习惯用Spring Cloud Gateway,性能好,而且支持响应式编程。

网关在抢单系统里主要干这几件事:

  • 路由转发:根据请求路径,转发到对应的微服务
  • 限流熔断:防止流量把后端冲垮
  • 鉴权校验:验证Token,拦截非法请求
  • 日志记录:记录每次请求的入参、出参、耗时

我画了一张图,帮你理解网关在整个架构中的位置:

客户端 API网关 限流/鉴权/路由 日志/熔断 抢单核心服务 用户服务 订单服务 Nacos 注册中心 客户端 API网关 微服务 注册中心 服务注册/发现

网关的限流策略,我一般用令牌桶算法。抢单开始前,先往桶里放好令牌。每个请求来了拿一个令牌,拿不到就直接返回「抢单太火爆」。这样能保证后端服务不会被打满。

// 网关限流配置示例
spring:
  cloud:
    gateway:
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/order/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 100
                redis-rate-limiter.burstCapacity: 200

小技巧:网关层可以做「灰度发布」。比如新版本上线,先让5%的流量走新服务,没问题了再全量切换。这个在抢单系统里特别实用,能避免一次上线搞崩全站。

嗯,架构设计这块就聊这么多。记住一句话:架构是演进来的,不是设计出来的。先跑通核心链路,再慢慢优化。别一开始就想搞个完美的架构,那反而容易把自己绕进去。

专注资料整理