# 技术架构文档

## 概述

本文档描述用户管理系统的技术架构设计,包括系统架构、性能优化、缓存策略、数据库优化等,确保系统能够满足 PRD 要求的性能指标:
- 支持 10 亿用户规模
- 支持 10 万级并发访问
- API 响应时间 P99 < 500ms
- 系统可用性 99.99%

---

## 1. 系统架构

### 1.1 整体架构

```
┌─────────────────────────────────────────────────────────────────────────┐
│                              负载均衡层                                  │
│                    (Nginx / HAProxy / LVS)                              │
└──────────────────────────────┬──────────────────────────────────────────┘
                               │
        ┌──────────────────────┼──────────────────────┐
        │                      │                      │
┌───────▼────────┐   ┌────────▼────────┐   ┌────────▼────────┐
│   CDN 层       │   │   API 网关      │   │   WebSocket     │
│  (静态资源)     │   │ (路由/限流/鉴权) │   │   (实时通信)    │
└────────────────┘   └────────┬────────┘   └─────────────────┘
                              │
        ┌─────────────────────┼─────────────────────┐
        │                     │                     │
┌───────▼────────┐   ┌────────▼────────┐   ┌────────▼────────┐
│  应用服务层    │   │  应用服务层     │   │  应用服务层     │
│  (多实例)      │   │  (多实例)       │   │  (多实例)       │
│  ┌──────────┐  │   │  ┌──────────┐  │   │  ┌──────────┐  │
│  │ 认证服务 │  │   │  │ 认证服务 │  │   │  │ 认证服务 │  │
│  │ 用户服务 │  │   │  │ 用户服务 │  │   │  │ 用户服务 │  │
│  │ 权限服务 │  │   │  │ 权限服务 │  │   │  │ 权限服务 │  │
│  └──────────┘  │   │  └──────────┘  │   │  └──────────┘  │
└───────┬────────┘   └────────┬────────┘   └────────┬────────┘
        │                      │                      │
        └──────────────────────┼──────────────────────┘
                               │
        ┌──────────────────────┼──────────────────────┐
        │                      │                      │
┌───────▼────────┐   ┌────────▼────────┐   ┌────────▼────────┐
│  缓存层        │   │  缓存层         │   │  缓存层         │
│  (Redis 集群)  │   │  (Redis 集群)   │   │  (Redis 集群)   │
│  ┌──────────┐  │   │  ┌──────────┐  │   │  ┌──────────┐  │
│  │ 本地缓存 │  │   │  │ 本地缓存 │  │   │  │ 本地缓存 │  │
│  │ 分布式   │  │   │  │ 分布式   │  │   │  │ 分布式   │  │
│  └──────────┘  │   │  └──────────┘  │   │  └──────────┘  │
└───────┬────────┘   └────────┬────────┘   └────────┬────────┘
        │                      │                      │
        └──────────────────────┼──────────────────────┘
                               │
        ┌──────────────────────┼──────────────────────┐
        │                      │                      │
┌───────▼────────┐   ┌────────▼────────┐   ┌────────▼────────┐
│  数据库层      │   │  数据库层       │   │  数据库层       │
│  (主从复制)    │   │  (主从复制)     │   │  (主从复制)     │
│  ┌──────────┐  │   │  ┌──────────┐  │   │  ┌──────────┐  │
│  │ 主库     │  │   │  │ 主库     │  │   │  │ 主库     │  │
│  │ 从库 1   │  │   │  │ 从库 1   │  │   │  │ 从库 1   │  │
│  │ 从库 2   │  │   │  │ 从库 2   │  │   │  │ 从库 2   │  │
│  └──────────┘  │   │  └──────────┘  │   │  └──────────┘  │
└────────────────┘   └─────────────────┘   └─────────────────┘
```

### 1.2 单机架构（SQLite）

```
┌─────────────────────────────────────────┐
│          用户管理系统 (单实例)           │
│                                         │
│  ┌─────────────────────────────────┐  │
│  │      应用服务 (Port 8080)       │  │
│  │  ┌───────────────────────────┐  │  │
│  │  │ 本地缓存 (L1 Cache)        │  │  │
│  │  │   - 用户信息               │  │  │
│  │  │   - 权限信息               │  │  │
│  │  │   - Token 黑名单           │  │  │
│  │  └───────────────────────────┘  │  │
│  │  ┌───────────────────────────┐  │  │
│  │  │ 认证/用户/权限服务        │  │  │
│  │  └───────────────────────────┘  │  │
│  └─────────────────────────────────┘  │
│                  │                      │
│  ┌───────────────┴───────────────┐      │
│  │                               │      │
│  ▼                               ▼      │
│  ┌──────────────────┐   ┌──────────────┐│
│  │  SQLite DB       │   │  可选 Redis  ││
│  │  (单文件存储)    │   │  (L2 Cache)  ││
│  └──────────────────┘   └──────────────┘│
└─────────────────────────────────────────┘
```

