Nodejs调研与服务性能测试

Nodejs调研与服务性能测试

<br/><p>这几天对nodejs进行了一下简单的调研</p> <br/><p>主要关注这几个方面 <br/><ol> <br/> <li>socket服务性能,</li> <br/> <li>socket客户端性能</li> <br/> <li>http服务性能.</li> <br/> <li>服务的稳定性与资源占用</li> <br/> <li>开发成本</li> <br/></ol> <br/>考虑到今后的应用场景, 实现了一个简单的memcache代理服务. <br/></p> <br/><p> <br/>内部维护了一个50连接的简单连接池, 通过长连接与memcache服务器相连.<br /> <br/>同时对外提供socket代理服务与http restful服务 <br/></p> <br/> <br/><h3>测试环境</h3> <br/><p>测试使用编译安装的node.js v0.3.1,未使用任何第三方modules<br /> <br/>代理服务与memcache部署在不同的服务器中.<br /> <br/>系统均为rhel 5.2, cpu: AMD Opteron 2200, mem: 4g <br/></p> <br/> <br/><h3>测试用例</h3> <br/><p>通过此代理程序, 分别使用memcached协议与http协议从memcache服务中取出一个长度为100bytes的值, 并检查最终输出是否正确</p> <br/> <br/><h3>压力工具</h3> <br/><p>socket: 由于没有找到合适的socket压力工具.用node.js实现了一个简单的socket压力工具<br /> <br/>http: siege 2.70 <br/></p> <br/> <br/><h3>测试结论</h3> <br/><h5>服务启动与空载资源占用</h5> <br/><p><a href=“http://nodejs.kongwu.net/blog/wp-content/uploads/2010/12/standby.png”><img class=“alignnone size-full wp-image-11” title=“standby” src=“http://nodejs.kongwu.net/blog/wp-content/uploads/2010/12/standby.png” alt="" width=“635” height=“291” /></a><br /> <br/>程序启动20秒后,系统资源占用达到稳定状态, 内存消耗13m, 堆尺寸8m<br /> <br/>由堆使用变化可知v8每隔7~8秒会进行一次gc操作 <br/></p> <br/> <br/><h5>100并发100秒socket长连接压力</h5> <br/><p><a href=“http://nodejs.kongwu.net/blog/wp-content/uploads/2010/12/socket.png”><img class=“alignnone size-full wp-image-10” title=“socket” src=“http://nodejs.kongwu.net/blog/wp-content/uploads/2010/12/socket.png” alt="" width=“553” height=“536” /></a><br /> <br/>压力启动后内存占用迅速提高至30m, v8堆也基本维持在22m的水平, 使用率在20%到50%之间波动<br /> <br/>此时v8的gc操作频率降低到约20秒一次.<br /> <br/>qps曲线比较平稳,在16700左右波动,幅度在400左右,v8的gc操作对性能没有明显影响<br /> <br/>压力过程中cpu占用基本维持在95%左右,处于满载状态.<br /> <br/>另, 测试结束后20秒左右, 所占用资源被释放,内存与v8堆均回复至空载水平. <br/></p> <br/> <br/> <br/><h5>250并发100秒http长连接压力</h5> <br/><p><a href=“http://nodejs.kongwu.net/blog/wp-content/uploads/2010/12/http1.png”><img class=“alignnone size-full wp-image-9” title=“http1” src=“http://nodejs.kongwu.net/blog/wp-content/uploads/2010/12/http1.png” alt="" width=“613” height=“282” /></a><br /> <br/>与socket相比, http消耗的系统资源约多出30%,且8v的gc操作也要更频繁<br /> <br/>qps值为4392, gc操作对qps的影响也不明显<br /> <br/>压力过程中cpu占用基本维持在95%左右,处于满载状态.<br /> <br/>与socket时类似, 测试结束后20秒左右, 所占用资源被释放,内存与v8堆均回复至空载水平. <br/></p> <br/> <br/><h3>一些结论</h3> <br/><p>性能:单cpu, socket 17000 qps, http 4400 qps, 内存消耗30~40m, cpu基本满载<br /> <br/>用作中间层服务时,性能瓶颈基本应位于cpu运算性能.<br /> <br/>v8引擎gc操作带来的性能影响已经可以基本忽略.<br /> <br/>系统的健壮性不错,测试过程中qps与负载曲线基本都处于水平状态.且成功率均为100%<br /> <br/>快速开发, 代理服务与压力工具总计开发时间3~4小时左右, 且最终性能与编译型语言差距不大,但开发时间节省很多<br /> <br/>开发模式上与传统服务器端动态语言区别较大,不熟悉的开发人员需要一些上手时间.<br /> <br/><br /> <br/>另,由于时间因素,仅进行了单进程模式下的性能,使用web-worker模型的多进程模式下的性能没有进行测试<br /> <br/>不过由单进程性能可以基本推断,在普通8核服务器下应能做到10万以上的socket, qps, 3万以上的http qps<br /> <br/><br /> <br/>总体来说, 非阻塞模式的io处理给nodejs带来在相对低系统资源耗用下的高性能与出众的负载能力, 非常适合用作依赖其它io资源的中间层服务. <br/></p> <br/> <br/><h3>相关源码下载:</h3> <br/><p><a href=“http://nodejs-memcache-proxy-performance-test.googlecode.com/files/nodejs-text.tar.gz” target="_blank">http://nodejs-memcache-proxy-performance-test.googlecode.com/files/nodejs-text.tar.gz</a><br /> <br/>包括测试程序与socket压力工具. <br/></p> <br/>


