Skip to content

4.6 系统架构

一句话总结:架构决定系统的上限——5 层架构,Factory 模式,链上链下分工。

📊 学习进度

  • 状态:⬜ 未开始
  • 预计时长:3-4 小时
  • 已完成:0/3 个模块
  • 在整体流程中的位置:预测市场实战·第 3 阶段

📍 本章定位

  • 服务方案:方案 3(核心 90%)
  • 学习方式:⭐ 必学
  • 在流程中的作用:确定技术选型和系统架构
  • 核心知识点:技术选型、5 层架构设计、链上链下分工
  • 预计时长:3-4 小时
  • 完成后能做什么:能输出完整的系统架构文档

人机分工

环节谁做重要度说明
架构设计🧑 人⭐⭐⭐⭐⭐决定 5 层架构
技术选型🧑 人 + 🤖 AI⭐⭐⭐⭐人决策,AI 对比
文档输出🤖 AI⭐⭐⭐AI 生成文档

1. 技术选型

1.1 推荐技术栈(2025)

层级推荐技术备选选择理由
Base / ArbitrumOptimism低 Gas、高吞吐、生态成熟
合约Solidity + HardhatFoundry插件丰富、社区大
后端Node.js + TypeScriptGo快速开发、生态丰富
前端Next.js + wagmi + viemReactDApp 标准、类型安全
数据库PostgreSQLMongoDB事务性、可靠性
链上数据The Graph自建索引去中心化、实时
AIClaude API + LangGraphOpenAI长上下文、安全
做市自定义策略引擎无标准方案

1.2 技术栈选型对比

1.3 各层级技术对比详情

区块链层对比

Gas 费TPS生态EVM 兼容推荐度
Base$0.01-0.052000+Coinbase 支持⭐⭐⭐⭐⭐
Arbitrum$0.02-0.104000+最大 L2⭐⭐⭐⭐⭐
Optimism$0.03-0.152000+OP Stack 生态⭐⭐⭐⭐
Polygon$0.01-0.057000+Polymarket 选择⭐⭐⭐⭐
Ethereum$1-5015最安全⭐⭐

数据来源:L2Beat,2025 年 Q1 数据

开发框架对比

框架语言测试部署学习曲线社区
HardhatJavaScript内置插件最大
FoundrySolidityforge testforge增长快
TruffleJavaScript内置内置老牌

2. 5 层架构设计

2.1 架构图

2.2 各层职责详解

层级职责核心组件数据流
Layer 1: 事件池事件供给AI-Gateway, 规则引擎信息 → 事件
Layer 2: 业务中台业务逻辑撮合引擎, API事件 → 交易
Layer 3: 链上合约资产确权Factory 模式交易 → 链上
Layer 4: 预言机结果验证Oracle Nodes结果 → 验证
Layer 5: 做市流动性做市策略流动性 → 市场

2.3 架构设计原则

原则说明实现方式
链上链下分工链上做确权,链下做业务事件推送+撮合+统计
Factory 模式批量生产市场5 个 Factory 依次产出 Pod
多租户隔离DApp 独立空间每个 DApp 独立 Pod 集合
模块化组件可替换每个 Pod 独立合约
去中心化验证结果可信zk-verifier + Staking

3. 链上链下分工

3.1 分工矩阵

层级职责技术为什么放在这层
链上资产确权Solidity不可篡改、可验证
链上交易记录Solidity透明、可审计
链上结算分配Solidity公正、自动执行
链上预言机验证Solidity去中心化信任
链下订单撮合Node.js高性能、低延迟
链下数据统计Node.js灵活、高效
链下事件生成AI智能、持续
链下做市策略Node.js复杂计算、实时调整

3.2 关键交互点

3.3 数据一致性保障

场景问题解决方案
链下撮合结果可能与链上不一致定期对账+异常告警
事件状态同步链上状态变更监听合约事件
预言机结果可能延迟超时机制+重试
做市策略可能过期实时数据刷新

4. API 接口设计

4.1 核心 API 列表

接口方法路径说明
获取事件列表GET/api/events分页、筛选、排序
获取事件详情GET/api/events/:id含交易数据
创建事件POST/api/events需要认证
下单POST/api/orders市价/限价
取消订单DELETE/api/orders/:id需要签名
获取订单簿GET/api/orderbook/:eventId实时深度
获取交易记录GET/api/trades/:eventId历史成交
获取用户仓位GET/api/positions当前持仓
获取价格历史GET/api/prices/:eventIdK 线数据

