面试题答案
一键面试代码层面
- 模块设计优化
- 拆分与合并模块:检查模块的职责是否单一,若过于复杂应进一步拆分,减少模块间的耦合度。例如,将业务逻辑复杂的模块拆分成多个专注于单一功能的子模块。同时,对于一些小且关联性强的模块,在合适的情况下进行合并,减少模块加载开销。
- 优化模块导出:尽量使用
exports
或module.exports
导出单个函数或对象,避免导出过多不必要的属性和方法,减少内存占用。
- 异步处理优化
- 使用异步函数与Promise:确保所有I/O操作(如数据库查询、文件读取等)都使用异步方式。例如,将传统的回调风格的数据库查询函数改写为返回Promise的函数,然后使用
async/await
语法来处理,使代码更易读且避免回调地狱。 - 并发控制:使用
Promise.all
等方法控制并发请求数量。如果有多个异步任务需要同时执行,但过多并发可能导致资源耗尽,可以通过限制并发数量来优化性能。例如,假设有100个数据库查询任务,每次只并发执行10个,使用Promise.allSettled
来收集所有结果。 - 事件驱动架构:对于实时性要求较高的场景,采用事件驱动架构。例如,使用
EventEmitter
来处理WebSocket连接事件,当有新连接时,触发相应的处理函数,这样可以避免阻塞主线程。
- 使用异步函数与Promise:确保所有I/O操作(如数据库查询、文件读取等)都使用异步方式。例如,将传统的回调风格的数据库查询函数改写为返回Promise的函数,然后使用
服务器配置层面
- 负载均衡
- 硬件负载均衡器:在服务器前端部署硬件负载均衡设备,如F5 Big - IP等。这些设备可以根据预设的算法(如轮询、加权轮询、最少连接数等)将客户端请求均匀分配到多个后端服务器上。配置过程需要在硬件设备的管理界面中设置后端服务器的IP地址、端口等信息,并选择合适的负载均衡算法。
- 软件负载均衡器:使用Nginx或HAProxy等软件负载均衡器。以Nginx为例,在其配置文件(通常是
nginx.conf
或相关的虚拟主机配置文件)中,通过upstream
指令定义后端服务器集群,例如:
upstream api_servers {
server 192.168.1.100:3000;
server 192.168.1.101:3000;
}
server {
listen 80;
location / {
proxy_pass http://api_servers;
}
}
- 缓存
- 内存缓存:使用Redis等内存缓存工具。在Node.js应用中,可以使用
ioredis
或redis - client
等库连接Redis。对于频繁读取且不经常变化的数据,如API的某些配置信息或热门数据,可以在数据首次读取时缓存到Redis中。后续请求时,先从Redis中获取数据,如果存在则直接返回,不存在再查询数据库并将结果缓存到Redis。例如:
- 内存缓存:使用Redis等内存缓存工具。在Node.js应用中,可以使用
const Redis = require('ioredis');
const redis = new Redis();
async function getApiData() {
let data = await redis.get('api_data_key');
if (!data) {
// 从数据库查询数据
data = await queryDatabase();
await redis.set('api_data_key', data);
}
return data;
}
- **HTTP缓存**:在服务器端设置合适的HTTP缓存头,如 `Cache - Control` 和 `ETag`。对于静态资源(如图片、CSS、JavaScript文件等),可以设置较长的缓存时间。例如,在Node.js的Express应用中:
const express = require('express');
const app = express();
app.use('/static', express.static('public', {
maxAge: 31536000 // 1年
}));
对于动态API响应,可以根据业务逻辑设置合适的 ETag
,通过比较客户端请求头中的 If - None - Match
与服务器生成的 ETag
来判断数据是否有变化,若未变化则返回304状态码,减少数据传输。