### 1.3 集群架构（PostgreSQL/MySQL）

```
┌─────────────────────────────────────────────────────────────────┐
│                        负载均衡 (Nginx)                          │
└────────────────────────┬────────────────────────────────────────┘
                         │
        ┌────────────────┼────────────────┐
        │                │                │
┌───────▼────────┐ ┌────▼────────┐ ┌─────▼────────┐
│  应用实例 1    │ │  应用实例 2 │ │  应用实例 N │
│  (8080)       │ │  (8080)     │ │  (8080)      │
│  ┌──────────┐ │ │  ┌────────┐ │ │  ┌────────┐ │
│  │ 本地缓存 │ │ │  │ 本地缓 │ │ │  │ 本地缓 │ │
│  │ L1 Cache │ │ │  │ 存 L1  │ │ │  │ 存 L1  │ │
│  └──────────┘ │ │  └────────┘ │ │  └────────┘ │
└───────┬────────┘ └────┬────────┘ └─────┬────────┘
        │               │                │
        └───────────────┼────────────────┘
                        │
        ┌───────────────┴───────────────┐
        │                               │
┌───────▼────────┐          ┌──────────▼────────┐
│ Redis 集群      │          │  PostgreSQL 集群  │
│ (L2 Cache)      │          │  ┌─────────────┐  │
│  ┌──────────┐   │          │  │  主库      │  │
│  │ Master   │   │          │  │  (写)      │  │
│  │ 哨兵     │   │          │  └─────────────┘  │
│  └──────────┘   │          │  ┌─────────────┐  │
│  ┌──────────┐   │          │  │  从库 1    │  │
│  │ Slave 1  │   │          │  │  (读)      │  │
│  └──────────┘   │          │  └─────────────┘  │
│  ┌──────────┐   │          │  ┌─────────────┐  │
│  │ Slave N  │   │          │  │  从库 N    │  │
│  └──────────┘   │          │  │  (读)      │  │
└────────────────┘          │  └─────────────┘  │
                            └───────────────────┘
```

---

## 2. 技术栈选择

### 2.1 后端技术栈

| 层级 | 技术选型 | 说明 |
|------|---------|------|
| **开发语言** | Go 1.21+ | 高性能、并发能力强、内存占用低 |
| **Web 框架** | Gin / Fiber | 轻量级、高性能 |
| **数据库驱动** | GORM / sqlx | ORM 和原生 SQL 混合使用 |
| **缓存** | Redis (go-redis) | 高性能缓存和分布式锁 |
| **配置管理** | Viper | 配置文件和环境变量管理 |
| **日志** | Zap | 高性能结构化日志 |
| **监控** | Prometheus + OpenTelemetry | 指标收集和链路追踪 |
| **限流** | Uber Rate Limit | 令牌桶算法限流 |
| **JWT** | golang-jwt/jwt | JWT 生成和验证 |
| **密码加密** | golang.org/x/crypto/argon2 | Argon2id 密码哈希 |

### 2.2 前端技术栈（Admin 后台）

当前前端技术栈不再在本文件内独立演化，唯一有效方案见：

- `docs/plans/ADMIN_FRONTEND_EXECUTION_PLAN.md`

本文件只保留当前统一结论：

| 层级 | 技术选型 | 说明 |
|------|---------|------|
| **框架** | React 18 + TypeScript | 当前唯一前端框架口径 |
| **构建工具** | Vite | 从零启动成本低，构建快 |
| **UI 组件库** | Ant Design 5 | 后台场景优先 |
| **状态管理** | React Context（仅会话态） | 不引入 Pinia / Redux / Zustand |
| **HTTP 客户端** | 原生 `fetch` + 统一请求客户端 | 不再使用 Axios |
| **路由** | React Router 6 | 统一受保护路由方案 |
| **样式** | CSS Modules + CSS Variables + AntD Theme Token | 不使用 `styled-components` |

页面范围、类型模型、认证流和 API 服务层一律以 `docs/plans/ADMIN_FRONTEND_EXECUTION_PLAN.md` 为准。

### 2.3 基础设施