2 回复

Nodejs调研与服务性能测试

简介

这几天对Node.js进行了简单的调研,主要关注以下几个方面:

  1. Socket服务性能
  2. Socket客户端性能
  3. HTTP服务性能
  4. 服务的稳定性与资源占用
  5. 开发成本

考虑到今后的应用场景,实现了一个简单的Memcached代理服务。该服务内部维护了一个50连接的简单连接池,通过长连接与Memcached服务器相连,并对外提供Socket代理服务与HTTP RESTful服务。

测试环境

  • 使用编译安装的Node.js v0.3.1,未使用任何第三方模块。
  • 代理服务与Memcached部署在不同的服务器中。
  • 系统均为RHEL 5.2,CPU为AMD Opteron 2200,内存为4GB。

测试用例

通过此代理程序,分别使用Memcached协议与HTTP协议从Memcached服务中取出一个长度为100字节的值,并检查最终输出是否正确。

压力工具

  • Socket:由于没有找到合适的Socket压力工具,用Node.js实现了一个简单的Socket压力工具。
  • HTTP:使用siege 2.70。

测试结论

服务启动与空载资源占用

程序启动20秒后,系统资源占用达到稳定状态,内存消耗约为13MB,堆尺寸约为8MB。由堆使用变化可知V8每隔7~8秒会进行一次GC操作。

// 示例代码:Node.js启动时的内存与堆使用情况监控
const os = require('os');
const { heapStatistics } = require('v8');

setInterval(() => {
    console.log(`Memory Usage: ${process.memoryUsage().heapUsed / 1024 / 1024} MB`);
    console.log(`Heap Statistics: ${JSON.stringify(heapStatistics())}`);
}, 1000);
100并发100秒Socket长连接压力

压力启动后内存占用迅速提高至30MB,V8堆也基本维持在22MB的水平,使用率在20%到50%之间波动。此时V8的GC操作频率降低到约20秒一次。QPS曲线比较平稳,在16700左右波动,幅度在400左右,V8的GC操作对性能没有明显影响。压力过程中CPU占用基本维持在95%左右,处于满载状态。测试结束后20秒左右,所占用资源被释放,内存与V8堆均回复至空载水平。

// 示例代码:Node.js实现的Socket压力测试工具
const net = require('net');

const client = new net.Socket();
client.connect(11211, 'localhost', () => {
    console.log('Connected');
});

client.on('data', (data) => {
    console.log(`Received: ${data.toString()}`);
    client.end();
});

client.on('close', () => {
    console.log('Connection closed');
});
250并发100秒HTTP长连接压力

