面试题答案
一键面试- 使用文件锁机制:
- 在Node.js中,可以利用
fs
模块的fs.open
方法并传入'wx'
(或'w+x'
)标志来创建文件并尝试获取排他锁。如果文件已存在,fs.open
调用会失败,这样就可以避免多个节点同时写入同一文件。 - 例如:
- 在Node.js中,可以利用
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, 'example.txt');
fs.open(filePath, 'wx', (err, fd) => {
if (err) {
if (err.code === 'EEXIST') {
console.log('文件已被其他节点锁定,等待重试...');
// 可以在这里实现重试逻辑
} else {
console.error('打开文件失败:', err);
}
} else {
try {
const data = '要写入的数据';
fs.writeSync(fd, data);
console.log('数据写入成功');
} catch (writeErr) {
console.error('写入数据失败:', writeErr);
} finally {
fs.closeSync(fd);
}
}
});
- 分布式锁服务:
- 可以借助像Redis这样的分布式缓存服务来实现分布式锁。
- 步骤如下:
- 使用Redis的
SETNX
(SET if Not eXists)命令来尝试获取锁。例如,在Node.js中使用ioredis
库:
- 使用Redis的
const Redis = require('ioredis');
const redis = new Redis();
const lockKey = 'file - sync - lock';
const lockValue = Date.now() + 10000; // 锁的过期时间(毫秒)
redis.set(lockKey, lockValue, 'NX', 'EX', 10).then(() => {
// 获取锁成功,进行文件操作
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, 'example.txt');
const data = '要写入的数据';
fs.writeFileSync(filePath, data);
console.log('数据写入成功');
// 操作完成后释放锁
redis.del(lockKey).then(() => {
console.log('锁已释放');
}).catch(delErr => {
console.error('释放锁失败:', delErr);
});
}).catch(err => {
if (err.message.includes('BUSY')) {
console.log('锁已被其他节点获取,等待重试...');
// 可以在这里实现重试逻辑
} else {
console.error('获取锁失败:', err);
}
});
- 版本控制:
- 为每个文件维护一个版本号。每次文件更新时,版本号递增。
- 节点在读取文件时,同时获取版本号。在写入文件前,再次读取版本号并与之前获取的版本号进行比较。如果版本号相同,则可以进行写入操作,并更新版本号;如果版本号不同,则说明文件已被其他节点更新,需要重新读取文件并决定是否重新进行操作。
- 例如,可以将版本号和文件内容一起存储在JSON文件中:
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, 'example.json');
function readFileWithVersion() {
try {
const data = fs.readFileSync(filePath, 'utf8');
return JSON.parse(data);
} catch (err) {
if (err.code === 'ENOENT') {
return { version: 0, content: '' };
}
console.error('读取文件失败:', err);
return null;
}
}
function writeFileWithVersion({ version, content }) {
const newVersion = version + 1;
const newData = JSON.stringify({ version: newVersion, content });
try {
fs.writeFileSync(filePath, newData);
console.log('文件写入成功,版本号更新为:', newVersion);
} catch (err) {
console.error('写入文件失败:', err);
}
}
const current = readFileWithVersion();
if (current) {
const newContent = '新的文件内容';
const newData = { version: current.version, content: newContent };
const currentAfterRead = readFileWithVersion();
if (currentAfterRead && currentAfterRead.version === current.version) {
writeFileWithVersion(newData);
} else {
console.log('文件已被其他节点更新,需要重新读取并处理');
}
}
可能用到的技术或工具:
- Redis:用于实现分布式锁,确保同一时间只有一个节点能对文件进行操作。
- ETCD:也是一种分布式键值存储系统,可用于实现分布式锁和配置管理,在文件同步场景中也能发挥类似Redis的作用。
- JSON - Schema:用于验证文件内容的格式,特别是在使用版本控制将文件内容和版本号存储在JSON文件中的场景下,确保文件结构的正确性。