| 组件 | 技术选型 | 说明 |
|------|---------|------|
| **容器化** | Docker | 应用容器化 |
| **编排** | Kubernetes / Docker Compose | 容器编排 |
| **负载均衡** | Nginx | HTTP 负载均衡 |
| **监控** | Prometheus + Grafana | 指标监控 |
| **日志** | ELK (Elasticsearch + Logstash + Kibana) | 日志收集和分析 |
| **链路追踪** | Jaeger / Zipkin | 分布式链路追踪 |
| **消息队列** | 可选：Kafka / RabbitMQ | 异步消息处理 |

---

## 3. 性能优化方案

### 3.1 多级缓存架构

```
┌─────────────────────────────────────────────────────────────┐
│                      多级缓存架构                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐     │
│  │  L1 缓存    │ -> │  L2 缓存    │ -> │  L3 缓存    │     │
│  │  (本地内存) │    │  (Redis)   │    │  (数据库)   │     │
│  │             │    │             │    │             │     │
│  │  • 用户信息 │    │  • 用户信息 │    │  • 完整数据 │     │
│  │  • 权限信息 │    │  • 权限信息 │    │  • 原始数据 │     │
│  │  • Token    │    │  • Session  │    │             │     │
│  │  • 热点数据 │    │  • 热点数据 │    │             │     │
│  │             │    │             │    │             │     │
│  │  TTL: 5min  │    │  TTL: 30min │    │  TTL: 永久 │     │
│  │  容量: 1GB  │    │  容量: 64GB │    │  容量: 10TB │     │
│  │  命中率: 85%│    │  命中率: 12% │    │  命中率: 3% │     │
│  └─────────────┘    └─────────────┘    └─────────────┘     │
│        │                  │                  │              │
│        └──────────────────┼──────────────────┘              │
│                           │                                 │
│                     ┌─────▼─────┐                           │
│                     │  缓存回源 │                           │
│                     │   策略    │                           │
│                     └───────────┘                           │
└─────────────────────────────────────────────────────────────┘
```

### 3.2 L1 本地缓存实现（Go）

```go
package cache

import (
    "sync"
    "time"
)

type CacheItem struct {
    Value      interface{}
    ExpireTime time.Time
}

type LocalCache struct {
    items map[string]*CacheItem
    mu    sync.RWMutex
}

func NewLocalCache() *LocalCache {
    cache := &LocalCache{
        items: make(map[string]*CacheItem),
    }
    // 启动后台清理过期数据
    go cache.cleanupExpired()
    return cache
}

func (c *LocalCache) Set(key string, value interface{}, ttl time.Duration) {
    c.mu.Lock()
    defer c.mu.Unlock()
    
    expireTime := time.Now().Add(ttl)
    c.items[key] = &CacheItem{
        Value:      value,
        ExpireTime: expireTime,
    }
}

func (c *LocalCache) Get(key string) (interface{}, bool) {
    c.mu.RLock()
    defer c.mu.RUnlock()
    
    item, exists := c.items[key]
    if !exists {
        return nil, false
    }
    
    if time.Now().After(item.ExpireTime) {
        return nil, false
    }
    
    return item.Value, true
}

func (c *LocalCache) Delete(key string) {
    c.mu.Lock()
    defer c.mu.Unlock()
    delete(c.items, key)
}

func (c *LocalCache) cleanupExpired() {
    ticker := time.NewTicker(1 * time.Minute)
    defer ticker.Stop()
    
    for range ticker.C {
        c.mu.Lock()
        now := time.Now()
        for key, item := range c.items {
            if now.After(item.ExpireTime) {
                delete(c.items, key)
            }
        }
        c.mu.Unlock()
    }
}
```

### 3.3 L2 Redis 缓存策略

```go
package cache

import (
    "context"
    "encoding/json"
    "time"
    
    "github.com/redis/go-redis/v9"
)

type RedisCache struct {
    client *redis.Client
}

func NewRedisCache(addr string) *RedisCache {
    rdb := redis.NewClient(&redis.Options{
        Addr:         addr,
        Password:     "",
        DB:           0,
        PoolSize:     100,
        MinIdleConns: 10,
    })
    return &RedisCache{client: rdb}
}

// 设置缓存
func (r *RedisCache) Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
    data, err := json.Marshal(value)
    if err != nil {
        return err
    }
    return r.client.Set(ctx, key, data, ttl).Err()
}

// 获取缓存
func (r *RedisCache) Get(ctx context.Context, key string, dest interface{}) error {
    data, err := r.client.Get(ctx, key).Bytes()
    if err != nil {
        return err
    }
    return json.Unmarshal(data, dest)
}

// 缓存回源
func (r *RedisCache) GetOrSet(ctx context.Context, key string, ttl time.Duration, fn func() (interface{}, error), dest interface{}) error {
    // 尝试从缓存获取
    err := r.Get(ctx, key, dest)
    if err == nil {
        return nil
    }
    
    if err != redis.Nil {
        return err
    }
    
    // 缓存未命中,从数据源获取
    value, err := fn()
    if err != nil {
        return err
    }
    
    // 设置缓存
    if err := r.Set(ctx, key, value, ttl); err != nil {
        // 缓存设置失败不影响主流程
        return nil
    }
    
    // 将值赋给 dest
    data, _ := json.Marshal(value)
    return json.Unmarshal(data, dest)
}
```

