8.5 KiB
8.5 KiB
017-architecture.mdc (Deep Reference)
该文件为原始详细规范归档,供 Tier 3 按需读取。
🏗️ Million-Level Concurrency Architecture Standards
架构总览
┌──────────────┐
│ CDN/WAF │
└──────┬───────┘
│
┌────────────┴────────────┐
│ Nginx Cluster │
│ (负载均衡 + SSL + 静态) │
└────────────┬────────────┘
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Hyperf-1 │ │ Hyperf-2 │ │ Hyperf-N │
│ Swoole │ │ Swoole │ │ Swoole │
│ HTTP:9501│ │ HTTP:9501│ │ HTTP:9501│
│ WS:9502 │ │ WS:9502 │ │ WS:9502 │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
└───────┬───────┴───────┬───────┘
│ │
┌──────┴──────┐ ┌─────┴──────┐
│ Redis │ │ MySQL │
│ Cluster/ │ │ Master │
│ Sentinel │ │ ├─Slave 1 │
│ │ │ └─Slave 2 │
└─────────────┘ └────────────┘
无状态服务设计
所有 Hyperf 实例必须无状态,确保水平扩展:
| 状态类型 | 存储位置 | 禁止 |
|---|---|---|
| 用户 Session | Redis | 存储在内存/文件 |
| JWT Token | Redis (可验证+可吊销) | 仅本地验证 |
| 文件上传 | 对象存储 (S3/OSS) | 本地 storage/ |
| WebSocket 连接 | Redis 维护映射表 | 进程内变量 |
| 配置 | 配置中心 / env | 硬编码 |
缓存策略
多级缓存
L1: 进程内缓存 (APCu / Swoole Table) — 毫秒级, 容量小
L2: Redis 缓存 — 亚毫秒级, 容量中
L3: MySQL 查询 — 毫秒级, 容量大
缓存防护
| 问题 | 场景 | 解决方案 |
|---|---|---|
| 穿透 | 查询不存在的数据 | 布隆过滤器 / 缓存空值 (TTL 30s) |
| 雪崩 | 大量缓存同时过期 | TTL 加随机抖动 / 预热 |
| 击穿 | 热点 Key 过期时大量请求 | 互斥锁 (singleflight) |
// Cache-Aside with mutex lock
public function getOrderWithLock(int $id): ?ProductionOrder
{
$cacheKey = "order:{$id}";
$lockKey = "lock:order:{$id}";
$cached = $this->redis->get($cacheKey);
if ($cached !== false) {
return unserialize($cached);
}
// Mutex: only one coroutine queries DB
$lock = $this->redis->set($lockKey, '1', ['NX', 'EX' => 5]);
if ($lock) {
try {
$order = ProductionOrder::find($id);
$ttl = 300 + random_int(0, 60); // jitter
$this->redis->setex($cacheKey, $ttl, serialize($order));
return $order;
} finally {
$this->redis->del($lockKey);
}
}
// Wait and retry
Coroutine::sleep(0.05);
return $this->getOrderWithLock($id);
}
限流策略
令牌桶 (API 级别)
use Hyperf\RateLimit\Annotation\RateLimit;
#[RateLimit(create: 1, capacity: 100, limitCallback: [RateLimitHandler::class, 'handle'])]
public function list(): array
{
// 每秒生成 1 个令牌,桶容量 100
}
滑动窗口 (用户级别)
// Redis ZSET sliding window
public function isRateLimited(string $key, int $maxRequests, int $windowSeconds): bool
{
$now = microtime(true);
$windowStart = $now - $windowSeconds;
$pipe = $this->redis->pipeline();
$pipe->zremrangebyscore($key, '-inf', (string) $windowStart);
$pipe->zadd($key, [(string) $now => $now]);
$pipe->zcard($key);
$pipe->expire($key, $windowSeconds);
$results = $pipe->exec();
return $results[2] > $maxRequests;
}
消息队列削峰
高并发写入:
Client → API → Redis Queue (缓冲) → Consumer → MySQL
适用场景:
- 订单创建 (削峰)
- 通知发送 (异步)
- 日志记录 (解耦)
- 数据统计 (批处理)
服务降级与熔断
// 降级策略
class OrderService
{
public function getStatistics(int $orderId): array
{
try {
return $this->doGetStatistics($orderId);
} catch (\Throwable $e) {
// Fallback: return cached/default data
return $this->getCachedStatistics($orderId) ?? self::DEFAULT_STATS;
}
}
}
// 熔断器模式
// Circuit Breaker: CLOSED → OPEN → HALF-OPEN → CLOSED
// Use hyperf/circuit-breaker component
数据库扩展策略
垂直拆分 (按业务域)
production_db → 订单、子订单、发货
permission_db → 用户、角色、权限
notification_db → 通知、消息
水平分片 (百万级后)
分片键: order_id
分片策略: order_id % shard_count
路由层: Hyperf 中间层 或 ProxySQL
注意: 跨分片查询需要聚合层
部署扩展清单
| 阶段 | QPS | 架构 |
|---|---|---|
| 起步 | < 1K | 单机 Docker Compose |
| 成长 | 1K ~ 10K | Nginx + 2~4 Hyperf + MySQL主从 + Redis Sentinel |
| 规模 | 10K ~ 100K | K8s + HPA + MySQL Cluster + Redis Cluster |
| 百万 | 100K+ | 微服务拆分 + 消息队列 + 分库分表 + CDN |
模块通信规范
与
019-modular.mdc互补,本节侧重跨服务/跨进程通信;019 侧重代码内模块边界。
通信方式选择矩阵
| 场景 | 推荐方式 | 禁止方式 |
|---|---|---|
| 同进程同步调用 | 依赖注入 + 接口 | 全局静态方法 |
| 跨进程异步 | AsyncQueue / RabbitMQ | 轮询 DB |
| 实时推送 | WebSocket + Redis Pub/Sub | HTTP 长轮询 |
| 定时任务 | Hyperf Crontab | sleep 循环 |
| 跨服务数据 | REST API / 共享 Redis | 直连对方 DB |
前端模块通信规范
组件间通信优先级(由低到高耦合):
1. Props & Emits(父子) — 首选
2. provide/inject(跨层级) — 适合主题/配置
3. Pinia Store(状态共享) — 跨模块全局状态
4. EventBus (mitt) — 非父子一次性事件(慎用)
5. URL / Query Params — 页面级状态持久化
// ✅ 推荐:通过 Pinia 跨模块共享状态
// stores/notification.ts
export const useNotificationStore = defineStore('notification', () => {
const unreadCount = ref(0)
const messages = ref<Notification[]>([])
function addNotification(msg: Notification): void {
messages.value.unshift(msg)
unreadCount.value++
}
return { unreadCount, messages, addNotification }
})
// 订单模块使用通知(无直接耦合)
// views/order/composables/useOrderActions.ts
const notificationStore = useNotificationStore()
async function createOrder(data: OrderCreateForm): Promise<void> {
const order = await OrderApi.create(data)
// 通过 Store 通知,不直接调用通知组件
notificationStore.addNotification({
type: 'success',
title: '订单创建成功',
content: `订单号 ${order.orderNo} 已提交`,
})
}
WebSocket 模块通信
// src/composables/useWebSocket.ts — 全局单例 WebSocket 管理
// 所有模块订阅自己关心的消息类型,不感知连接细节
export const wsClient = useWebSocket()
// 订单模块:只监听订单相关消息
const { on, off } = useWebSocket()
on('order.status_changed', (payload) => {
orderStore.updateOrderStatus(payload.orderId, payload.status)
})
// 通知模块:只监听通知消息
on('notification.new', (payload) => {
notificationStore.addNotification(payload)
})
性能基线
| 指标 | 目标值 | 监控方式 |
|---|---|---|
| API P99 延迟 | < 200ms | Prometheus + Grafana |
| 数据库查询 | < 50ms | 慢查询日志 |
| Redis 命令 | < 5ms | Redis INFO |
| 缓存命中率 | > 85% | 自定义指标 |
| 错误率 | < 0.1% | Sentry / 日志 |
| 可用性 | 99.9% | 健康检查 + 告警 |