在我的节点服务器中我有一个变量
var clicks = 0;
每次用户点击webapp时,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对象,但我很好奇本机解决方案可以提供什么)。
答案 0 :(得分:4)
来自fs.writeFile()
的node.js文档:
请注意,多次使用
fs.writeFile()
是不安全的 相同的文件,无需等待回调。对于这种情况, 强烈建议使用fs.createWriteStream()
。
这不是一个数学问题,无法确定何时可能导致问题 - 它只是一个错误的代码,在无法预测的情况下会给你一个冲突的机会。 node.js doc明确指出这可能会导致冲突。
为了确保您不会发生冲突,请以不同的方式编写代码,以免发生冲突。
如果您想确保所有写入按正确的传入请求顺序发生,那么最后一个到达请求始终是最终在文件中的那个,那么您需要在数据到达时对其进行排队(所以订单被保留)并以打开文件进行独占访问的方式写入文件,因此在先前请求仍在编写并正确处理争用错误时,没有其他请求可以写入。
这是数据库主要为您自动执行的问题,因此可能是使用数据库的一个原因。
假设您没有使用群集,因此没有多个进程尝试写入此文件,并且您只是想确保发送的最后一个值是通过此过程写入文件的值,您可以做这样的事情:
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);
}
});
}
}
})();
答案 1 :(得分:1)
@jfriend00对于createWriteStream
肯定是正确的,并且已经对数据库提出了一个观点,并且几乎所有内容都说了,但我想强调关于数据库的观点,因为基本上文件保存方法似乎很奇怪我
这不仅会让你免于跟踪这些事情的麻烦,而且会显着加快速度(请记住,在节点中完成这些工作的方式,大量的文件读写过程将在一个线程中并行化,所以基本上如果其中一个持续多年,它可能会略微影响整体表现。)
Redis是存储键值数据的完美解决方案,因此您可以在Redis数据库中存储每个用户的点击数据,无论如何,当您获得足够的流量时,您必须与它们一起运行:)< / p>
如果您还不相信,请看一下这个简单的基准:
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");
});
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)。