与Socket相比,HTTP消耗的系统资源约多出30%,且V8的GC操作也要更频繁。QPS值为4392,GC操作对QPS的影响也不明显。压力过程中CPU占用基本维持在95%左右,处于满载状态。测试结束后20秒左右,所占用资源被释放,内存与V8堆均回复至空载水平。

// 示例代码:Node.js实现的HTTP压力测试工具
const http = require('http');

const options = {
    hostname: 'localhost',
    port: 8080,
    path: '/memcached',
    method: 'GET'
};

const req = http.request(options, (res) => {
    let data = '';
    res.on('data', (chunk) => {
        data += chunk;
    });
    res.on('end', () => {
        console.log(`Response: ${data}`);
    });
});

req.end();

结论

  • 性能:单CPU,Socket 17000 QPS,HTTP 4400 QPS,内存消耗30~40MB,CPU基本满载。
  • 用作中间层服务时,性能瓶颈基本应位于CPU运算性能。
  • V8引擎GC操作带来的性能影响已经可以基本忽略。
  • 系统的健壮性不错,测试过程中QPS与负载曲线基本都处于水平状态,且成功率均为100%。
  • 快速开发,代理服务与压力工具总计开发时间3~4小时左右,且最终性能与编译型语言差距不大,但开发时间节省很多。
  • 开发模式上与传统服务器端动态语言区别较大,不熟悉的开发人员需要一些上手时间。

总体来说,非阻塞模式的IO处理给Node.js带来了在相对低系统资源耗用下的高性能与出众的负载能力,非常适合用作依赖其他IO资源的中间层服务。


在进行Node.js的调研与服务性能测试时,我们可以重点关注以下几个方面:

  1. Socket服务性能
  2. Socket客户端性能
  3. HTTP服务性能
  4. 服务的稳定性与资源占用
  5. 开发成本

为了帮助理解这些方面的测试结果,以下是一些简化的示例代码片段,用于实现一个简单的Memcache代理服务,并通过Socket和HTTP两种协议测试其性能。

示例代码

Memcache代理服务 (server.js)

const net = require('net');
const memcacheClient = require('memcached');

const client = new memcacheClient('localhost:11211');

const server = net.createServer((socket) => {
    socket.on('data', async (data) => {
        const [command, key] = data.toString().split(' ');
        if (command === 'GET') {
            const result = await client.get(key);
            socket.write(result);
        }
    });
});

server.listen(6379, () => {
    console.log('Server listening on port 6379');
});

HTTP代理服务 (httpServer.js)

const http = require('http');
const memcacheClient = require('memcached');

const client = new memcacheClient('localhost:11211');

const server = http.createServer(async (req, res) => {
    const { url } = req;
    const match = url.match(/\/get\?key=(\w+)/);
    if (match) {
        const key = match[1];
        const result = await client.get(key);
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end(result);
    } else {
        res.writeHead(400);
        res.end('Bad Request');
    }
});

server.listen(8080, () => {
    console.log('HTTP Server listening on port 8080');
});

性能测试

Socket压力测试 (socketTest.js)

const net = require('net');

function createClient() {
    const socket = net.connect({ port: 6379 }, () => {
        socket.write('GET key');
    });

    socket.on('data', (data) => {
        console.log(`Received: ${data}`);
        socket.destroy();
    });

    socket.on('end', () => {
        console.log('Connection closed');
    });
}

// 创建多个客户端并发送请求
for (let i = 0; i < 100; i++) {
    setTimeout(createClient, i * 100);
}

HTTP压力测试 (siege)

可以使用siege工具来测试HTTP服务性能。首先确保安装了siege,然后运行以下命令:

siege -c 250 -t 100S http://localhost:8080/get?key=testKey

结论

根据上述测试结果,我们可以得出以下结论:

  • 性能: 单CPU环境下,Socket服务可以达到大约17000 QPS,HTTP服务可以达到大约4400 QPS。
  • 资源占用: 在高并发情况下,内存占用大约在30~40MB之间,CPU几乎满载。
  • 稳定性: 在长时间的压力测试中,QPS和负载曲线保持稳定,成功率达到100%。
  • 开发成本: Node.js提供了快速开发的优势,开发效率较高。

总之,Node.js在非阻塞I/O处理方面表现出色,非常适合用于中间层服务。

回到顶部