使用Node.js对文件进行读/写锁定

3

我希望能够实现以下事件序列:

我理解原子写入的价值,但是否有任何建议来

1. locking a file
2. reading from it
3. writing to it
4. releasing the lock

我们如何使用Node.js来实现这个功能?假设该文件存储着简单的JSON数据。
2个回答

1
即使是这样一个简单的用例,如果有其他进程同时访问文件,我认为您确实需要一种锁定机制。
我尝试了Lockfile和Warlock,对它们的默认设置以及微调它们的难度并不满意。
因此,我编写了一种不同类型的互斥库,称为“live-mutex”,它允许无需轮询,并且是完全事件驱动的客户端代理模型。它的主要优点是比lockfile和warlock快约15倍。
请查看: Github.com/oresoftware/live-mutex

1
你说得很对 - 令人惊讶的是,那些每周下载量达到数百万的模块质量如此之低或者干脆无法工作。你的包看起来很不错。但我更喜欢一个不需要TCP端口的文件锁定解决方案。 你是否遇到过fcntl咨询文件锁定的问题? - Simon Rigét
live-mutex 不需要 TCP 端口,您可以使用 Unix 域套接字,而且 UDS 的性能更高,大约是 2 倍。 - Alexander Mills
@SimonRigét 请尝试使用UDS测试live-mutex,并告诉我您的想法。 - Alexander Mills

1

您必须确保“原子锁”。从内部节点,您可以使用符号链接来实现此目的。这是一个简单计数器的示例:

const fs = require('fs');

// the lock function must be a recursive timer
const flock = (file_name, resolve, reject) => {
  fs.symlink(file_name, 'locked_' + file_name, (err) => {
    if(err)
      if(err.code == 'EEXIST')
        setTimeout(() => {
          flock(file_name, resolve, reject)
        }, 13);
      else
        reject(err);
    else
      resolve();
  });
}

const counter_increment = async () => {
  file_name = 'counter.txt';

  // Lock file
  await new Promise((resolve, reject) => {
    flock(file_name, resolve, reject);
  });

  // Read file
  let count = await new Promise((resolve, reject) => {
    fs.readFile(file_name, 'utf8', (err, data) => {
      if (err) resolve(0);
      resolve(parseInt(data));
    });
  });

  // Write file
  await new Promise((resolve, reject) => {
    fs.writeFile(file_name,"" + ++count + " ", (err) => {
      if (err) reject(err);
      resolve();
    });
  });

  // Unlock file
  fs.unlink('locked_' + file_name, (err) => {
    if (err) console.error(err);
  });

  return count;
};

counter_increment();

这种方式相比于真正的操作系统实现文件锁来说速度较慢,但对于生产环境来说是有效的。
Node.js文件系统库在这一点上还不够成熟。(截至Node.js 11版本)这个功能应该已经成为标准了,但却没有。
fs.ext模块https://github.com/baudehlo/node-fs-ext/添加了真正的操作系统文件锁定。不幸的是,它处理多个请求的方式存在一个错误,使其在生产中无法使用。此外,维护者似乎没有时间修复它。
我遇到的所有其他模块都做得不太好。即使是非常受欢迎的那些模块也是如此。

mkdir是一个原子操作,还有这个库可以使用TCP在进程之间进行锁定:https://github.com/ORESoftware/live-mutex - user5047085
你有关于多请求 bug 的信息吗? - Soylent Graham
这是libuv文件函数的设计缺陷/不成熟,因此也影响了模块中使用的方法。 请参见:https://github.com/baudehlo/node-fs-ext/issues/79 - Simon Rigét

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接