### 3.4 缓存穿透、击穿、雪崩防护

```go
package cache

import (
    "context"
    "sync"
    "time"
)

// 缓存穿透防护: 布隆过滤器
type BloomFilter struct {
    bits []bool
    size int
}

func (b *BloomFilter) Add(key string) {
    // 简化实现,实际使用推荐使用 github.com/bits-and-blooms/bloom
    idx := hash(key) % b.size
    b.bits[idx] = true
}

func (b *BloomFilter) Contains(key string) bool {
    idx := hash(key) % b.size
    return b.bits[idx]
}

// 缓存击穿防护: 单机互斥锁
type SingleFlight struct {
    mu    sync.Mutex
    calls map[string]*call
}

type call struct {
    wg  sync.WaitGroup
    val interface{}
    err error
}

func (s *SingleFlight) Do(key string, fn func() (interface{}, error)) (interface{}, error) {
    s.mu.Lock()
    if s.calls == nil {
        s.calls = make(map[string]*call)
    }
    
    if c, ok := s.calls[key]; ok {
        s.mu.Unlock()
        c.wg.Wait()
        return c.val, c.err
    }
    
    c := new(call)
    c.wg.Add(1)
    s.calls[key] = c
    s.mu.Unlock()
    
    c.val, c.err = fn()
    c.wg.Done()
    
    s.mu.Lock()
    delete(s.calls, key)
    s.mu.Unlock()
    
    return c.val, c.err
}

// 缓存雪崩防护: 随机 TTL
func RandomTTL(baseTTL time.Duration, jitter time.Duration) time.Duration {
    jitterNs := time.Duration(time.Now().UnixNano() % int64(jitter))
    return baseTTL + jitterNs
}
```

### 3.5 数据库读写分离

```go
package database

import (
    "gorm.io/gorm"
)

type Cluster struct {
    Master *gorm.DB
    Slaves []*gorm.DB
    mu     sync.RWMutex
}

func NewCluster(master *gorm.DB, slaves []*gorm.DB) *Cluster {
    return &Cluster{
        Master: master,
        Slaves: slaves,
    }
}

// 获取读库 (负载均衡)
func (c *Cluster) GetSlave() *gorm.DB {
    c.mu.RLock()
    defer c.mu.RUnlock()
    
    if len(c.Slaves) == 0 {
        return c.Master
    }
    
    // 轮询选择从库
    idx := time.Now().UnixNano() % int64(len(c.Slaves))
    return c.Slaves[idx]
}

// 写操作使用主库
func (c *Cluster) Write() *gorm.DB {
    return c.Master
}

// 读操作使用从库
func (c *Cluster) Read() *gorm.DB {
    return c.GetSlave()
}
```

### 3.6 数据库连接池优化

```yaml
# database.yml
database:
  # 主库连接池
  master:
    max_open_conns: 100      # 最大打开连接数
    max_idle_conns: 20       # 最大空闲连接数
    conn_max_lifetime: 1800s  # 连接最大存活时间（30分钟）
    conn_max_idle_time: 600s  # 连接最大空闲时间（10分钟）
  
  # 从库连接池
  slave:
    max_open_conns: 200      # 从库可以配置更大的连接池
    max_idle_conns: 50
    conn_max_lifetime: 1800s
    conn_max_idle_time: 600s
```

```go
// Go 实现
db.SetMaxOpenConns(100)
db.SetMaxIdleConns(20)
db.SetConnMaxLifetime(30 * time.Minute)
db.SetConnMaxIdleTime(10 * time.Minute)
```

---

## 4. 接口性能优化

### 4.1 批量操作优化

