Files
user-system/docs/ARCHITECTURE.md

1166 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 技术架构文档
## 概述
本文档描述用户管理系统的技术架构设计,包括系统架构、性能优化、缓存策略、数据库优化等,确保系统能够满足 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. **高可用**: 多机房部署、数据备份
通过以上优化,系统能够达到 PRD 要求的性能指标:
- 10 亿用户规模
- 10 万级并发
- P99 响应时间 < 500ms
- 99.99% 可用性
---
*本文档持续更新中,如有疑问请联系技术团队。*