4.2 API 响应格式

typescript
// 统一响应格式
interface ApiResponse<T> {
  code: number;         // 0=成功, 非0=错误
  message: string;      // 描述
  data: T;              // 数据
  timestamp: number;    // 时间戳
}

// 事件列表响应
interface EventListResponse {
  events: Event[];
  total: number;
  page: number;
  pageSize: number;
}

// 订单簿响应
interface OrderBookResponse {
  eventId: string;
  bids: OrderLevel[];   // 买单,价格从高到低
  asks: OrderLevel[];   // 卖单,价格从低到高
  lastPrice: number;
  timestamp: number;
}

interface OrderLevel {
  price: number;        // 价格 (0.01-0.99)
  quantity: number;     // 数量
  orderCount: number;   // 订单数
}

4.3 API 认证与限流

机制说明配置
认证JWT + 钱包签名24h 过期
限流每用户 100 req/minRedis 计数
签名交易需要 EIP-712 签名防重放

5. 数据库设计

5.1 核心表结构

sql
-- 事件表
CREATE TABLE events (
  id UUID PRIMARY KEY,
  title VARCHAR(256) NOT NULL,
  description TEXT,
  category VARCHAR(32) NOT NULL,
  resolution_source VARCHAR(256),
  end_time TIMESTAMP NOT NULL,
  status VARCHAR(16) DEFAULT 'active',  -- active | resolved | cancelled
  yes_price DECIMAL(5,4) DEFAULT 0.5000,
  no_price DECIMAL(5,4) DEFAULT 0.5000,
  total_volume DECIMAL(18,2) DEFAULT 0,
  chain_event_id VARCHAR(66),           -- 链上事件 ID
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

-- 订单表
CREATE TABLE orders (
  id UUID PRIMARY KEY,
  event_id UUID REFERENCES events(id),
  user_address VARCHAR(42) NOT NULL,
  side VARCHAR(3) NOT NULL,             -- YES | NO
  order_type VARCHAR(8) NOT NULL,       -- MARKET | LIMIT
  price DECIMAL(5,4),
  amount DECIMAL(18,2) NOT NULL,
  filled_amount DECIMAL(18,2) DEFAULT 0,
  status VARCHAR(16) DEFAULT 'pending', -- pending | filled | partial | cancelled
  created_at TIMESTAMP DEFAULT NOW()
);

-- 成交记录表
CREATE TABLE trades (
  id UUID PRIMARY KEY,
  event_id UUID REFERENCES events(id),
  buyer_address VARCHAR(42) NOT NULL,
  seller_address VARCHAR(42) NOT NULL,
  side VARCHAR(3) NOT NULL,
  price DECIMAL(5,4) NOT NULL,
  amount DECIMAL(18,2) NOT NULL,
  fee DECIMAL(18,2) NOT NULL,
  tx_hash VARCHAR(66),
  created_at TIMESTAMP DEFAULT NOW()
);

-- 索引
CREATE INDEX idx_events_category ON events(category);
CREATE INDEX idx_events_status ON events(status);
CREATE INDEX idx_events_end_time ON events(end_time);
CREATE INDEX idx_orders_event ON orders(event_id, status);
CREATE INDEX idx_orders_user ON orders(user_address);
CREATE INDEX idx_trades_event ON trades(event_id, created_at);

5.2 数据流图


6. Gas 优化策略

6.1 优化方法

策略说明节省比例实现复杂度
L2 部署Base/Arbitrum90%+
批处理批量处理订单50%
状态通道链下交易,链上结算80%
事件聚合事件批量创建40%
存储优化使用 mapping 替代 array30%

6.2 批处理实现示例

solidity
// 批量提交成交结果,节省 Gas
function batchSettle(
    uint256 eventId,
    address[] calldata buyers,
    address[] calldata sellers,
    uint256[] calldata amounts,
    uint256[] calldata prices
) external onlyOperator {
    require(buyers.length == sellers.length, "Length mismatch");
    require(buyers.length == amounts.length, "Length mismatch");
    
    for (uint256 i = 0; i < buyers.length; i++) {
        _settleTrade(eventId, buyers[i], sellers[i], amounts[i], prices[i]);
    }
}

7. 部署架构

7.1 生产环境部署

7.2 OPC 轻量部署方案

作为 OPC,不需要复杂的生产环境。推荐轻量方案:

组件推荐方案成本
前端Vercel / Cloudflare Pages免费
APIRailway / Fly.io$5-20/月
数据库Supabase / Neon免费层
RedisUpstash免费层
监控Grafana Cloud免费层
域名Cloudflare$10/年

8. 架构演进路线

8.1 MVP 到生产级的演进

预测市场架构不是一蹴而就的,需要分阶段演进:

阶段架构数据库部署用户规模月成本
MVP单体PostgreSQL 单实例Vercel + Railway<1k DAU$50
成长期模块化PostgreSQL 主从Docker + K8s1k-10k DAU$500
规模化微服务分库分表 + ClickHouse多区域 K8s10k+ DAU$5,000

8.2 性能瓶颈与优化

瓶颈症状解决方案优先级
数据库查询慢API 响应 >500ms索引优化 + Redis 缓存P0
撮合延迟高订单处理 >100ms内存撮合 + 批处理P0
链上交互慢确认时间 >30sL2 部署 + 批量提交P1
WebSocket 吞吐低推送延迟 >1s连接池 + 消息压缩P1
前端加载慢首屏 >3sCDN + 代码分割P2

性能优化代码示例

typescript
// Redis 缓存层
class CacheLayer {
  private redis: Redis;
  private defaultTTL = 60; // 60 秒

  async get<T>(key: string, fetchFn: () => Promise<T>, ttl?: number): Promise<T> {
    // 1. 尝试从缓存获取
    const cached = await this.redis.get(key);
    if (cached) {
      return JSON.parse(cached);
    }
    
    // 2. 缓存未命中,从数据源获取
    const data = await fetchFn();
    
    // 3. 写入缓存
    await this.redis.setex(key, ttl || this.defaultTTL, JSON.stringify(data));
    
    return data;
  }

  // 批量获取,减少网络往返
  async mget<T>(keys: string[]): Promise<(T | null)[]> {
    const results = await this.redis.mget(...keys);
    return results.map(r => r ? JSON.parse(r) : null);
  }
}

8.3 可观测性架构

支柱工具用途采样率
日志Loki + Promtail错误排查100%
指标Prometheus性能监控15s 间隔
追踪Jaeger链路分析10% 采样

9. 常见问题

问题原因解决方案
架构过重过度设计先做 MVP,再迭代
技术选型错误没有调研先做技术调研
扩展性差没有预留Factory 模式设计
Gas 太高链上操作过多优化链下处理
数据不一致链上链下同步问题定期对账+事件监听
API 延迟高数据库查询慢索引优化+缓存

9. 下一步

完成架构设计后,进入 阶段 4:智能合约

8.4 微服务拆分策略

当系统达到一定规模后,需要从单体架构拆分为微服务。以下是推荐的拆分顺序和策略:

拆分顺序服务拆分理由依赖复杂度
1撮合引擎性能瓶颈,需要独立扩展
2做市服务策略独立,需要快速迭代撮合引擎
3事件服务AI 生成逻辑独立
4用户服务认证+权限独立
5数据服务分析逻辑独立PostgreSQL

服务间通信设计

typescript
// 服务间通信接口
interface ServiceBus {
  // 发布事件
  publish(topic: string, message: any): Promise<void>;
  
  // 订阅事件
  subscribe(topic: string, handler: (message: any) => Promise<void>): void;
  
  // 请求-响应模式
  request<T>(service: string, method: string, params: any): Promise<T>;
}

// 使用示例
const bus = new ServiceBus();

// 撮合引擎发布成交事件
bus.publish('trade.matched', {
  eventId: 'xxx',
  buyerId: '0x...',
  sellerId: '0x...',
  price: 0.65,
  quantity: 100
});

// 做市服务订阅成交事件,更新库存
bus.subscribe('trade.matched', async (trade) => {
  await marketMaker.updatePosition(trade);
});

// 数据服务订阅成交事件,记录分析
bus.subscribe('trade.matched', async (trade) => {
  await analytics.recordTrade(trade);
});

8.5 数据库读写分离实现

当单库成为瓶颈时,读写分离是最简单的优化方案:

typescript
// 数据库读写分离层
class DatabaseRouter {
  private writePool: Pool;  // 主库连接池
  private readPool: Pool;   // 从库连接池
  
  constructor(writeUrl: string, readUrl: string) {
    this.writePool = new Pool({ connectionString: writeUrl });
    this.readPool = new Pool({ connectionString: readUrl, max: 20 });
  }
  
  // 写操作路由到主库
  async write<T>(query: string, params?: any[]): Promise<T> {
    return this.writePool.query(query, params);
  }
  
  // 读操作路由到从库
  async read<T>(query: string, params?: any[]): Promise<T> {
    return this.readPool.query(query, params);
  }
  
  // 强制读主库(写后读场景)
  async readFromMaster<T>(query: string, params?: any[]): Promise<T> {
    return this.writePool.query(query, params);
  }
}
场景路由策略原因
创建订单主库写操作
查询订单簿从库读操作,可容忍延迟
下单后查询主库写后读一致性
用户列表从库读操作
结算操作主库写操作,需要强一致性

8.6 API 网关设计

预测市场需要一个统一的 API 网关来处理认证、限流、路由等横切关注点:

typescript
// API 网关核心配置
interface GatewayConfig {
  rateLimit: {
    windowMs: number;      // 时间窗口(毫秒)
    maxRequests: number;    // 最大请求数
  };
  auth: {
    jwtSecret: string;
    excludePaths: string[]; // 不需要认证的路径
  };
  cors: {
    origins: string[];
    credentials: boolean;
  };
}

// 限流中间件示例
class RateLimiter {
  private requests: Map<string, number[]> = new Map();

  check(clientId: string, limit: number, windowMs: number): boolean {
    const now = Date.now();
    const timestamps = this.requests.get(clientId) || [];
    const validTimestamps = timestamps.filter(t => now - t < windowMs);

    if (validTimestamps.length >= limit) {
      return false; // 超过限流
    }

    validTimestamps.push(now);
    this.requests.set(clientId, validTimestamps);
    return true;
  }
}

API 网关最佳实践

实践说明优先级
统一认证JWT + 钱包签名P0
限流保护每用户 100 req/minP0
请求日志记录所有请求P1
错误处理统一错误格式P1
版本管理/api/v1/ 前缀P2

8.7 WebSocket 实时推送架构

预测市场需要亚秒级的数据推送。以下是 WebSocket 推送架构设计:

typescript
// WebSocket 连接管理器
class WebSocketManager {
  private connections: Map<string, WebSocket> = new Map();
  private subscriptions: Map<string, Set<string>> = new Map();
  
  /**
   * 订阅事件更新
   */
  subscribe(clientId: string, eventId: string): void {
    const key = `event:${eventId}`;
    
    if (!this.subscriptions.has(key)) {
      this.subscriptions.set(key, new Set());
    }
    this.subscriptions.get(key)!.add(clientId);
  }
  
  /**
   * 推送订单簿更新
   */
  broadcastOrderBook(eventId: string, snapshot: OrderBookSnapshot): void {
    const key = `event:${eventId}`;
    const clients = this.subscriptions.get(key);
    
    if (!clients) return;
    
    const message = JSON.stringify({
      type: 'orderbook',
      eventId,
      data: snapshot,
      timestamp: Date.now()
    });
    
    for (const clientId of clients) {
      const ws = this.connections.get(clientId);
      if (ws && ws.readyState === WebSocket.OPEN) {
        ws.send(message);
      }
    }
  }
}

WebSocket 最佳实践

实践说明优先级
心跳检测每 30 秒 ping/pongP0
断线重连自动重连 + 状态恢复P0
消息压缩gzip 压缩减少带宽P1
订阅管理精细化订阅避免浪费P1
背压处理消息队列缓冲P2

参考与延伸

[11] Socket.IO Documentation(2025)— WebSocket 实时通信框架

[12] BullMQ(2025)— Redis 消息队列

[1] L2Beat(2025)— L2 数据对比

[2] Hardhat Documentation(2025)— 合约开发框架

[3] The Graph(2025)— 链上数据索引

[4] Vercel(2025)— 前端部署平台

[5] Supabase(2025)— 开源数据库服务

[6] OpenTelemetry(2025)— 可观测性框架

[7] Designing Data-Intensive Applications(2017)— Martin Kleppmann,分布式系统设计经典

[8] Microservices Patterns(2018)— Chris Richardson,微服务架构模式

[9] Base Network Documentation(2025)— Base L2 官方文档

[10] Redis Documentation(2025)— Redis 缓存最佳实践

OPC 超级个体实战指南