```go
// 不推荐: 循环查询
func GetUsersBatch(userIDs []int64) ([]*User, error) {
    var users []*User
    for _, id := range userIDs {
        var user User
        if err := db.First(&user, id).Error; err != nil {
            return nil, err
        }
        users = append(users, &user)
    }
    return users, nil
}

// 推荐: 批量查询
func GetUsersBatch(userIDs []int64) ([]*User, error) {
    var users []*User
    if err := db.Where("id IN ?", userIDs).Find(&users).Error; err != nil {
        return nil, err
    }
    return users, nil
}
```

### 4.2 预加载关联数据

```go
// 不推荐: N+1 查询
func GetUsersWithRoles() ([]*User, error) {
    var users []*User
    db.Find(&users)
    
    for _, user := range users {
        var roles []Role
        db.Where("user_id = ?", user.ID).Find(&roles) // N+1 查询
        user.Roles = roles
    }
    return users, nil
}

// 推荐: 预加载
func GetUsersWithRoles() ([]*User, error) {
    var users []*User
    db.Preload("Roles").Find(&users) // 使用 Preload 一次性加载
    return users, nil
}
```

### 4.3 索引优化

```sql
-- 用户登录查询优化
-- 不推荐: 全表扫描
SELECT * FROM users WHERE email = 'john@example.com' AND status = 1;

-- 推荐: 创建复合索引
CREATE INDEX idx_email_status ON users(email, status);

-- 角色权限查询优化
-- 不推荐: 多次关联查询
SELECT p.* FROM permissions p
INNER JOIN role_permissions rp ON p.id = rp.permission_id
WHERE rp.role_id IN (SELECT role_id FROM user_roles WHERE user_id = ?);

-- 推荐: 优化 SQL 和索引
CREATE INDEX idx_user_roles_user_id ON user_roles(user_id);
CREATE INDEX idx_role_permissions_role_id ON role_permissions(role_id);

-- 使用 JOIN 优化
SELECT p.* FROM permissions p
INNER JOIN role_permissions rp ON p.id = rp.permission_id
INNER JOIN user_roles ur ON rp.role_id = ur.role_id
WHERE ur.user_id = ?;
```

### 4.4 分页优化（游标分页）

```go
// 不推荐: OFFSET 分页（数据量大时性能差）
func GetUsersByPage(page, pageSize int) ([]*User, error) {
    var users []*User
    offset := (page - 1) * pageSize
    if err := db.Offset(offset).Limit(pageSize).Find(&users).Error; err != nil {
        return nil, err
    }
    return users, nil
}

// 推荐: 游标分页（基于 ID）
type PageResult struct {
    Users    []*User `json:"users"`
    LastID   int64   `json:"last_id"`
    HasMore  bool    `json:"has_more"`
}

func GetUsersByCursor(lastID int64, pageSize int) (*PageResult, error) {
    var users []*User
    query := db.Order("id ASC").Limit(pageSize + 1)
    
    if lastID > 0 {
        query = query.Where("id > ?", lastID)
    }
    
    if err := query.Find(&users).Error; err != nil {
        return nil, err
    }
    
    hasMore := len(users) > pageSize
    if hasMore {
        users = users[:pageSize]
    }
    
    var lastIDResult int64
    if len(users) > 0 {
        lastIDResult = users[len(users)-1].ID
    }
    
    return &PageResult{
        Users:   users,
        LastID:  lastIDResult,
        HasMore: hasMore,
    }, nil
}
```

---

## 5. 并发处理优化

### 5.1 协程池

```go
package worker

import (
    "sync"
)

type Task func()

type WorkerPool struct {
    tasks   chan Task
    workers int
    wg      sync.WaitGroup
}

func NewWorkerPool(workers int, taskQueueSize int) *WorkerPool {
    return &WorkerPool{
        tasks:   make(chan Task, taskQueueSize),
        workers: workers,
    }
}

func (p *WorkerPool) Start() {
    for i := 0; i < p.workers; i++ {
        p.wg.Add(1)
        go p.worker()
    }
}

func (p *WorkerPool) worker() {
    defer p.wg.Done()
    for task := range p.tasks {
        task()
    }
}

func (p *WorkerPool) Submit(task Task) {
    p.tasks <- task
}

func (p *WorkerPool) Stop() {
    close(p.tasks)
    p.wg.Wait()
}
```

### 5.2 批量并发查询

