Deno 1.40+版本WebWorker执行MySQL查询性能骤降问题排查
问题描述
我正在开发一个需并行执行大量MySQL查询的Web应用,为提升速度与用户体验,采用WebWorker处理查询:主Deno线程将SQL发送至WebWorker,执行后返回结果。在Deno 1.39.4版本前,应用性能极佳,部分查询耗时从数秒降至0.xx秒。但升级至Deno 1.40+(已测试至1.46.x全版本)后,查询速度变得极慢,且在另一台电脑测试也出现相同情况。
主线程代码
connect(): Promise<this> { return new Promise(resolve => { this.worker = new Worker(import.meta.resolve("./MySQLWorker.ts"), { type: "module" }); this.worker.addEventListener("message", e => resolve(this), { once: true }); this.worker.postMessage({ msg: "connect", data: this.settings }); }); } query(sql:string, values?:any[]):Promise<any>{ return new Promise(resolve => { const requestId = crypto.randomUUID(); const listener = (e:any) => { const message = e.data; if (message.requestId != requestId) return; this.worker?.removeEventListener("message", listener); resolve(message.data); } this.worker?.addEventListener("message", listener); this.worker?.postMessage({ requestId, msg: "query", data: { sql, values }}) }); }
WebWorker代码
import { Client } from "https://deno.land/x/mysql@v2.12.1/mod.ts"; const client = new Client(); let iid = 0; addEventListener("message", async e => { const message = e.data; switch(message.msg){ case "connect": { await client.connect(message.data); postMessage("connected"); iid = setInterval(() => query("SELECT id FROM users WHERE id = 0"), 60000); // keep connection alive break; } case "disconnect": { clearInterval(iid); client.close(); break; } case "query": { const requestId = message.requestId; setTimeout(async () => { /* Sometimes in production / test under customer infrastructure * the connection is forcibly closed by the remote host. (os error 10054) * That causes the application to crash. So we try to catch this error * and exceute the query again for a maxAttempts number of times before failing * but keeping the application alive anyways */ const sql = message.data.sql; const values = message.data.values; let maxAttempts = 5; let data = undefined; while (data == undefined && maxAttempts-- > 0){ data = await query(sql, values); if (data == undefined && maxAttempts > 0) { console.log("DB Connection problem, trying again in 500ms"); await pause(500); } } data = data || []; postMessage({ requestId, data }); }, 1) break; } } }); function pause(millis:number):Promise<void>{ return new Promise(resolve => setTimeout(resolve, millis)); } // deno-lint-ignore no-explicit-any async function query(sql: string, values?:any):Promise<any>{ try { return await client.query(sql, values); } catch (err){ return err.code == "ECONNRESET" ? undefined : [] } }
可能的原因分析
- Worker消息传递机制变更:Deno 1.40+对Worker的结构化克隆算法或消息通道实现做了调整,导致主线程与Worker间的消息序列化/反序列化开销大幅增加。你的架构依赖频繁的
postMessage传递SQL和结果,序列化逻辑变慢会直接拖慢查询响应速度。 - MySQL客户端库兼容性问题:你使用的
mysql@v2.12.1未针对Deno 1.40+的新API或运行时变化适配。比如新版本对网络IO调度逻辑做了调整,旧版客户端的连接池、查询执行逻辑无法高效利用新调度机制,引发查询阻塞或延迟升高。 - 异步任务调度瓶颈:Worker处理
query消息时用了setTimeout(async () => {}, 1),Deno旧版本中这只是微任务调度,但新版本事件循环优先级调整后,1ms延迟被放大,大量并行查询下任务排队等待时间累积,整体响应变慢。 - 单Worker串行处理瓶颈:当前实现是单Worker串行处理所有查询,每个查询的重试逻辑(最多5次、每次间隔500ms)会阻塞后续查询执行。旧版本事件循环调度更高效时问题不明显,新版本调度逻辑变化后,串行处理的瓶颈被放大。
- 线程模型变化:Deno 1.40+对Worker的线程管理做了调整,比如线程启动开销增加、线程间上下文切换成本变高,Worker与主线程的通信链路效率下降,影响整体性能。
内容的提问来源于stack exchange,提问作者lviggiani
相关产品推荐
相关产品推荐

