nodejs缓存
Ⅰ 请教关于Nodejs多进程共享缓存数据
以正常目前的业务场景来说(非nodejs),一个进程平均是用1.5-3G内存不等.缓存是根据某些特定条件组合生成的key(key的数量稍微有点儿多),需要从MongoDB/Redis读取数据.
1MB的数据是业务数据传输量最大的那种,不是只有这种业务.
场景可以假设为,获取用户的一些浏览记录,包含图片,描述,评测等(描述与评价都算是比较大的传输量的数据),每次获取30条左右.然后再乘以一定的用户在线数量,这个缓存数据是比较庞大的.先不考虑这个架构是否可以优化.
发这个主题的原因只是想了解到nodejs有没有什么成熟方案可以共享进程间的数据
比如
用户X,访问站点时,被调度系统分配给A进程获取了luby的浏览历史,A进程从mongodb获取到luby的记录列表进行呈现.这时候用户Y也想看看luby的浏览历史,这调度系统分配给了B进程.这个时候B进程又要再去mongodb获取一次.
我期望是B进程可以共享A进程的luby记录列表
1)降低mongogdb的访问频率
2)提高响应速度,因为减少了mongodb查询,减少了网络传输.
Ⅱ 如何在Nodejs中使用缓存
Nodejs可以使用redis缓存。
Redis数据库采用极简的设计思想,最新版的源码包还不到2Mb。其在使用上也有别于一般的数据库。
node_redis
redis驱动程序多使用 node_redis此模块可搭载官方的 hiredis C 语言库 - 同样是非阻塞的,比使用javaScript内置的解释器性能稍好。可选择将hiredis 与 redis 一同安装。
npm install hiredis redis
如果 hiredis 安装成功, node_redis 会默认使用 hiredis, 否则会使用JavaScript的解释器。
Redis的一个Key不仅可以对应一个String类型的值,还支持hashes, lists, sets, sorted sets, bitmaps等。
比如存/取一组Hash值,Redis中有两个对应的命令
HMSET key field value [field value ...]、
为一个Key一次设置多个哈希键/值, 多用于JSON对象的写入(序列化的SESSION)。
HGETALL key
读取一个Key的所有 哈希键/值,多用于JSON对象读取
这两个命令即是在NodeJS中存取JSON对象的关键,
下面是node_reids中对应的例子:
全选复制放进笔记var redis = require("redis"),
client = redis.createClient();
//写入JavaScript(JSON)对象
client.hmset('sessionid', { username: 'kris', password: 'password' }, function(err) {
console.log(err)
})
//读取JavaScript(JSON)对象
client.hgetall('sessionid', function(err, object) {
console.log(object)
})
Ⅲ nodejs如何实现
摘要 CommonJS 是一种模块化的标准,而 NodeJS 是这种标准的实现,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
Ⅳ nodejs fs 文件流传输要不要缓存区
nodejs的fs模块并没有提供一个的方法,但我们可以很容易的实现一个,比如:
var source = fs.readFileSync('/path/to/source', {encoding: 'utf8'});
fs.writeFileSync('/path/to/dest', source);
这种方式是把文件内容全部读入内存,然后再写入文件,对于小型的文本文件,这没有多大问题,比如grunt-file-就是这样实现的。但是对于体积较大的二进制文件,比如音频、视频文件,动辄几个GB大小,如果使用这种方法,很容易使内存“爆仓”。理想的方法应该是读一部分,写一部分,不管文件有多大,只要时间允许,总会处理完成,这里就需要用到流的概念。
如上面高大上的图片所示,我们把文件比作装水的桶,而水就是文件里的内容,我们用一根管子(pipe)连接两个桶使得水从一个桶流入另一个桶,这样就慢慢的实现了大文件的复制过程。
Stream在nodejs中是EventEmitter的实现,并且有多种实现形式,例如:
http responses request
fs read write streams
zlib streams
tcp sockets
child process stdout and stderr
上面的文件复制可以简单实现一下:
var fs = require('fs');
var readStream = fs.createReadStream('/path/to/source');
var writeStream = fs.createWriteStream('/path/to/dest');
readStream.on('data', function(chunk) { // 当有数据流出时,写入数据
writeStream.write(chunk);
});
readStream.on('end', function() { // 当没有数据时,关闭数据流
writeStream.end();
});
上面的写法有一些问题,如果写入的速度跟不上读取的速度,有可能导致数据丢失。正常的情况应该是,写完一段,再读取下一段,如果没有写完的话,就让读取流先暂停,等写完再继续,于是代码可以修改为:
var fs = require('fs');
var readStream = fs.createReadStream('/path/to/source');
var writeStream = fs.createWriteStream('/path/to/dest');
readStream.on('data', function(chunk) { // 当有数据流出时,写入数据
if (writeStream.write(chunk) === false) { // 如果没有写完,暂停读取流
readStream.pause();
}
});
writeStream.on('drain', function() { // 写完后,继续读取
readStream.resume();
});
readStream.on('end', function() { // 当没有数据时,关闭数据流
writeStream.end();
});
或者使用更直接的pipe
// pipe自动调用了data,end等事件
fs.createReadStream('/path/to/source').pipe(fs.createWriteStream('/path/to/dest'));
下面是一个更加完整的复制文件的过程
var fs = require('fs'),
path = require('path'),
out = process.stdout;
var filePath = '/Users/chen/Movies/Game.of.Thrones.S04E07.1080p.HDTV.x264-BATV.mkv';
var readStream = fs.createReadStream(filePath);
var writeStream = fs.createWriteStream('file.mkv');
var stat = fs.statSync(filePath);
var totalSize = stat.size;
var passedLength = 0;
var lastSize = 0;
var startTime = Date.now();
readStream.on('data', function(chunk) {
passedLength += chunk.length;
if (writeStream.write(chunk) === false) {
readStream.pause();
}
});
readStream.on('end', function() {
writeStream.end();
});
writeStream.on('drain', function() {
readStream.resume();
});
setTimeout(function show() {
var percent = Math.ceil((passedLength / totalSize) * 100);
var size = Math.ceil(passedLength / 1000000);
var diff = size - lastSize;
lastSize = size;
out.clearLine();
out.cursorTo(0);
out.write('已完成' + size + 'MB, ' + percent + '%, 速度:' + diff * 2 + 'MB/s');
if (passedLength < totalSize) {
setTimeout(show, 500);
} else {
var endTime = Date.now();
console.log();
console.log('共用时:' + (endTime - startTime) / 1000 + '秒。');
}
}, 500);
可以把上面的代码保存为.js试验一下
我们添加了一个递归的setTimeout(或者直接使用setInterval)来做一个旁观者,每500ms观察一次完成进度,并把已完成的大小、百分比和复制速度一并写到控制台上,当复制完成时,计算总的耗费时间,效果如图:
我们复制了一集1080p的权利的游戏第四季第7集,大概3.78G大小,由于使用了SSD,可以看到速度还是非常不错的,哈哈哈~
复制完成后,显示总花费时间
结合nodejs的readline, process.argv等模块,我们可以添加覆盖提示、强制覆盖、动态指定文件路径等完整的复制方法,有兴趣的可以实现一下,实现完成,可以
ln -s /path/to/.js /usr/local/bin/my
这样就可以使用自己写的my命令替代系统的cp命令
Ⅳ nodejs orm redis怎么做缓存
Nodejs可以使用redis缓存。 Redis数据库采用极简的设计思想,最新版的源码包还不到2Mb。其在使用上也有别于一般的数据库。 node_redis redis驱动程序多使用 node_redis此模块可搭载官方的 hiredis C 语言库 - 同样是非阻塞的
Ⅵ nodejs 模块会缓存,但执行是会再次解析么
Node.js中模块可以通过文件路径或名字获取模块的引用。模块的引用会映射到一个js文件路径,除非它是一个Node内置模块。
Node的内置模块公开了一些常用的API给开发者,并且它们在Node进程开始的时候就预加载了。
Ⅶ 为什么redis在java是同步缓存,而在nodejs是异步缓存
JAVASCRIPT中是没有多线程的,所有涉及外部IO的全部都是回调。
这样的好处是JS天然就是一个不会阻塞的系统,这也是NODEJS现在作为前后端黏合层的原因。
Ⅷ nodejs查看node-cache在哪个问孩子
为什么不使用现有的Cache存储系统,比如Redis,比如Memcached。不是说Redis不够好,只是在处理某些场景中使用的Redis会显的太“笨重”了——Redis的优势之一在于能够供多进程共享,有完善的备份和恢复机制。
但反过来想,如果你的缓存仅供单个进程,单个Node实例使用,并且可以容忍缓存的丢失,承受冷启动。那么是值得用不到500行的代码来搭建一个速度更快的缓存模块。
Ⅸ 想问一下 nodejs 内存要怎么查看
varcookie=require('cookie');mole.exports=function(req,res,conf,views,db){..varbody=req.body,.id=req.ids[0],.usid=cookie.parse(req.headers.cookie).usid;..functionredirect(){.res.writeHead(302,{'location':'/accounts'});.res.end();..}..functionjoinpage(){.res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});.res.write(views.ACCOUNTS_JOIN);.res.write(views.unit({id:'accounts_menu',name:'accounts_menu',..options:{.class_id:id..}.}));.res.write(views.unit({id:'accounts_join',name:'accounts_join',options:{..action:'/accounts/'+id+'/join',..num:'0'}.}));.res.end(views.FOOTER);..}..db.session(usid,function(state){.//已经建立会话.if(state){joinpage();return;.}.//没有建立会话.redirect();..});};//////////////////////////////////////////////////////////////////////////////////////////////////////////这段代码,是nodejs其中一个路由处理函数.使用到了views视图模型,db数据库模型,以及conf全局配置文件.并且使用了cookie模块来解析会话ID.views视图模型:生产HTML界面[可以随时切换到PC或者移动HTML,接口一致]db数据模型:生产数据库数据conf全局配置文件:你所需要的全局环境内容代码的功能:检测请求.是否建立会话?..是,跳转到"/"路由..否,为用户显示登录界面其中views负责生产视图界面,在views模型中缓存了大量的常量,类似ACCOUNTS_JOIN,是页面布局。对于其中的动态内容,采用facebook的bigpipe技术。views.unit(/*id,name,css,js,content*/)输出script片段,分流到浏览器渲染。整个服务器端在启动时渲染完毕所有的页面布局体,并缓存到views模型中,动态内容由bigpipe发送到前端渲染。
Ⅹ nodejs socket怎么主动刷新缓存区数据
清空socket缓存区的数据的方法
由于socket是以数据流的形式发送数据,接收方不知道对方一次性发送了多少数据,也能保证对方一次性发送的数据能在同一刻接收到,所以Receive方法是这么工作的:
接受一个byye[]类型的参数作为缓冲区,在经过一定的时间后把接收到的数据填充到这个缓冲区里面,并且返回实际接收到数据的长度,这个实际接收到的数据长度有可能为0(没有接收到数据)、大于0小于缓冲区的长度(接收到数据,但是没有我们预期的多)、等于缓冲区的长度(说明接收到的数据大于等于我们预期的长度)。
每次接收缓冲区都用同一个byte[] byteMessage,并且你没有检查接收到的数据长度,所以第一次你接收到的数据是123456,第二次你只接收到了8,但是缓冲区里面还有23456,所以加起来就是823456了。
socket接收缓冲区的大小有讲究,设置大了接收起来慢,因为它要等尽可能多的数据接收到了再返回;设置小了需要重复多次调用接收方法才能把数据接收完,socket有个属性,标识了系统默认的接收缓冲区大小,可以参考这个!
还有就是用recv读取,但是由于不知道缓存里有多少数据,如果是阻塞模式,到最后必然等到超时才知道数据已经读取完毕,这是个问题。
另一个是用fgetc,通过返回判断是否是feof:
whlie (1) { a=fgetc(f);if (feof(f)) break;//…
b=fgetc(f);if (feof(f)) break;//…}当然,我不知道读取完毕后最后一次调用fgetc会不会堵塞,需要测试。
在非阻塞模式下,我们用recv就可以轻松搞定了,但是阻塞模式下,由于我们不知道缓冲区有多少数据,不能直接调用recv尝试清除。
使用一个小小的技巧,利用select函数,我们可以轻松搞定这个问题:
select函数用于监视一个文件描述符集合,如果集合中的描述符没有变化,则一直阻塞在这里,直到超时时间到达;在超时时间内,一旦某个描述符触发了你所关心的事件,select立即返回,通过检索文件描述符集合处理相应事件;select函数出错则返回小于零的值,如果有事件触发,则返回触发事件的描述符个数;如果超时,返回0,即没有数据可读。
重点在于:我们可以用select的超时特性,将超时时间设置为0,通过检测select的返回值,就可以判断缓冲是否被清空。通过这个技巧,使一个阻塞的socket成了‘非阻塞’socket.
现在就可以得出解决方案了:使用select函数来监视要清空的socket描述符,并把超时时间设置为0,每次读取一个字节然后丢弃(或者按照业务需要进行处理,随你便了),一旦select返回0,说明缓冲区没数据了(“超时”了)。