计算何时多次写入文件会导致不准确

Calculating when multiple writes to a file will cause inaccuracies?

本文关键字:不准确 文件 何时多 计算      更新时间:2023-09-26

在我的节点服务器中,我有一个变量,

var clicks = 0;

每次用户在 Web 应用中单击时,WebSocket 事件都会发送一条消息。 在服务器上,

clicks++;
if (clicks % 10 == 0) {
  saveClicks();
}
function saveClicks() {
    var placementData = JSON.stringify({'clicks' : clicks});
    fs.writeFile( __dirname + '/clicks.json', placementData, function(err) {
    });
}

我必须以什么速度开始担心覆盖?我将如何计算这个数学?

(我正在考虑为每次单击创建一个MongoDB json对象,但我很好奇本机解决方案可以提供什么(。

从节点.js文档用于fs.writeFile()

请注意fs.writeFile(),在 相同的文件,无需等待回调。对于此方案, 强烈建议fs.createWriteStream()

这不是

一个数学问题,无法弄清楚这何时会导致问题 - 它只是糟糕的代码,让您在无法预测的情况下发生冲突的机会。节点.js文档明确指出这可能会导致冲突。

若要确保没有冲突,请以不同的方式编写代码,以便不会发生冲突。

如果要确保所有写入都按传入请求的正确顺序进行,以便到达的最后一个请求始终是最终出现在文件中的请求,那么您需要在数据到达时对数据进行排队(以便保留顺序(并以打开文件进行独占访问的方式写入文件,以便在先前请求仍在时没有其他请求可以写入适当地编写和处理争用错误。

这是数据库通常自动为您执行的问题,因此这可能是使用数据库的原因之一。

假设您没有使用集群,因此没有多个进程尝试写入此文件,并且您只想确保发送的最后一个值是此进程写入文件的值,您可以执行以下操作:

var saveClicks = (function() {
    var isWriting = false;
    var lastData;
    return function() {
        // always save most recent data here
        lastData = JSON.stringify({'clicks' : clicks});
        if (!isWriting) {
            writeData(lastData);
        }
        function writeData(data) {
            isWriting = true;
            lastData = null;
            fs.writeFile(__dirname + '/clicks.json', data, function(err) {
                isWriting = false;
                if (err) {
                    // decide what to do if an error occurs
                }
                // if more data arrived while we were writing this, then write it now
                if (lastData) {
                    writeData(lastData);
                }
            });
        }
    }
})();
@jfriend00对

createWriteStream绝对是正确的,并且已经对数据库提出了一个观点,而且一切都说得差不多了,但我想强调一下关于数据库的观点,因为基本上文件保存方法对我来说似乎很奇怪。

因此,请使用数据库。

这不仅可以使您免于跟踪此类事情的麻烦,而且会显着加快速度(请记住,在node中完成工作的方式,众多文件读写过程将在单个线程中并行化,所以基本上如果其中一个持续很长时间,它可能会稍微影响整体性能(。

Redis 是存储键值数据的完美解决方案,因此您可以将每个用户的点击次数等数据存储在 Redis 数据库中,当您获得足够的流量时,无论如何您都必须运行该数据库:)

如果你还不相信,看看这个简单的基准:

雷迪斯:

var async = require('async');
var redis = require("redis"),
    client = redis.createClient();
console.time("To Redis");
async.mapLimit(new Array(100000).fill(0), 1, (el, cb) => client.set("./test", 777, cb), () => {
    console.timeEnd("To Redis");
});

到雷迪斯:5410.383ms

司 司长:

var async = require('async');
var fs = require('fs');
console.time("To file");
async.mapLimit(new Array(100000).fill(0), 1, (el, cb) => fs.writeFile("./test", 777, cb), () => {
    console.timeEnd("To file");
});

到文件:20344.749ms

而且,顺便说一下,您可以通过简单地将此"点击保护程序"添加到套接字socket.on('disconnect', ...来显着增加单击次数,之后将存储进度(现在是 10 次(。