第三章:系统架构
本章详细介绍 VSDB 的双进程架构设计、分层结构和各模块职责。
3.1 整体架构
VSDB 采用双进程架构,将数据库操作隔离在独立的 Worker 进程中。
graph TD
subgraph "VSCode Extension Host (主进程)"
A["extension.ts<br/>入口与命令注册"]
B["核心管理层"]
C["UI 层"]
subgraph "核心管理层"
B1["ConnectionManager"]
B2["IpcManager"]
B3["Storage"]
B4["ScannerEngine"]
B5["HistoryManager"]
B6["BookmarkManager"]
B7["SearchEngine"]
end
subgraph "UI 层"
C1["TreeView<br/>(连接树)"]
C2["Webview Panels<br/>(React 应用)"]
end
end
subgraph "Worker Process (子进程)"
D["worker.ts<br/>Worker 入口"]
E["QueryQueue<br/>查询队列"]
subgraph "数据库驱动层"
F1["MySqlDriver"]
F2["PostgreSqlDriver"]
end
subgraph "Schema Inspector"
G1["MySqlSchema"]
G2["PgSchema"]
end
end
A --> B
B --> C
B2 -->|"IPC (child_process)"| D
D --> E
E --> F1
E --> F2
F1 --> G1
F2 --> G2
3.2 双进程架构原理
为什么选择双进程
graph TD
subgraph "单进程架构的问题"
A1["数据库操作"] --> A2["阻塞 Extension Host"]
A2 --> A3["VSCode 卡顿"]
A4["驱动异常"] --> A5["扩展崩溃"]
A5 --> A6["需要重启 VSCode"]
end
subgraph "双进程架构的优势"
B1["数据库操作"] --> B2["Worker 进程"]
B2 --> B3["Extension Host 不受影响"]
B4["Worker 崩溃"] --> B5["自动重启恢复"]
B5 --> B6["用户体验连续"]
end
| 问题 | 单进程 | 双进程 |
|---|---|---|
| 复杂查询阻塞 | 阻塞 VSCode | Worker 执行,UI 正常 |
| 驱动异常 | 扩展崩溃 | Worker 崩溃自动恢复 |
| 内存泄漏 | 影响 VSCode | Worker 可重启清理 |
| 长时间操作 | UI 无响应 | 异步 IPC 通信 |
进程通信方式
VSDB 使用 Node.js child_process.fork() 创建 Worker:
// IpcManager.ts
this.worker = fork(this.workerPath, [], {
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
});
IPC 通信特点:
- 原生支持:无需额外依赖
- JSON 序列化:消息自动序列化/反序列化
- 双向通信:主进程和 Worker 都可发送消息
3.3 分层架构
graph TB
subgraph "UI 层"
UI1["TreeView"]
UI2["Webview Panel"]
end
subgraph "管理层"
M1["ConnectionManager"]
M2["IpcManager"]
M3["ScannerEngine"]
M4["HistoryManager"]
M5["BookmarkManager"]
M6["SearchEngine"]
end
subgraph "Worker 层"
W1["QueryQueue"]
W2["Driver"]
W3["SchemaInspector"]
end
subgraph "存储层"
S1["JSON Storage"]
S2["SecretStorage"]
S3["Schema Cache"]
end
UI1 --> M1
UI1 --> M2
UI2 --> M2
M1 --> S1
M1 --> S2
M3 --> S1
M2 -->|"IPC"| W1
W1 --> W2
W2 --> W3
M6 --> S3
各层职责
| 层级 | 模块 | 职责 |
|---|---|---|
| UI 层 | TreeView | 连接树展示、节点交互 |
| Webview | SQL 编辑器、数据网格、表单 | |
| 管理层 | ConnectionManager | 连接 CRUD、范围管理 |
| IpcManager | Worker 生命周期、消息路由 | |
| ScannerEngine | 协调配置扫描 | |
| HistoryManager | 查询历史存储 | |
| BookmarkManager | 书签管理 | |
| SearchEngine | 全局搜索协调 | |
| Worker 层 | QueryQueue | 并发控制、超时管理 |
| Driver | 数据库连接、查询执行 | |
| SchemaInspector | 元信息查询 | |
| 存储层 | JSON Storage | 连接配置持久化 |
| SecretStorage | 密码加密存储 | |
| Schema Cache | 搜索缓存 |
3.4 Extension Host(主进程)
入口模块
extension.ts 是扩展入口,负责:
// 主要职责
export function activate(context: vscode.ExtensionContext) {
// 1. 初始化管理器
const storage = new Storage(context.globalState, context.secrets);
const connectionManager = new ConnectionManager(storage, projectRoot);
const ipcManager = new IpcManager({ ... });
// 2. 初始化扫描引擎
const scannerEngine = new ScannerEngine();
// 3. 初始化辅助管理器
const historyManager = new HistoryManager(context.globalState);
const bookmarkManager = new BookmarkManager(context.globalState);
const searchEngine = new SearchEngine(ipcManager, connectionManager);
// 4. 初始化 TreeView
const treeProvider = new TreeProvider(connectionManager, ipcManager, ...);
const treeView = vscode.window.createTreeView(VIEWS.CONNECTIONS, {
treeDataProvider: treeProvider,
});
// 5. 注册命令
registerCommands(context);
// 6. 自动扫描(如果有工作区)
autoScanProject(workspaceRoot);
}
命令注册
VSDB 注册两类命令:
graph TD
subgraph "全局命令"
C1["vsdb.addConnection"]
C2["vsdb.scanProject"]
C3["vsdb.newQuery"]
C4["vsdb.search"]
end
subgraph "树节点命令"
T1["vsdb.tree.connect"]
T2["vsdb.tree.disconnect"]
T3["vsdb.tree.newQuery"]
T4["vsdb.viewTableStructure"]
T5["vsdb.exportData"]
end
C1 --> F1["打开连接表单"]
C2 --> F2["扫描项目配置"]
C3 --> F3["打开 SQL 编辑器"]
C4 --> F4["搜索表/列"]
3.5 Worker Process(子进程)
Worker 入口
worker.ts 是 Worker 进程入口:
// Worker 生命周期
process.on('message', (request: WorkerRequest) => {
handleMessage(request); // 处理请求
});
process.send?.({ type: 'ready' }); // 通知主进程就绪
process.on('disconnect', () => {
shutdown(); // 父进程断开时清理
});
process.on('SIGTERM', () => {
shutdown(); // 信号终止时清理
});
请求处理流程
sequenceDiagram
participant Host as Extension Host
participant Worker as Worker Process
participant Queue as QueryQueue
participant Driver as DatabaseDriver
Host->>Worker: WorkerRequest (type=query)
Worker->>Queue: enqueue(request)
Queue->>Driver: execute(sql)
Driver-->>Queue: QueryResult
Queue-->>Worker: WorkerResponse
Worker-->>Host: WorkerResponse
查询队列
QueryQueue 实现并发控制和超时管理:
class QueryQueue {
private queue = new Map<string, PendingQuery>();
private maxConcurrency = 5;
private defaultTimeout = 30000;
enqueue(request: WorkerRequest, handler: () => Promise<WorkerResponse>) {
// 1. 检查并发限制
// 2. 设置超时定时器
// 3. 执行查询
// 4. 返回结果或超时错误
}
cancel(requestId: string) {
// 取消正在执行的查询
}
}
3.6 数据流分析
连接建立流程
sequenceDiagram
participant User as 用户
participant Tree as TreeView
participant CM as ConnectionManager
participant IPC as IpcManager
participant Worker as Worker Process
participant Driver as MySqlDriver
User->>Tree: 点击连接节点
Tree->>IPC: sendRequest(connect)
IPC->>Worker: WorkerRequest(type=connect)
Worker->>CM: 检查连接配置
Worker->>Driver: driver.connect(config)
Driver-->>Worker: 连接成功
Worker-->>IPC: WorkerResponse(type=result)
IPC-->>Tree: 更新连接状态
Tree-->>User: 显示连接图标
查询执行流程
sequenceDiagram
participant User as 用户
participant Webview as SQL Editor
participant IPC as IpcManager
participant Worker as Worker Process
participant Queue as QueryQueue
participant Driver as Driver
User->>Webview: 输入 SQL,点击执行
Webview->>IPC: postMessage(executeQuery)
IPC->>Worker: WorkerRequest(type=query)
Worker->>Queue: enqueue
Queue->>Driver: driver.query(sql)
Driver-->>Queue: QueryResult
Queue-->>Worker: WorkerResponse
Worker-->>IPC: WorkerResponse
IPC-->>Webview: WorkerResponse
Webview-->>User: 显示结果表格
流式查询流程(大数据)
sequenceDiagram
participant User as 用户
participant Webview as SQL Editor
participant IPC as IpcManager
participant Worker as Worker Process
participant Driver as Driver
User->>Webview: 执行大查询
Webview->>IPC: sendRequest(streamQuery)
IPC->>Worker: WorkerRequest(type=streamQuery)
Worker->>Driver: driver.streamQuery(sql)
loop 每 1000 行
Driver-->>Worker: chunk
Worker-->>IPC: StreamChunk
IPC-->>Webview: StreamChunk
Webview-->>User: 渲染数据块
end
Driver-->>Worker: end
Worker-->>IPC: streamEnd
IPC-->>Webview: streamEnd
Webview-->>User: 完成
3.7 错误处理架构
Worker 崩溃恢复
stateDiagram-v2
[*] --> Running
Running --> Crashed: 进程退出
Crashed --> Restarting: 重启尝试 < max
Restarting --> Running: 重启成功
Restarting --> Failed: 重试次数超限
Failed --> [*]
Running --> Shutdown: 正常关闭
Shutdown --> [*]
恢复策略:
// IpcManager.ts
worker.on('exit', (code, signal) => {
if (!isShuttingDown && restartOnCrash && restartAttempts < maxRestartAttempts) {
restartAttempts++;
const delay = Math.min(500 * Math.pow(2, restartAttempts - 1), 5000);
setTimeout(() => {
this.start(); // 重启 Worker
this.reconnectActiveConnections(); // 恢复连接
}, delay);
}
});
错误分类与处理
// Worker 错误分类
type QueryErrorClass = 'connection' | 'syntax' | 'timeout' | 'permission' | 'unknown';
function classifyQueryError(error: unknown): ClassifiedError {
const message = error instanceof Error ? error.message : String(error);
if (message.includes('ECONNREFUSED')) {
return { errorClass: 'connection', retryable: true };
}
if (message.includes('syntax error')) {
return { errorClass: 'syntax', retryable: false };
}
if (message.includes('timeout')) {
return { errorClass: 'timeout', retryable: true };
}
// ...
}
| 错误类 | 典型原因 | retryable | 用户提示 |
|---|---|---|---|
connection | 网络问题、服务未启动 | ✓ | "连接失败,请检查网络" |
syntax | SQL 语法错误 | ✗ | "SQL 语法错误" |
timeout | 查询超时 | ✓ | "查询超时,可重试" |
permission | 权限不足 | ✗ | "权限不足" |
unknown | 其他错误 | ✗ | "未知错误" |
3.8 性能考量
IPC 消息大小限制
IPC 消息通过 JSON 序列化传输,大消息会影响性能:
// 流式传输策略
const chunkSize = 1000; // 每块最多 1000 行
for await (const chunk of driver.streamQuery(sql)) {
send({
requestId,
chunkIndex,
rows: chunk.rows, // 限制在 chunkSize
});
}
内存管理
// Worker 内存监控
const memoryLimitMb = 512;
setInterval(() => {
const usage = process.memoryUsage();
const heapUsedMb = usage.heapUsed / (1024 * 1024);
if (heapUsedMb > memoryLimitMb) {
send({ type: 'error', error: { code: 'WORKER_MEMORY_EXCEEDED' } });
}
}, 10000);
心跳机制
// 防止僵尸进程
const heartbeatInterval = 15000; // 15秒发送 ping
const maxMissedHeartbeats = 2; // 2次未响应视为崩溃
setInterval(() => {
worker.send({ type: 'ping' });
missedHeartbeats++;
if (missedHeartbeats >= maxMissedHeartbeats) {
worker.kill('SIGKILL'); // 强制终止
}
}, heartbeatInterval);
3.9 小结
本章介绍了 VSDB 的系统架构:
- 双进程架构:Extension Host + Worker Process
- 分层设计:UI 层 → 管理层 → Worker 层 → 存储层
- IPC 通信:JSON 序列化,请求/响应匹配
- 错误处理:崩溃恢复,错误分类
- 性能优化:流式传输,内存监控,心跳机制
下一章将深入 IPC 通信机制的实现细节。