1、multi-node
node只能单进程,单cpu工作,而multi-node则可以让node在多进程下共享内存的工作,实现机制是依靠child_process的sendmsg做到的。想要了解具体实现原理请查阅multi-node的源代码。
他的具体用法也非常的简单,我们看示例代码:
var server = require("http").createServer(function(request, response){
//这里是处理请求的程序
});
var nodes = require("multi-node").listen({
port: 80, //监听的端口
nodes: 4 //打开node进程数,一般最多为服务器CPU个数
}, server);
这样使用 $ node server.js就会启动4个server.js来监听80端口,具体请求被分配到哪个进程,由multi-node控制。在进程之间通信可以利用他提供的Framing,也可以利用redis等内存db来做。
nodes.addListener("node", function(stream){
stream = require("multi-node").frameStream(stream);
stream.addListener("message", function(data){
//在这里接受从其他进程发送的数据,可以是字符串,对象或其他格式
});
stream.send({foo:"bar"}); //类似广播概念,给所有进程广播这个消息
});
单进程"hello world"node服务器,在4CPU 3.4GHZ服务器上压测是4000qps+,开了multi-node以后再测试可以稳定达到7500qps+以上,峰值在8500qps+,性能大幅度提高。
2、generic-pool
generic-pool是一个通用连接池,node和php不同,php每次和db通信,都需要先建立连接然后执行程序,最后释放这个连接。node是可以事先建立一个池子,然后根据需要生成连接放入这个池中,当node要和db通信时则去池子中拿连接,用完以后不释放,而是将这个连接归还到池中,我们也可以设定这个池子的的最大连接数和闲置连接超时释放的时间。
1、可以不必为建立连接和释放连接消耗更多的响应时间,一个连接在高并发下可以被高度重用。
2、有队列机制,当池子中连接都用完了,其他请求在排队时,有一些紧急的任务需要插队,我们可以很方便的做到这点。
他的示例代码是为mysql提供连接池,我就不贴上来了,我们来为redis做一个简单的链接池,并测试下。先简单介绍下他的几个参数:
name : name of pool (string, optional)
create : function that returns a new resource
should call callback() with the created resource
destroy : function that accepts a resource and destroys it
max : maximum number of resources to create at any given time
idleTimeoutMillis : max milliseconds a resource can go unused before it should be destroyed
(default 30000)
reapIntervalMillis : frequency to check for idle resources (default 1000),
priorityRange : int between 1 and x - if set, borrowers can specify their
relative priority in the queue if no resources are available.
see example. (default 1)
log : true/false or function -
If a log is a function, it will be called with log strings
Else if log is true, verbose log info will be sent to console.log()
Else internal log messages be ignored (this is the default)
英文好的朋友很容易就看懂了上面的这些说明,我为英文和我一样比较差的朋友简单翻译一下,省的他们再去google翻译了。
name:连接池的名字,例如“mysql”,主要是用作日志上的区分,一个名字而已
create:一个函数,和db建立连接的函数,必须要把创建好的db连接示例传入到callback函数中
destroy:摧毁和这个db连接的函数
idleTimeoutMillis:为每个连接设置一个超时时间
reapIntervalMillis:检查闲置连接的频率
priorityRange:1-X的整数,当没有连接时,可以为1-X这几个应用开辟绿色通道,让他们插队。
log:日志系统,true的话则是记录详细日志,开发时用,一般为false
下面我就贴一段redis连接池的代码:
var poolModule = require('./generic-pool.js');
var pool = poolModule.Pool({
name : 'redis',
create : function(callback) {
var client = require('redis').createClient(); //这里是创建redis连接实例的代码
callback(null, client); //创建完了以后,要把client传给callback,这里第一个参数看了源码得知是err,我们不必理会
},
destroy : function(client) { client.quit(); }, //当超时则释放连接
max : 10, //最大连接数
idleTimeoutMillis : 30000, //超时时间
log : true,
});
下面我可以利用他提供的几个方法,用连接池来操作redis:
var test_pool =function(){
pool.acquire(function(err, client) {
client.set('test', 'xdy',function(err, reply){
console.log(reply+"");
pool.release(client);
})
});
pool.acquire(function(err, client) {
client.set('test1', 'xdy',function(err, reply){
console.log(reply+"");
pool.release(client);
})
});
pool.acquire(function(err, client) {
client.set('test2', 'xdy',function(err, reply){
console.log(reply+"");
pool.release(client);
})
});
}
test_pool ();
setTimeout(function(){
test_pool ();
},500);
我们定义了一个test_pool的方法,定义了3个redis操作,使用pool的acquire方法来去连接池拿连接,在处理完毕以后,用pool的release方法将连接归还到连接池,我们打开日志,运行程序以后可以看到:
在test_pool()执行后,连接池创建了3个连接给test_pool,test_pool在redis操作完毕以后,归还连接,在500毫秒之后,test_pool再次去连接池拿连接操作redis,这时因为之前的连接没有超时,所以之前的3个连接又被拿出来处理第二次test_pool函数了。这样就做到了重用,不必每次去建立和释放连接,当30秒过后,连接会自动释放掉。
个人觉得我们还可以对这个连接池改写一下,再提高一下连接池在某些情况下的性能,为连接池增加一项配置,就是永不过期的连接数,这样我就可以在程序启动的时候预先放置好一些连接永不过期,如果大并发突然过来可以节约一点创建连接的时间,这种情况比较少,改写以后可能压力测试成绩会好一点。
具体压测数据,请关注我博客,我将会在和PHP对比压测文章内给出。
- 264分析两大利器:264VISA和Elecard StreamEye Tools
学了264有将近3个月有余,好多时候都在学习老毕的书和反复看JM86的代码,最近才找到264分析两大利器:264VISA和Elecard StreamEye Tools.不由得感叹,恨不逢同时. 简单 ...
- Spring Security和 JWT两大利器来打造一个简易的权限系统。
写在前面 关于 Spring Security Web系统的认证和权限模块也算是一个系统的基础设施了,几乎任何的互联网服务都会涉及到这方面的要求.在Java EE领域,成熟的安全框架解决方案一般有 A ...
- 如何使用 K8s 两大利器"审计"和"事件"帮你摆脱运维困境?
概述 下面几个问题,相信广大 K8s 用户在日常集群运维中都曾经遇到过: 集群中的某个应用被删除了,谁干的? Apiserver 的负载突然变高,大量访问失败,集群中到底发生了什么? 集群节点 Not ...
- 告别set和get,两大利器轻松搞定model转换
场景一:一般我们遇到需要新建model,常规做法就是创建一个类,老老实实的定义好model中的所有属性,一般来说属性对应的set方法和get方法都是少不了的,有时候还需要toString甚至equal ...
- 转: H264码流分析 --264分析两大利器:264VISA和Elecard StreamEye Tools
转码: http://www.360doc.com/content/13/0225/19/21412_267854467.shtml ESEYE视频工具全称是什么: Elecard StreamEye ...
- .Net 两大利器Newtonsoft.NET和Dapper
你可以使用ado.net返回的DataTable让Newtonsoft.NET来序列化成Json. 当然你可以使用Dapper返回的List让Newtonsoft.NET来序列化成JSON. 参考资料 ...
- webpack 教程 那些事儿03-webpack两大精华插件,热加载
本节主要讲述 webpack的两大经典开发调试插件,热插拔内存缓存机制 文章目录 1. html-webpack-plugin插件的使用 2. webpack-dev-middleware 插件登场 ...
- [转帖]两大容器管理平台,Kubernetes与OpenShift有什么区别?
两大容器管理平台,Kubernetes与OpenShift有什么区别? https://www.sohu.com/a/327413642_100159565 原来openshift 就是 k8s的一个 ...
- 3dTiles 数据规范详解[3] 内嵌在瓦片文件中的两大数据表
转载请声明出处:全网@秋意正寒 零.本篇前言 说实话,我很纠结是先介绍瓦片的二进制数据文件结构,还是先介绍这两个重要的表.思前想后,我决定还是先介绍这两个数据表. 因为这两个表不先给读者灌输,那么介绍 ...
随机推荐
- 【t070】二进制
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 求所有可以只用1和00拼成的长度为N的二进制数的个数除以15746的余数. 比如当N=4的时候,有5个 ...
- git 分支建立及合并
分支的新建与合并 让我们来看一个简单的分支新建与分支合并的例子,实际工作中你可能会用到类似的工作流. 你将经历如下步骤: 开发某个网站. 为实现某个新的需求,创建一个分支. 在这个分支上开展工作. 正 ...
- ArcSDE中Compress与Compact的区别
原文 ArcSDE中Compress与Compact的区别 附件一”为两种数据库需要的管理工作. 与所表示的含义与操作是不同的. 对于来说,Compressing与Smart Dat ...
- JS表格分页组件:fupage的设计思路和具体用法(未来考虑开源,争取在2015年)
一.背景 之前在秒针工作的时候,某js高级工程师写了很多自己的组件,其中一套是分页组件,叫做st-grid.不过在我看来,bug太多,我经常给他反馈bug,我也不清楚为啥别人没有发现. ...
- Tokumx vs Mongodb
Mongodb是一个文档型nosql数据库 採用C++编写 Mongo DB最大的优势在于全部的数据持久操作都无需开发者手动编写SQL语句,直接调用方法就能够轻松的实现CRUD操作. 非常多人觉得mo ...
- BZOJ 2783 树 - 树上倍增 + 二分
传送门 分析: 对每个点都进行一次二分:将该点作为链的底端,二分链顶端所在的深度,然后倍增找到此点,通过前缀和相减求出链的权值,并更新l,r. code #include<bits/stdc++ ...
- 【a703】求逆序对
Time Limit: 10 second Memory Limit: 2 MB 问题描述 给定一个序列a1,a2...an.如果存在i小于j 并且ai大于aj,那么我们称之为逆序对,求给定序列中逆序 ...
- Python 第三方库 cp27、cp35 等文件名的含义
What does version name 'cp27' or 'cp35' mean in Python? 如对于 gensim-0.12.4-cp27-none-win_amd64.whl文件名 ...
- 微信小程序开发demo-地图定位
要求要完成的功能: 1.要完成的要点是城市定位. 2.就是切换城市. 首页我们先参照微信小程序开放的官方文档找到: 在这里我们可以找到”当前位置经纬度“ getLocation: function ( ...
- View的绘制顺序
1.写在 super.onDraw() 的下面 把绘制代码写在 super.onDraw() 的下面,由于绘制代码会在原有内容绘制结束之后才执行,所以绘制内容就会盖住控件原来的内容. 2.写在 sup ...