Skip to content

CrossBridge 性能优化方案

🚨 WebSocket 中继服务器性能瓶颈分析

潜在问题

  1. 单点瓶颈: 所有跨域通信都通过中继服务器
  2. 网络延迟: 增加了一跳网络传输
  3. 服务器负载: 高频消息会给服务器造成压力
  4. 带宽消耗: 服务器需要处理大量数据转发

🎯 混合优化解决方案

方案一:智能路由 + 多层通信

mermaid
graph TB
    subgraph "同域通信(高性能)"
        A1[页面 A1] -.SharedWorker.-> A2[页面 A2]
        B1[页面 B1] -.PostMessage.-> B2[iframe B2]
    end

    subgraph "跨域通信(按需选择)"
        A1 -.直连P2P.-> C1[页面 C1]
        A1 -.iframe桥接.-> D1[页面 D1]
        A1 -.WebSocket中继.-> E1[页面 E1]
    end

    subgraph "性能优化层"
        Cache[本地缓存]
        Batch[消息批处理]
        Compress[数据压缩]
    end

方案二:P2P + 中继混合架构

typescript
// 智能适配器选择器
class IntelligentAdapterSelector {
  private performanceMetrics: Map<string, AdapterPerformance> = new Map();

  selectOptimalAdapter(
    message: Message,
    availableAdapters: BaseAdapter[]
  ): BaseAdapter {
    // 1. 同域优先使用高性能方案
    if (this.isSameDomain(message.to)) {
      return (
        this.findAdapter('shared-worker') || this.findAdapter('post-message')
      );
    }

    // 2. 跨域根据数据量和频率选择
    if (this.isHighFrequencyData(message)) {
      // 高频数据优先使用 P2P 或 iframe 桥接
      return (
        this.findAdapter('webrtc-p2p') || this.findAdapter('iframe-bridge')
      );
    }

    // 3. 低频重要数据使用可靠的 WebSocket 中继
    return this.findAdapter('websocket-relay');
  }

  private isHighFrequencyData(message: Message): boolean {
    const recentMessages = this.getRecentMessages(message.event, 5000); // 5秒内
    return recentMessages.length > 10; // 5秒内超过10条消息认为是高频
  }
}

方案三:WebRTC P2P 直连(最优性能)

typescript
// WebRTC P2P 适配器
class WebRTCP2PAdapter extends BaseAdapter {
  private peerConnections: Map<string, RTCPeerConnection> = new Map();
  private dataChannels: Map<string, RTCDataChannel> = new Map();
  private signalingServer: WebSocket | null = null;

  async connect(): Promise<void> {
    // 1. 连接信令服务器(仅用于建立连接)
    await this.connectSignalingServer();

    // 2. 监听其他页面的连接请求
    this.listenForPeerRequests();
  }

  async send(message: Message): Promise<boolean> {
    const targetPageId = message.to as string;
    let dataChannel = this.dataChannels.get(targetPageId);

    if (!dataChannel || dataChannel.readyState !== 'open') {
      // 建立 P2P 连接
      dataChannel = await this.establishP2PConnection(targetPageId);
    }

    if (dataChannel && dataChannel.readyState === 'open') {
      // 直接 P2P 发送,无需经过服务器
      dataChannel.send(JSON.stringify(message));
      return true;
    }

    // P2P 失败时回退到中继服务器
    return this.fallbackToRelay(message);
  }

  private async establishP2PConnection(
    targetPageId: string
  ): Promise<RTCDataChannel | null> {
    const peerConnection = new RTCPeerConnection({
      iceServers: [
        { urls: 'stun:stun.l.google.com:19302' },
        {
          urls: 'turn:turn.e-tudou.com:3478',
          username: 'user',
          credential: 'pass',
        },
      ],
    });

    // 创建数据通道
    const dataChannel = peerConnection.createDataChannel('cross-bridge', {
      ordered: true,
      maxRetransmits: 3,
    });

    // ICE 候选交换通过信令服务器
    peerConnection.onicecandidate = (event) => {
      if (event.candidate) {
        this.sendSignalingMessage(targetPageId, {
          type: 'ice-candidate',
          candidate: event.candidate,
        });
      }
    };

    // 创建 offer
    const offer = await peerConnection.createOffer();
    await peerConnection.setLocalDescription(offer);

    // 通过信令服务器发送 offer
    this.sendSignalingMessage(targetPageId, {
      type: 'offer',
      offer: offer,
    });

    this.peerConnections.set(targetPageId, peerConnection);

    return new Promise((resolve) => {
      dataChannel.onopen = () => {
        this.dataChannels.set(targetPageId, dataChannel);
        resolve(dataChannel);
      };

      // 连接超时回退
      setTimeout(() => resolve(null), 5000);
    });
  }
}

方案四:消息批处理和压缩优化

typescript
// 性能优化的消息管理器
class OptimizedMessageManager {
  private batchQueue: Message[] = []
  private batchTimer: number | null = null
  private compressionEnabled = true

  async sendOptimized(message: Message, adapter: BaseAdapter): Promise<boolean> {
    // 1. 高优先级消息立即发送
    if (message.priority === 0) {
      return this.sendImmediately(message, adapter)
    }

    // 2. 普通消息加入批处理队列
    this.batchQueue.push(message)

    // 3. 启动批处理定时器
    if (!this.batchTimer) {
      this.batchTimer = window.setTimeout(() => {
        this.flushBatchQueue(adapter)
      }, 50) // 50ms 批处理间隔
    }

    // 4. 队列满时立即发送
    if (this.batchQueue.length >= 10) {
      this.flushBatchQueue(adapter)
    }

    return true
  }

  private async flushBatchQueue(adapter: BaseAdapter): Promise<void> {
    if (this.batchQueue.length === 0) return

    const messages = [...this.batchQueue];
    this.batchQueue = [];

    if (this.batchTimer) {
      clearTimeout(this.batchTimer);
      this.batchTimer = null;
    }

    // 压缩批量数据
    let payload: any = messages;
    let isCompressed = false;

    if (this.compressionEnabled && messages.length > 5) {
      payload = await this.compressData(messages);
      isCompressed = true;
    }

    // 构建批量消息
    const batchMessage: Message = {
      id: generateId(),
      type: 'batch',
      event: 'batch-data',
      data: payload,
      from: this.config.pageId,
      timestamp: Date.now(),
      meta: {
        isCompressed,
        count: messages.length
      }
    };

    return adapter.send(batchMessage);
  }
}

📊 总结建议

  1. 首选方案: 采用 [方案二] (P2P + 中继混合架构),即 WebsocketRelay + IframeBridge。这在开发成本和性能之间取得了最佳平衡。
  2. 次选方案: 如果后端资源极其受限,使用 [Iframe 桥接] 方案。
  3. 高性能需求: 仅在确实需要传输音视频或海量数据时,才引入 [WebRTC P2P] 方案。
  4. 默认开启: 始终开启 [消息批处理] 和 [数据压缩],这对所有场景都有益处。

Released under the MIT License.