CrossBridge 性能优化方案
🚨 WebSocket 中继服务器性能瓶颈分析
潜在问题
- 单点瓶颈: 所有跨域通信都通过中继服务器
- 网络延迟: 增加了一跳网络传输
- 服务器负载: 高频消息会给服务器造成压力
- 带宽消耗: 服务器需要处理大量数据转发
🎯 混合优化解决方案
方案一:智能路由 + 多层通信
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);
}
}📊 总结建议
- 首选方案: 采用 [方案二] (P2P + 中继混合架构),即
WebsocketRelay+IframeBridge。这在开发成本和性能之间取得了最佳平衡。 - 次选方案: 如果后端资源极其受限,使用 [Iframe 桥接] 方案。
- 高性能需求: 仅在确实需要传输音视频或海量数据时,才引入 [WebRTC P2P] 方案。
- 默认开启: 始终开启 [消息批处理] 和 [数据压缩],这对所有场景都有益处。