457 lines
19 KiB
Markdown
457 lines
19 KiB
Markdown
# YARP Gateway 架构文档
|
|
|
|
## 1. 整体架构模式
|
|
|
|
本项目基于 **YARP (Yet Another Reverse Proxy)** 实现的 API 网关,采用 **反向代理模式**,支持多租户路由、动态配置和分布式负载均衡。
|
|
|
|
### 1.1 架构图
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
│ 外部请求 │
|
|
└─────────────────────────────────┬───────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
│ ASP.NET Core Pipeline │
|
|
├─────────────────────────────────────────────────────────────────────────────┤
|
|
│ ┌────────────────┐ ┌─────────────────────┐ ┌──────────────────────┐ │
|
|
│ │ CORS 中间件 │ -> │ JwtTransformMiddleware │ -> │ TenantRoutingMiddleware │ │
|
|
│ └────────────────┘ └─────────────────────┘ └──────────────────────┘ │
|
|
└─────────────────────────────────┬───────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
│ YARP Reverse Proxy │
|
|
├─────────────────────────────────────────────────────────────────────────────┤
|
|
│ ┌───────────────────────────┐ ┌──────────────────────────────────────┐ │
|
|
│ │ DynamicProxyConfigProvider │ -> │ DistributedWeightedRoundRobinPolicy │ │
|
|
│ └───────────┬───────────────┘ └──────────────────────────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ ┌───────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ RouteConfig / ClusterConfig │ │
|
|
│ └───────────────────────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────┬───────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
│ 后端服务集群 │
|
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
│ │ Service A│ │ Service B│ │ Service C│ │ Service D│ │
|
|
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 1.2 核心设计模式
|
|
|
|
| 模式 | 应用场景 | 实现位置 |
|
|
|------|----------|----------|
|
|
| 反向代理 | 请求转发 | `Yarp.ReverseProxy` |
|
|
| 策略模式 | 负载均衡策略 | `DistributedWeightedRoundRobinPolicy` |
|
|
| 观察者模式 | 配置变更监听 | `PgSqlConfigChangeListener` |
|
|
| 工厂模式 | DbContext 创建 | `GatewayDbContextFactory` |
|
|
| 单例模式 | 配置提供者 | `DatabaseRouteConfigProvider`, `DatabaseClusterConfigProvider` |
|
|
| 生产者-消费者 | 配置变更通知 | `Channel<bool>` in `PgSqlConfigChangeListener` |
|
|
|
|
---
|
|
|
|
## 2. 核心组件和职责
|
|
|
|
### 2.1 中间件层 (Middleware)
|
|
|
|
#### JwtTransformMiddleware
|
|
**文件路径**: `src/Middleware/JwtTransformMiddleware.cs`
|
|
|
|
**职责**:
|
|
- 解析 JWT Token
|
|
- 提取租户信息 (tenant claim)
|
|
- 将用户信息注入请求头
|
|
|
|
**处理流程**:
|
|
```
|
|
Authorization Header -> JWT 解析 -> 提取 Claims -> 注入 X-Tenant-Id, X-User-Id, X-User-Name, X-Roles
|
|
```
|
|
|
|
#### TenantRoutingMiddleware
|
|
**文件路径**: `src/Middleware/TenantRoutingMiddleware.cs`
|
|
|
|
**职责**:
|
|
- 从请求头获取租户 ID
|
|
- 根据 URL 路径提取服务名称
|
|
- 查询路由缓存获取目标集群
|
|
- 设置动态集群 ID
|
|
|
|
### 2.2 配置提供层 (Config Providers)
|
|
|
|
#### DynamicProxyConfigProvider
|
|
**文件路径**: `src/DynamicProxy/DynamicProxyConfigProvider.cs`
|
|
|
|
**职责**:
|
|
- 实现 YARP 的 `IProxyConfigProvider` 接口
|
|
- 整合路由和集群配置
|
|
- 提供配置变更通知机制
|
|
|
|
```csharp
|
|
public interface IProxyConfigProvider
|
|
{
|
|
IProxyConfig GetConfig();
|
|
}
|
|
```
|
|
|
|
#### DatabaseRouteConfigProvider
|
|
**文件路径**: `src/Config/DatabaseRouteConfigProvider.cs`
|
|
|
|
**职责**:
|
|
- 从数据库加载路由配置
|
|
- 转换为 YARP `RouteConfig` 格式
|
|
- 支持热重载
|
|
|
|
#### DatabaseClusterConfigProvider
|
|
**文件路径**: `src/Config/DatabaseClusterConfigProvider.cs`
|
|
|
|
**职责**:
|
|
- 从数据库加载集群配置
|
|
- 管理服务实例 (地址、权重)
|
|
- 配置健康检查策略
|
|
|
|
### 2.3 服务层 (Services)
|
|
|
|
#### RouteCache
|
|
**文件路径**: `src/Services/RouteCache.cs`
|
|
|
|
**职责**:
|
|
- 内存缓存路由信息
|
|
- 支持全局路由和租户专用路由
|
|
- 提供快速查询接口
|
|
|
|
**数据结构**:
|
|
```
|
|
_globalRoutes: ConcurrentDictionary<string, RouteInfo> // 全局路由
|
|
_tenantRoutes: ConcurrentDictionary<string, ConcurrentDictionary<string, RouteInfo>> // 租户路由
|
|
```
|
|
|
|
**查询优先级**: 租户专用路由 > 全局路由
|
|
|
|
#### PgSqlConfigChangeListener
|
|
**文件路径**: `src/Services/PgSqlConfigChangeListener.cs`
|
|
|
|
**职责**:
|
|
- 监听 PostgreSQL NOTIFY 事件
|
|
- 双重保障:事件监听 + 轮询回退
|
|
- 触发配置热重载
|
|
|
|
**监听流程**:
|
|
```
|
|
PostgreSQL NOTIFY -> OnNotification -> _reloadChannel -> ReloadConfigAsync
|
|
│
|
|
└── FallbackPollingAsync (5分钟轮询)
|
|
```
|
|
|
|
#### KubernetesPendingSyncService
|
|
**文件路径**: `src/Services/KubernetesPendingSyncService.cs`
|
|
|
|
**职责**:
|
|
- 同步 Kubernetes 服务发现
|
|
- 管理待处理服务列表
|
|
- 清理过期服务记录
|
|
|
|
#### RedisConnectionManager
|
|
**文件路径**: `src/Services/RedisConnectionManager.cs`
|
|
|
|
**职责**:
|
|
- 管理 Redis 连接
|
|
- 提供分布式锁实现
|
|
- 连接池管理
|
|
|
|
### 2.4 负载均衡层
|
|
|
|
#### DistributedWeightedRoundRobinPolicy
|
|
**文件路径**: `src/LoadBalancing/DistributedWeightedRoundRobinPolicy.cs`
|
|
|
|
**职责**:
|
|
- 实现加权轮询负载均衡
|
|
- 基于 Redis 的分布式状态存储
|
|
- 支持实例权重配置
|
|
|
|
**算法流程**:
|
|
```
|
|
1. 获取分布式锁 (Redis)
|
|
2. 读取负载均衡状态
|
|
3. 计算权重选择目标
|
|
4. 更新状态并释放锁
|
|
5. 失败时降级到简单选择
|
|
```
|
|
|
|
---
|
|
|
|
## 3. 数据流和请求处理流程
|
|
|
|
### 3.1 请求处理流程图
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client as 客户端
|
|
participant CORS as CORS中间件
|
|
participant JWT as JwtTransformMiddleware
|
|
participant Tenant as TenantRoutingMiddleware
|
|
participant YARP as YARP代理
|
|
participant LB as 负载均衡器
|
|
participant Service as 后端服务
|
|
|
|
Client->>CORS: HTTP请求
|
|
CORS->>JWT: 跨域检查通过
|
|
JWT->>JWT: 解析JWT Token
|
|
JWT->>Tenant: 注入租户信息头
|
|
Tenant->>Tenant: 提取服务名称
|
|
Tenant->>Tenant: 查询RouteCache
|
|
Tenant->>YARP: 设置动态集群ID
|
|
YARP->>LB: 获取可用目标
|
|
LB->>LB: 加权轮询选择
|
|
LB->>Service: 转发请求
|
|
Service-->>Client: 返回响应
|
|
```
|
|
|
|
### 3.2 配置变更流程
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A[数据库变更] --> B[SaveChangesAsync]
|
|
B --> C[DetectConfigChanges]
|
|
C --> D[NOTIFY gateway_config_changed]
|
|
D --> E[PgSqlConfigChangeListener]
|
|
E --> F{收到通知?}
|
|
F -->|是| G[ReloadConfigAsync]
|
|
F -->|否| H[轮询检测版本变化]
|
|
H --> G
|
|
G --> I[RouteCache.ReloadAsync]
|
|
G --> J[DatabaseRouteConfigProvider.ReloadAsync]
|
|
G --> K[DatabaseClusterConfigProvider.ReloadAsync]
|
|
I --> L[更新内存缓存]
|
|
J --> L
|
|
K --> L
|
|
L --> M[DynamicProxyConfigProvider.UpdateConfig]
|
|
M --> N[触发 IChangeToken]
|
|
N --> O[YARP重新加载配置]
|
|
```
|
|
|
|
### 3.3 Kubernetes 服务发现流程
|
|
|
|
```
|
|
┌─────────────────┐
|
|
│ Kubernetes API │
|
|
└────────┬────────┘
|
|
│ 30s 间隔
|
|
▼
|
|
┌─────────────────────────────┐
|
|
│ KubernetesPendingSyncService │
|
|
├─────────────────────────────┤
|
|
│ 1. 获取 K8s 服务列表 │
|
|
│ 2. 对比现有待处理记录 │
|
|
│ 3. 新增/更新/清理记录 │
|
|
└────────┬────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────┐
|
|
│ GwPendingServiceDiscovery │
|
|
│ (待处理服务发现表) │
|
|
└────────┬────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────┐
|
|
│ PendingServicesController │
|
|
│ - GET: 查看待处理服务 │
|
|
│ - POST /assign: 分配集群 │
|
|
│ - POST /reject: 拒绝服务 │
|
|
└─────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 4. 关键抽象层
|
|
|
|
### 4.1 配置模型
|
|
|
|
```
|
|
┌───────────────────────────────────────────────────────────────┐
|
|
│ 配置层次结构 │
|
|
├───────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌─────────────────┐ ┌─────────────────┐ │
|
|
│ │ JwtConfig │ │ RedisConfig │ │
|
|
│ │ - Authority │ │ - Connection │ │
|
|
│ │ - Audience │ │ - Database │ │
|
|
│ │ - Validate* │ │ - InstanceName │ │
|
|
│ └─────────────────┘ └─────────────────┘ │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
│ │ DynamicProxyConfigProvider │ │
|
|
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
|
|
│ │ │ RouteConfig[] │ │ ClusterConfig[] │ │ │
|
|
│ │ │ - RouteId │ │ - ClusterId │ │ │
|
|
│ │ │ - ClusterId │ │ - Destinations │ │ │
|
|
│ │ │ - Match.Path │ │ - LoadBalancing │ │ │
|
|
│ │ │ - Metadata │ │ - HealthCheck │ │ │
|
|
│ │ └─────────────────┘ └─────────────────┘ │ │
|
|
│ └─────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
└───────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 4.2 数据模型
|
|
|
|
```
|
|
┌─────────────────┐ ┌─────────────────┐
|
|
│ GwTenant │ │ GwTenantRoute │
|
|
├─────────────────┤ ├─────────────────┤
|
|
│ Id │ │ Id │
|
|
│ TenantCode ────┼────►│ TenantCode │
|
|
│ TenantName │ │ ServiceName │
|
|
│ Status │ │ ClusterId │
|
|
│ Version │ │ PathPattern │
|
|
│ IsDeleted │ │ Priority │
|
|
└─────────────────┘ │ IsGlobal │
|
|
│ Status │
|
|
│ Version │
|
|
└────────┬────────┘
|
|
│
|
|
▼
|
|
┌─────────────────┐
|
|
│ GwServiceInstance│
|
|
├─────────────────┤
|
|
│ Id │
|
|
│ ClusterId ────┤
|
|
│ DestinationId │
|
|
│ Address │
|
|
│ Health │
|
|
│ Weight │
|
|
│ Status │
|
|
│ Version │
|
|
└─────────────────┘
|
|
```
|
|
|
|
### 4.3 接口定义
|
|
|
|
```csharp
|
|
// 路由缓存接口
|
|
public interface IRouteCache
|
|
{
|
|
Task InitializeAsync();
|
|
Task ReloadAsync();
|
|
RouteInfo? GetRoute(string tenantCode, string serviceName);
|
|
RouteInfo? GetRouteByPath(string path);
|
|
}
|
|
|
|
// Redis 连接管理接口
|
|
public interface IRedisConnectionManager
|
|
{
|
|
IConnectionMultiplexer GetConnection();
|
|
Task<IDisposable> AcquireLockAsync(string key, TimeSpan? expiry = null);
|
|
Task<T> ExecuteInLockAsync<T>(string key, Func<Task<T>> func, TimeSpan? expiry = null);
|
|
}
|
|
|
|
// 负载均衡策略接口 (YARP)
|
|
public interface ILoadBalancingPolicy
|
|
{
|
|
string Name { get; }
|
|
DestinationState? PickDestination(HttpContext context, ClusterState cluster, IReadOnlyList<DestinationState> availableDestinations);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. 入口点分析
|
|
|
|
### 5.1 程序入口 (`Program.cs`)
|
|
|
|
**文件路径**: `src/Program.cs`
|
|
|
|
**启动流程**:
|
|
|
|
```
|
|
1. 创建 WebApplication Builder
|
|
└── 配置 Serilog 日志
|
|
|
|
2. 配置选项
|
|
├── JwtConfig (JWT 认证配置)
|
|
└── RedisConfig (Redis 连接配置)
|
|
|
|
3. 注册数据库服务
|
|
└── GatewayDbContext (PostgreSQL)
|
|
|
|
4. 注册核心服务 (Singleton)
|
|
├── DatabaseRouteConfigProvider
|
|
├── DatabaseClusterConfigProvider
|
|
├── RouteCache
|
|
├── RedisConnectionManager
|
|
├── DynamicProxyConfigProvider
|
|
└── DistributedWeightedRoundRobinPolicy
|
|
|
|
5. 注册后台服务 (HostedService)
|
|
├── PgSqlConfigChangeListener
|
|
└── KubernetesPendingSyncService
|
|
|
|
6. 配置中间件管道
|
|
├── CORS
|
|
├── JwtTransformMiddleware
|
|
└── TenantRoutingMiddleware
|
|
|
|
7. 映射端点
|
|
├── /health (健康检查)
|
|
├── /api/gateway/* (管理 API)
|
|
└── /api/* (代理路由)
|
|
|
|
8. 初始化并运行
|
|
└── RouteCache.InitializeAsync()
|
|
```
|
|
|
|
### 5.2 依赖注入关系
|
|
|
|
```
|
|
Program.cs
|
|
│
|
|
├── Config/
|
|
│ ├── JwtConfig (Options)
|
|
│ ├── RedisConfig (Options + Singleton)
|
|
│ ├── DatabaseRouteConfigProvider (Singleton)
|
|
│ └── DatabaseClusterConfigProvider (Singleton)
|
|
│
|
|
├── DynamicProxy/
|
|
│ └── DynamicProxyConfigProvider (Singleton, IProxyConfigProvider)
|
|
│
|
|
├── Services/
|
|
│ ├── RouteCache (Singleton, IRouteCache)
|
|
│ ├── RedisConnectionManager (Singleton)
|
|
│ ├── PgSqlConfigChangeListener (HostedService)
|
|
│ └── KubernetesPendingSyncService (HostedService)
|
|
│
|
|
├── LoadBalancing/
|
|
│ └── DistributedWeightedRoundRobinPolicy (Singleton, ILoadBalancingPolicy)
|
|
│
|
|
└── Data/
|
|
└── GatewayDbContext (DbContextFactory)
|
|
```
|
|
|
|
---
|
|
|
|
## 6. 技术栈
|
|
|
|
| 组件 | 技术 | 用途 |
|
|
|------|------|------|
|
|
| 反向代理 | YARP 2.x | 核心代理功能 |
|
|
| 数据库 | PostgreSQL + EF Core | 配置存储 |
|
|
| 缓存 | Redis | 分布式状态、锁 |
|
|
| 服务发现 | Fengling.ServiceDiscovery | Kubernetes 集成 |
|
|
| 日志 | Serilog | 结构化日志 |
|
|
| 容器化 | Docker | 部署支持 |
|
|
| 目标框架 | .NET 10.0 | 运行时 |
|
|
|
|
---
|
|
|
|
## 7. 扩展点
|
|
|
|
1. **负载均衡策略**: 实现 `ILoadBalancingPolicy` 接口
|
|
2. **配置提供者**: 继承 `IProxyConfigProvider`
|
|
3. **中间件**: 添加自定义中间件到管道
|
|
4. **服务发现**: 扩展 `IServiceDiscoveryProvider`
|
|
5. **健康检查**: 配置 `HealthCheckConfig` |