```go
package service

import (
    "sync"
)

func BatchGetUsers(userIDs []int64) (map[int64]*User, error) {
    result := make(map[int64]*User)
    var mu sync.Mutex
    var wg sync.WaitGroup
    errChan := make(chan error, len(userIDs))
    
    // 创建协程池
    pool := worker.NewWorkerPool(10, 1000)
    pool.Start()
    defer pool.Stop()
    
    for _, id := range userIDs {
        wg.Add(1)
        pool.Submit(func() {
            defer wg.Done()
            
            user, err := getUserByID(id)
            if err != nil {
                errChan <- err
                return
            }
            
            mu.Lock()
            result[id] = user
            mu.Unlock()
        })
    }
    
    wg.Wait()
    close(errChan)
    
    // 检查是否有错误
    for err := range errChan {
        if err != nil {
            return nil, err
        }
    }
    
    return result, nil
}
```

---

## 6. 性能监控

### 6.1 Prometheus 指标定义

```go
package metrics

import (
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promauto"
)

var (
    // HTTP 请求数
    HTTPRequestsTotal = promauto.NewCounterVec(
        prometheus.CounterOpts{
            Name: "http_requests_total",
            Help: "Total number of HTTP requests",
        },
        []string{"method", "path", "status"},
    )
    
    // HTTP 请求耗时
    HTTPRequestDuration = promauto.NewHistogramVec(
        prometheus.HistogramOpts{
            Name:    "http_request_duration_seconds",
            Help:    "HTTP request latency in seconds",
            Buckets: prometheus.DefBuckets,
        },
        []string{"method", "path"},
    )
    
    // 缓存命中率
    CacheHitTotal = promauto.NewCounterVec(
        prometheus.CounterOpts{
            Name: "cache_hit_total",
            Help: "Total number of cache hits",
        },
        []string{"cache_level", "key_pattern"},
    )
    
    CacheMissTotal = promauto.NewCounterVec(
        prometheus.CounterOpts{
            Name: "cache_miss_total",
            Help: "Total number of cache misses",
        },
        []string{"cache_level", "key_pattern"},
    )
    
    // 数据库查询耗时
    DBQueryDuration = promauto.NewHistogramVec(
        prometheus.HistogramOpts{
            Name:    "db_query_duration_seconds",
            Help:    "Database query latency in seconds",
            Buckets: []float64{0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5},
        },
        []string{"operation", "table"},
    )
    
    // 在线用户数
    OnlineUsers = promauto.NewGauge(
        prometheus.GaugeOpts{
            Name: "online_users",
            Help: "Current number of online users",
        },
    )
    
    // 总用户数
    TotalUsers = promauto.NewGauge(
        prometheus.GaugeOpts{
            Name: "total_users",
            Help: "Total number of users",
        },
    )
)
```

### 6.2 中间件集成

```go
package middleware

import (
    "strconv"
    "time"
    
    "github.com/gin-gonic/gin"
    "your-project/metrics"
)

func PrometheusMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        
        // 处理请求
        c.Next()
        
        // 记录指标
        duration := time.Since(start).Seconds()
        status := strconv.Itoa(c.Writer.Status())
        
        metrics.HTTPRequestsTotal.WithLabelValues(
            c.Request.Method,
            c.FullPath(),
            status,
        ).Inc()
        
        metrics.HTTPRequestDuration.WithLabelValues(
            c.Request.Method,
            c.FullPath(),
        ).Observe(duration)
    }
}
```

---

## 7. 性能目标与调优

### 7.1 性能目标

| 指标 | 目标值 | 当前值 | 状态 |
|------|--------|--------|------|
| 并发用户数 | 100,000 | - | 待验证 |
| QPS | 100,000 | - | 待验证 |
| P50 响应时间 | < 100ms | - | 待验证 |
| P99 响应时间 | < 500ms | - | 待验证 |
| 缓存命中率 | > 95% | - | 待验证 |
| 数据库 QPS | < 10,000 | - | 待验证 |

### 7.2 性能调优清单

- [ ] 启用本地缓存（L1 Cache）
- [ ] 配置 Redis 集群（L2 Cache）
- [ ] 数据库读写分离
- [ ] 优化数据库索引
- [ ] 批量操作优化
- [ ] 使用游标分页
- [ ] 连接池调优
- [ ] 协程池优化
- [ ] 启用 Gzip 压缩
- [ ] CDN 加速静态资源
- [ ] HTTP/2 支持
- [ ] 数据库查询优化

### 7.3 压力测试方案

```bash
# 使用 Apache Bench (ab)
ab -n 100000 -c 1000 http://localhost:8080/api/v1/users

# 使用 wrk
wrk -t12 -c400 -d30s http://localhost:8080/api/v1/users

# 使用 hey
hey -n 100000 -c 1000 http://localhost:8080/api/v1/users
```

---

## 8. 扩展性设计

### 8.1 水平扩展

