Skip to content

网关与微服务演进

MiniAdmin 已提供独立的 MiniAdmin.Gateway 网关项目。当前阶段推荐把它作为统一入口和入口治理层使用,不急着把核心业务拆成多个服务。

当前定位

MiniAdmin.Gateway 的职责很克制:

能力当前实现说明
反向代理YARP/api/** 转发到后端 API
路径整理PathRemovePrefix=/api前端继续访问 /api/auth/login,后端仍接收 /auth/login
健康检查/health用于 Docker、1Panel、反向代理探活
入口限流ASP.NET Core RateLimiter网关层做全局限流和登录限流
灰度发布稳定哈希 + 自定义负载策略支持百分比、白名单、租户、用户、IP 和请求头
请求追踪X-Trace-Id生成或透传追踪 ID,并在响应中返回
熔断保护Closed/Open/HalfOpen上游连续失败时快速失败并自动探测恢复
转发头X-Forwarded-*保留真实来源 IP、Host 和协议
CORS本地开发允许 localhost127.0.0.1方便前端开发模式直连网关

网关不做业务认证、不查数据库、不直接访问租户、角色、流程等业务表。认证授权仍在 MiniAdmin.Api 中完成,这样能保证现有功能不被入口层改动影响。

请求链路

Docker Compose 默认链路如下:

mermaid
flowchart LR
    B["浏览器"] --> W["mini-admin-web Nginx"]
    W -->|/api/**| G["MiniAdmin.Gateway"]
    G -->|YARP remove /api| A["MiniAdmin.Api"]
    A --> M["MySQL"]
    A --> R["Redis"]

本地开发时可以只启动 API 和网关:

mermaid
flowchart LR
    F["前端开发服务"] -->|http://localhost:8088/api/**| G["MiniAdmin.Gateway"]
    G -->|http://localhost:5021/**| A["MiniAdmin.Api"]

本地启动

先启动后端 API:

powershell
dotnet run --project src/MiniAdmin.Api/MiniAdmin.Api.csproj --urls http://localhost:5021

再启动网关:

powershell
dotnet run --project src/MiniAdmin.Gateway/MiniAdmin.Gateway.csproj --urls http://localhost:8088

检查网关自身健康:

powershell
Invoke-WebRequest -Uri http://localhost:8088/health -UseBasicParsing

检查网关代理到 API:

powershell
Invoke-WebRequest -Uri http://localhost:8088/api/health -UseBasicParsing

默认上游配置在 src/MiniAdmin.Gateway/appsettings.json

json
{
  "ReverseProxy": {
    "Clusters": {
      "miniadmin_api": {
        "Destinations": {
          "stable": {
            "Address": "http://localhost:5021/"
          },
          "canary": {
            "Address": "http://localhost:5021/"
          }
        }
      }
    }
  }
}

如果你的 API 端口不是 5021,可以用环境变量覆盖:

powershell
$env:ReverseProxy__Clusters__miniadmin_api__Destinations__stable__Address = "http://localhost:5022/"
$env:ReverseProxy__Clusters__miniadmin_api__Destinations__canary__Address = "http://localhost:5022/"
dotnet run --project src/MiniAdmin.Gateway/MiniAdmin.Gateway.csproj --urls http://localhost:8088

/.well-known/**/connect/** 也会原样代理到 API,供 OAuth2/OIDC 客户端发现和换取令牌。

Docker Compose 使用

Compose 已包含 gateway 服务。默认容器链路是:

text
web -> gateway -> api -> mysql/redis

关键端口:

变量默认值说明
MINIADMIN_WEB_PORT5666前端访问入口
MINIADMIN_GATEWAY_PORT8088网关健康检查和外部 API 入口
MINIADMIN_HTTP_PORT8080API 直连端口,调试和健康检查使用

启动:

powershell
Copy-Item .env.example .env
docker compose up -d --build

访问:

text
前端:http://localhost:5666
网关健康:http://localhost:8088/health
API 代理:http://localhost:8088/api/health
API 直连:http://localhost:8080/health

生产或 1Panel 部署时,推荐只把前端端口暴露给公网,API 和网关端口绑定到服务器本机或内网,再由 Nginx、1Panel 网站或负载均衡统一转发。

网关限流

网关使用 RateLimiting 配置节,和 API 内部限流是两层保护:

配置项默认值说明
RateLimiting:Enabledtrue是否启用网关限流
RateLimiting:PermitLimit1200全局每个调用方在窗口期内允许的请求数
RateLimiting:WindowSeconds60全局固定窗口秒数
RateLimiting:QueueLimit0全局排队数量,默认不排队
RateLimiting:LoginPermitLimit20登录接口每个 IP 在窗口期内允许的请求数
RateLimiting:LoginWindowSeconds60登录接口固定窗口秒数
RateLimiting:LoginQueueLimit0登录接口排队数量,默认不排队

Docker 环境可通过 .env 调整:

text
MINIADMIN_GATEWAY_RATE_LIMITING_ENABLED=true
MINIADMIN_GATEWAY_RATE_LIMITING_PERMIT_LIMIT=1200
MINIADMIN_GATEWAY_RATE_LIMITING_WINDOW_SECONDS=60
MINIADMIN_GATEWAY_LOGIN_RATE_LIMITING_PERMIT_LIMIT=20
MINIADMIN_GATEWAY_LOGIN_RATE_LIMITING_WINDOW_SECONDS=60

触发限流时,网关返回 HTTP 429 和统一 JSON:

json
{
  "code": 429,
  "message": "请求过于频繁,请稍后再试。",
  "data": null
}

灰度发布、追踪与熔断

默认灰度关闭,stablecanary 都指向同一个 API,不会改变单实例部署。准备好灰度实例后配置:

text
MINIADMIN_GATEWAY_CANARY_ENABLED=true
MINIADMIN_GATEWAY_CANARY_PERCENTAGE=10
MINIADMIN_CANARY_API_ADDRESS=http://mini-admin-api-canary:8080/

相同租户、用户或 IP 会通过稳定哈希持续命中同一发布通道;X-Release-Channel: canary 可强制进入灰度,白名单和自定义请求头规则可在 Canary 配置节中设置。响应包含 X-Trace-Id,便于关联网关与 API 日志。

熔断器默认按 Compose 配置启用,可通过以下变量调整:

text
MINIADMIN_GATEWAY_CIRCUIT_BREAKER_ENABLED=true
MINIADMIN_GATEWAY_CIRCUIT_BREAKER_FAILURE_THRESHOLD=5
MINIADMIN_GATEWAY_CIRCUIT_BREAKER_BREAK_SECONDS=30

达到失败阈值后进入 Open 状态并快速返回 503;等待窗口结束进入 HalfOpen,探测成功后恢复 Closed。它保护入口,不替代业务重试、幂等或跨服务补偿。

为什么现在不直接拆成微服务

MiniAdmin 目前的核心复杂度集中在认证、RBAC、租户、工作流、消息和审计之间的协作。过早拆分会带来这些成本:

  • 本地开发需要同时启动更多服务。
  • 调试一次审批或消息链路需要跨多个日志。
  • 事务一致性要引入 Outbox、Inbox、重试和补偿。
  • 权限、租户上下文和审计上下文要跨服务传递。
  • 数据库边界变复杂,简单 CRUD 也会变成远程调用。

所以当前更推荐:网关先统一入口,后端保持模块化单体。等业务量、团队规模或部署隔离需求真的出现,再拆物理服务。

推荐拆分顺序

如果后续要走微服务,建议按风险从低到高拆:

阶段可拆服务理由
1通知服务对主流程影响低,天然异步,适合事件驱动
2文件服务存储边界清晰,可独立扩容和限流
3计划任务/运维服务与在线请求链路耦合较低
4业务模块服务例如合同、采购、客户等独立业务域
5工作流服务规则复杂、上下文多,建议等模型稳定后再拆
6认证与租户服务平台核心,不建议早期拆

微服务落地前置能力

真正拆服务前,至少补齐这些工程能力:

  • 服务注册或稳定的服务发现配置。
  • 统一配置中心或环境变量治理。
  • OpenTelemetry 链路追踪、指标和集中日志。
  • 服务间认证,例如内部 JWT、mTLS 或网关内网访问控制。
  • 分布式事件总线,例如 RabbitMQ、Kafka 或 Redis Stream。
  • Outbox/Inbox,保证本地事务和跨服务事件一致性。
  • API 版本治理,避免前端和服务之间强耦合升级。
  • 数据库边界设计,明确哪些表属于哪个服务。

当前推荐实践

短期内保持下面的架构最稳:

mermaid
flowchart TB
    G["MiniAdmin.Gateway"]
    A["MiniAdmin.Api 模块化单体"]
    DB["MySQL"]
    C["Redis"]

    G --> A
    A --> DB
    A --> C

新增业务模块时仍放在现有分层中:

  • DTO 和接口放 MiniAdmin.Application.Contracts
  • 应用服务放 MiniAdmin.Application
  • 仓储、外部服务实现放 MiniAdmin.Infrastructure
  • 标准接口通过应用服务上的 Dynamic API 元数据暴露;文件流等传输细节放 MiniAdmin.Api
  • 页面、动态路由和权限通过 PageRegistry 注册。
  • 需要对外统一入口时,通过 MiniAdmin.Gateway 暴露 /api/**

这样既能满足开源项目的上手成本,也给将来的服务拆分留出了入口层。

MiniAdmin documentation site. Built for learning, delivery, and secondary development.