NodeJS全栈开发面试题讲解——P9性能优化(Node.js 高级)
✅ 9.1 Node.js 的性能瓶颈一般出在哪?如何排查?
Node.js 单线程 + 异步模型,瓶颈常出现在:
-
阻塞操作(如:同步 I/O、CPU 密集型计算)
-
数据库慢查询 / 索引失效
-
外部接口慢响应
-
大量并发请求导致内存泄漏、事件堆积
🔍 排查工具:
工具/命令 | 用途 |
---|---|
Chrome DevTools | 分析 V8 的 CPU/内存使用 |
clinic / 0x | 分析 event loop 阻塞点 |
pm2 monit | 监控 Node 应用性能(内存/CPU) |
APM 工具(如SkyWalking) | 服务调用链追踪 |
✅ 9.2 如何避免主线程阻塞?哪些操作容易阻塞线程?
Node.js 的主线程负责处理事件循环,一旦被阻塞,所有请求都会卡住。
🚫 易阻塞的操作:
-
文件同步 I/O(如
fs.readFileSync
) -
压缩/加密计算
-
图片处理(如 sharp)
-
JSON 大对象解析
-
无限循环 / 大型 for 循环
✅ 避免方案:
-
异步处理(如
fs.promises
) -
使用
worker_threads
或子进程处理 CPU 密集型任务 -
使用消息队列进行任务拆分
-
限流、分批、延迟处理(如 setImmediate)
✅ 9.3 说说你对 Stream 的理解,什么时候用它来提升性能?
Stream 是 Node.js 的核心模块,适用于处理大文件或连续数据流,可极大降低内存占用。
🧠 Stream 四种类型:
-
Readable(可读流)→ 如
fs.createReadStream()
-
Writable(可写流)→ 如
fs.createWriteStream()
-
Duplex(双工流)
-
Transform(转换流)
📌 用法场景:
-
文件上传/下载
-
视频转码
-
日志写入
-
大 JSON 文件处理
fs.createReadStream('input.txt').pipe(transform).pipe(fs.createWriteStream('output.txt'));
✅ 9.4 如何用 cluster 或 worker_threads 实现多核并发?
Node.js 是单线程,但服务器有多核,我们可以利用 cluster 或 worker_threads 实现并发处理。
🔧 cluster 模块(常用于 HTTP 服务多进程)
if (cluster.isMaster) {for (let i = 0; i < os.cpus().length; i++) cluster.fork();
} else {app.listen(3000);
}
缺点:内存独立、无法共享数据
🔧 worker_threads(适合 CPU 密集型计算)
new Worker('./heavy-task.js', { workerData: { n: 100000 } });
适合拆分密码加密、图像处理、复杂循环等任务
✅ 9.5 如何对接口进行性能监控和报警?用过什么工具?
✅ 方法:
-
接口响应时间统计(可打 log / 中间件埋点)
-
异常监控(如 5xx 报错、耗时超过阈值)
-
服务健康监控(/healthz)
-
报警机制(钉钉机器人/飞书 webhook)
🧰 工具:
类型 | 工具名 |
---|---|
日志监控 | Winston、Pino + ELK |
性能/APM | SkyWalking、Jaeger、Zipkin |
监控平台 | Prometheus + Grafana |
告警集成 | Sentry / OpenTelemetry |
✅ 9.6 如何做数据库性能优化?举几个具体手段。
✅ 优化点:
-
建索引
-
为
WHERE
,JOIN
,ORDER BY
常用字段建索引 -
覆盖索引,避免回表
-
-
慢查询优化
-
分析执行计划
EXPLAIN
-
拆分大查询(LIMIT 分页 + 子查询)
-
-
缓存热点数据
-
查询 Redis 缓存,命中即返回
-
-
字段优化
-
避免 SELECT *,控制字段数量
-
精简 JSON 类型字段
-
✅ 9.7 静态资源 / CDN 如何优化访问性能?
✅ 优化手段:
-
静态资源部署到 CDN 节点(如:Cloudflare、阿里 CDN)
-
利用 HTTP 缓存:
-
Cache-Control: max-age
-
ETag
/Last-Modified
-
-
图片压缩(WebP)、字体子集化
-
按需加载 + 懒加载
✅ 9.8 如何实现缓存机制?本地缓存 vs Redis 缓存?
类型 | 优点 | 缺点 |
---|---|---|
本地缓存(Map/LRU) | 快速、0延迟 | 多进程不共享、易失效 |
Redis 缓存 | 跨服务共享、高容量 | 需要维护 Redis 服务、网络延迟 |
🧩 典型使用场景:
-
本地缓存:接口幂等性缓存(短时)、配置缓存
-
Redis 缓存:用户数据缓存、热门文章、排行榜等
const val = await redis.get(`post:${id}`);
if (val) return JSON.parse(val);
✅ 9.9 如何处理高并发下的“缓存击穿 / 雪崩 / 穿透”?
类型 | 说明 | 解决方案 |
---|---|---|
缓存穿透 | 请求的 key 在缓存和数据库都不存在(如 user:-1) | 设置空值缓存 / 使用布隆过滤器 |
缓存击穿 | 某个热点 key 突然过期,瞬间大量请求打到 DB | 加锁(互斥锁)+ 预加载 |
缓存雪崩 | 大量缓存同时过期 | 随机过期时间 / 分批加载 / 限流 |
✅ 9.10 前后端性能联调你做过哪些?前端也会影响响应时间吗?
是的,前端性能直接影响首屏加载时间、交互速度等用户体验。
✅ 联调优化经验:
-
用 Chrome DevTools + Network 面板分析接口时间
-
后端压缩响应(gzip)
-
减少接口数量(合并请求)
-
异步加载不影响首屏的数据
-
数据分页 / 虚拟滚动
✅ 前端常见性能问题:
-
不必要的 re-render(React)
-
Vue 的 computed 缓存未用好
-
图表 / 表格渲染数据量过大
-
图片未压缩、未懒加载
✅ 总结一图
编号 | 关键点 | 涉及知识 |
---|---|---|
9.1 | 性能瓶颈排查 | Chrome DevTools / APM |
9.2 | 主线程阻塞来源 | 文件同步、CPU 任务、JSON大对象等 |
9.3 | Stream 用法 | 文件处理、内存控制 |
9.4 | 多核并发方案 | cluster + worker_threads |
9.5 | 接口监控与报警 | Prometheus、Grafana、Sentry |
9.6 | 数据库优化 | 索引、分页、缓存 |
9.7 | 静态资源优化 | CDN、缓存、压缩 |
9.8 | 缓存策略 | 本地缓存 vs Redis |
9.9 | 缓存三难问题 | 击穿、雪崩、穿透 |
9.10 | 前后端性能联调 | 接口压缩、延迟分析、懒加载等 |