- **无状态设计**: 应用服务不保存状态,支持水平扩展
- **会话管理**: 使用 Redis 存储会话
- **文件存储**: 使用对象存储（OSS/S3）
- **消息队列**: 使用 Kafka/RabbitMQ 异步处理

### 8.2 垂直扩展

- **资源限制**: 根据 QPS 调整资源配置
- **缓存调优**: 增加缓存容量
- **数据库优化**: 增加 CPU/内存,使用更好的存储

---

## 9. 容灾与高可用

### 9.1 多机房部署

```
┌─────────────────────────────────────────────────────────┐
│                    全局负载均衡 (GSLB)                  │
└──────────────────┬───────────────┬──────────────────────┘
                   │               │
        ┌──────────▼────┐  ┌──────▼──────────┐
        │  机房 A (北京) │  │  机房 B (上海)  │
        │  ┌──────────┐  │  │  ┌──────────┐  │
        │  │ 负载均衡 │  │  │  │ 负载均衡 │  │
        │  └────┬─────┘  │  │  └────┬─────┘  │
        │       │        │  │       │        │
        │  ┌────▼────┐  │  │  ┌────▼────┐  │
        │  │ 应用集群│  │  │  │ 应用集群│  │
        │  └────┬────┘  │  │  └────┬────┘  │
        │       │        │  │       │        │
        │  ┌────▼────┐  │  │  ┌────▼────┐  │
        │  │Redis集群│  │  │  │Redis集群│  │
        │  └─────────┘  │  │  └─────────┘  │
        │  ┌────┬────┐  │  │  ┌────┬────┐  │
        │  │DB主│DB从│  │  │  │DB主│DB从│  │
        │  └────┴────┘  │  │  └────┴────┘  │
        └───────────────┘  └───────────────┘
                   │               │
                   └───────┬───────┘
                           │
                    ┌──────▼──────┐
                    │  异地灾备    │
                    │  (广州)     │
                    └─────────────┘
```

### 9.2 数据备份策略

- **实时备份**: 主从复制
- **每日备份**: 全量备份 + 增量备份
- **跨机房备份**: 异地备份
- **加密存储**: 备份数据加密

---

## 10. 性能优化案例

### 10.1 登录接口优化

**优化前**: 500ms (P99)
```go
// 每次都查询数据库
func Login(username, password string) (*User, error) {
    var user User
    db.Where("username = ?", username).First(&user)
    // 验证密码...
    return &user, nil
}
```

**优化后**: 50ms (P99)
```go
// 使用本地缓存 + Redis 缓存
func Login(username, password string) (*User, error) {
    // L1 缓存查询
    if user, ok := l1Cache.Get("user:" + username); ok {
        return user.(*User), nil
    }
    
    // L2 缓存查询
    var user User
    err := redisCache.GetOrSet(ctx, "user:"+username, 30*time.Minute, 
        func() (interface{}, error) {
            var u User
            db.Where("username = ?", username).First(&u)
            return &u, nil
        }, &user)
    
    if err != nil {
        return nil, err
    }
    
    // 更新 L1 缓存
    l1Cache.Set("user:"+username, &user, 5*time.Minute)
    
    return &user, nil
}
```

### 10.2 权限查询优化

**优化前**: 1000ms (P99)
```go
// 每次都查询数据库
func GetUserPermissions(userID int64) ([]string, error) {
    var userRoles []UserRole
    db.Where("user_id = ?", userID).Find(&userRoles)
    
    var permissions []string
    for _, ur := range userRoles {
        var rolePermissions []RolePermission
        db.Where("role_id = ?", ur.RoleID).Find(&rolePermissions)
        
        for _, rp := range rolePermissions {
            var permission Permission
            db.First(&permission, rp.PermissionID)
            permissions = append(permissions, permission.Code)
        }
    }
    
    return permissions, nil
}
```

**优化后**: 20ms (P99)
```go
// 使用本地缓存 + Redis 缓存 + 批量查询
func GetUserPermissions(userID int64) ([]string, error) {
    cacheKey := fmt.Sprintf("user:permissions:%d", userID)
    
    // L1 缓存查询
    if perms, ok := l1Cache.Get(cacheKey); ok {
        return perms.([]string), nil
    }
    
    // L2 缓存查询
    var permissions []string
    err := redisCache.GetOrSet(ctx, cacheKey, 30*time.Minute,
        func() (interface{}, error) {
            // 批量查询角色和权限
            var result []struct {
                PermissionCode string
            }
            
            db.Table("permissions").
                Select("permissions.code as permission_code").
                Joins("INNER JOIN role_permissions ON role_permissions.permission_id = permissions.id").
                Joins("INNER JOIN user_roles ON user_roles.role_id = role_permissions.role_id").
                Where("user_roles.user_id = ?", userID).
                Scan(&result)
            
            var codes []string
            for _, r := range result {
                codes = append(codes, r.PermissionCode)
            }
            
            return codes, nil
        }, &permissions)
    
    if err != nil {
        return nil, err
    }
    
    // 更新 L1 缓存
    l1Cache.Set(cacheKey, permissions, 5*time.Minute)
    
    return permissions, nil
}
```

---

## 11. 性能监控与告警

### 11.1 核心监控指标

| 指标 | 类型 | 说明 |
|------|------|------|
| `http_requests_total` | Counter | HTTP 请求总数 |
| `http_request_duration_seconds` | Histogram | HTTP 请求耗时 |
| `cache_hit_total` | Counter | 缓存命中数 |
| `cache_miss_total` | Counter | 缓存未命中数 |
| `db_query_duration_seconds` | Histogram | 数据库查询耗时 |
| `online_users` | Gauge | 在线用户数 |
| `total_users` | Gauge | 总用户数 |

### 11.2 告警规则

```yaml
groups:
  - name: user-ms-alerts
    rules:
      # 高错误率告警
      - alert: HighErrorRate
        expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.01
        for: 5m
        annotations:
          summary: "高错误率告警"
      
      # 高响应时间告警
      - alert: HighResponseTime
        expr: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 0.5
        for: 5m
        annotations:
          summary: "P99 响应时间超过 500ms"
      
      # 低缓存命中率告警
      - alert: LowCacheHitRate
        expr: rate(cache_hit_total[5m]) / (rate(cache_hit_total[5m]) + rate(cache_miss_total[5m])) < 0.9
        for: 10m
        annotations:
          summary: "缓存命中率低于 90%"
```

---

## 12. 总结

本技术架构文档定义了用户管理系统的完整技术方案,包括:

1. **系统架构**: 单机（SQLite）和集群（PostgreSQL/MySQL）两种架构
2. **多级缓存**: L1 本地缓存 + L2 Redis 缓存 + L3 数据库
3. **性能优化**: 批量操作、预加载、索引优化、游标分页
4. **并发处理**: 协程池、批量并发查询
5. **监控告警**: Prometheus 指标、告警规则
6. **扩展性**: 水平扩展、垂直扩展
7. **高可用**: 多机房部署、数据备份

### 12.1 安全架构

| 安全机制 | 实现状态 | 说明 |
|----------|----------|------|
| 密码哈希 | ✅ Argon2id | 64MB 内存，5次迭代，4并行 |
| JWT JTI 防枚举 | ✅ | timestamp(8B hex) + random(16B hex) |
| Token 滚动轮换 | ✅ | refresh token 每次刷新后旧值失效 |
| 访问令牌内存存储 | ✅ | 前端不使用 localStorage 存 token |
| 401 并发刷新锁 | ✅ | 单例 Promise 模式 |
| CSRF 保护 | ✅ | POST/PUT/DELETE/PATCH 自动注入 CSRF Token |
| 常数时间密码比较 | ✅ | 防时序攻击 |
| JWT Secret 弱检测 | ✅ | 启动时 Warn 日志 |
| TOTP 设备信任 | ✅ | 信任设备免二次验证 |
| 密码修改 PCE | ✅ | PasswordChangedAt 更新使旧 token 失效 |

### 12.2 已修复的安全问题

| 问题 | 严重等级 | 修复版本 |
|------|----------|----------|
| LIKE 查询 SQL 注入 | P0 | 2026-04-09 |
| 登录计数竞态条件 | P0 | 2026-04-09 |
| Refresh Token 黑名单 fail-open | P0 | 2026-04-09 |
| 验证码 Replay 攻击 | P0 | 2026-04-09 |
| CORS 危险配置 | P0 | 2026-04-09 |
| UpdateUser IDOR 越权 | P0 | 2026-04-09 |
| Login TOTP 绕过 | P0 | 2026-04-09 |
| 游标分页数据错乱 | P0 | 2026-04-09 |
| 错误信息泄露 | P1 | 2026-04-09 |
| OAuth context 丢失 | P1 | 2026-04-09 |
| rows.Err 未检查 | P1 | 2026-04-09 |
| DeleteRole 非事务 | P1 | 2026-04-09 |
| ActivateEmail GET 越权 | P2 | 2026-04-18 |
| ValidateResetToken GET 越权 | P2 | 2026-04-18 |

---

*本文档持续更新中，如有疑问请联系技术团队。*
