Nodejs Http 服务 压力测试
发布于 1 年前 作者 TimLiu1 3351 次浏览 来自 分享

nodejs压力测试

背景

随着公司的业务的扩展,并发也越来越高,随着并发的变高,必然会带来很多问题,比如响应变慢,响应超时,甚至服务宕机,为了能够更好的处理此类问题,我们必须了解nodejs的基础性能,下面就是针对以下两种情况做的压力测试。

  • nodejs每秒钟能处理多少个简单请求

  • nodejs每秒中能够处理多少个简单查询数据库的请求

准备条件
  • server: 原生nodejs搭建一个http服务,每个请求返回1k的数据, node version:10
const http = require('http');

let port = process.env.port | 3000

http.createServer(app).listen(port, () => {
    console.log(`server is listening ${port}`)
})

let num = 0;
function app(req, res) {
    console.log(`第${num++}次访问`)
    res.end(getdata().toString())
}

function getdata() {
    let size = 1 * 1024
    let arr = new Array(size)
    for (let i = 0; i < arr.length; i++) {
        arr[i] = 1
    }
    return arr;
}
  • ab压力测试工具

  • 硬件条件

    阿里云 Ubuntu,8G,2CPU

测试场景一

请求10000次,并发分别为10 100 1000 5000 10000

ab -n10000 -c10 http://localhost:3000/

Concurrency Level:      10
Time taken for tests:   1.763 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      21220000 bytes
HTML transferred:       20470000 bytes
Requests per second:    5672.22 [#/sec] (mean)
Time per request:       1.763 [ms] (mean)
Time per request:       0.176 [ms] (mean, across all concurrent requests)
Transfer rate:          11754.35 [Kbytes/sec] received

ab -n10000 -c100 http://localhost:3000/

Concurrency Level:      100
Time taken for tests:   1.338 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      21220000 bytes
HTML transferred:       20470000 bytes
Requests per second:    7472.81 [#/sec] (mean)
Time per request:       13.382 [ms] (mean)
Time per request:       0.134 [ms] (mean, across all concurrent requests)
Transfer rate:          15485.66 [Kbytes/sec] received

ab -n10000 -c1000 http://localhost:3000/

Concurrency Level:      1000
Time taken for tests:   1.489 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      21220000 bytes
HTML transferred:       20470000 bytes
Requests per second:    6713.89 [#/sec] (mean)
Time per request:       148.945 [ms] (mean)
Time per request:       0.149 [ms] (mean, across all concurrent requests)
Transfer rate:          13912.97 [Kbytes/sec] received

ab -n10000 -c5000 http://localhost:3000/

Concurrency Level:      5000
Time taken for tests:   2.179 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      21220000 bytes
HTML transferred:       20470000 bytes
Requests per second:    4589.91 [#/sec] (mean)
Time per request:       1089.345 [ms] (mean)
Time per request:       0.218 [ms] (mean, across all concurrent requests)
Transfer rate:          9511.52 [Kbytes/sec] received

ab -n10000 -c10000 http://localhost:3000/

Concurrency Level:      10000
Time taken for tests:   1.870 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      21220000 bytes
HTML transferred:       20470000 bytes
Requests per second:    5348.45 [#/sec] (mean)
Time per request:       1869.701 [ms] (mean)
Time per request:       0.187 [ms] (mean, across all concurrent requests)
Transfer rate:          11083.41 [Kbytes/sec] received
并发 总花费时间/s 失败个数 每秒请求(TPS) 总传输 每个请求/ms 传输速率(k/s)
10 1.763 0 5672 20M 0.176 11754
100 0.873 0 7472 20M 0.134 15485
1000 0.866 0 6713 20M 0.149 13912
5000 1.381 0 4589 20M 0.218 9511
10000 1.495 0 5348 20M 0.187 11083
总结

在本地环境,基本不考虑网络因素,不考虑每个请求返回1KB数据,TPS能够达到7000~1100, 并不是并发越大请求越快,两则之间不存在线性关系

测试场景二

基于上述程序,添加连接mongodb,每次查询大小为1kb的数据,返回,测试

const http = require('http');

let port = process.env.port | 3000

http.createServer(app).listen(port, () => {
    console.log(`server is listening ${port}`)
})

let num = 0;
function app(req, res) {
    console.log(`第${num++}次访问`)
    getDataFromDb(res)
}

function getdata() {
    let size = 1 * 1024
    let arr = new Array(size)
    for (let i = 0; i < arr.length; i++) {
        arr[i] = 1
    }
    return arr;
}

function getDataFromDb(res){
let data = Blog.findOne({},(err,result) => {
res.end(result.toString())
})
}

const mongoose = require("mongoose")
mongoose.connect('mongodb://localhost:30001/tim', {useNewUrlParser: true});
const Schema = mongoose.Schema;
const blogSchema = new Schema({
  title: String,
  body: []
});
const Blog = mongoose.model('Blog', blogSchema);
let obj = {title:"tim",body:getdata()}
const post = new Blog(obj);
post.save()

请求10000次,并发分别为10 100 150

ab -n10000 -c10 http://localhost:3000/

Concurrency Level:      10
Time taken for tests:   12.923 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      11690000 bytes
HTML transferred:       10940000 bytes
Requests per second:    773.84 [#/sec] (mean)
Time per request:       12.923 [ms] (mean)
Time per request:       1.292 [ms] (mean, across all concurrent requests)
Transfer rate:          883.41 [Kbytes/sec] received

ab -n10000 -c100 http://localhost:3000/

Concurrency Level:      100
Time taken for tests:   11.268 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      11690000 bytes
HTML transferred:       10940000 bytes
Requests per second:    887.44 [#/sec] (mean)
Time per request:       112.684 [ms] (mean)
Time per request:       1.127 [ms] (mean, across all concurrent requests)
Transfer rate:          1013.10 [Kbytes/sec] received

ab -n10000 -c1000 http://localhost:3000/

Concurrency Level:      1000
Time taken for tests:   12.815 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      11690000 bytes
HTML transferred:       10940000 bytes
Requests per second:    780.33 [#/sec] (mean)
Time per request:       1281.508 [ms] (mean)
Time per request:       1.282 [ms] (mean, across all concurrent requests)
Transfer rate:          890.83 [Kbytes/sec] received

ab -n10000 -c5000 http://localhost:3000/

Concurrency Level:      5000
Time taken for tests:   19.061 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      11690000 bytes
HTML transferred:       10940000 bytes
Requests per second:    524.63 [#/sec] (mean)
Time per request:       9530.570 [ms] (mean)
Time per request:       1.906 [ms] (mean, across all concurrent requests)
Transfer rate:          598.92 [Kbytes/sec] received

```ab -n10000 -c10000 http://localhost:3000/``

Concurrency Level:      10000
Time taken for tests:   12.900 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      11690000 bytes
HTML transferred:       10940000 bytes
Requests per second:    775.19 [#/sec] (mean)
Time per request:       12900.048 [ms] (mean)
Time per request:       1.290 [ms] (mean, across all concurrent requests)
Transfer rate:          884.96 [Kbytes/sec] received
并发 总花费时间/s 失败个数 每秒请求(TPS) 总传输 每个请求/ms 传输速率(k/s)
10 12.923 0 773.84 11M 1.292 883.41
100 11.268 0 887.44 11M 1.127 1013
1000 12.815 0 780.33 11M 1.282 890
5000 19.061 0 524.63 11M 1.906 598
10000 12.900 0 775.19 11M 1.290 884
总结

当有数据库操作时TPS在500~800左右,也就是平时我们的代码性能很好的情况下,如果存在数据库操作,单个实例TPS在500~800左右, 并发对TPS有较小影响

测试5000并发过程发生错误 apr_socket_recv: Connection reset by peer (104)


内核会认为系统受到了SYN flood攻击,会发送cookies(possible SYN flooding on port 80. Sending cookies),这样会减慢影响请求的速度,所以在应用服务武器上设置下这个参数为0禁用系统保护就可以进行大并发测试了:

# vim /etc/sysctl.conf 

net.ipv4.tcp_syncookies = 0

# sysctl -p

然后就可以超过5000个并发测试了

Notes 如果高并发出现错误Apache Bench test error on OS X: “apr_socket_recv: Connection reset by peer (54)”,请参考这篇文章 ,如果更新过程出现错误 configure: error: APR not found . Please read the documentation,请参考这篇文章

11 回复

node的性能远不止这么点,socket会消耗文件句柄,每个连接会消耗一些内存,所以你需要研究怎么调整内核参数,还有你如果在同一台机器上跑服务和测试,客户端会消耗端口号,(服务端只需要一个端口,而每个客户端连接都会占用一个端口,我有一次去面试,面试官居然和我争论这个问题,我很坚定的对他说,我敢100%确信你没有做过高并发项目)

@zengming00 在不同的机器上会增加一个变量,网络传输,这个点你怎么看

@zengming00 文件句柄是65535,应该不是瓶颈 image.png

node.js 升级到 12 ,数据库放在别的内网服务器。

@zuohuadong 这个建议挺好

没有对比就没有伤害,你可以试试golang

@ganshiqingyuan 之前对比过 fastify 和 gin ,不过跑的 helloworld ,15% 差距~

@ganshiqingyuan 我用斐波那契函数测试了以下,大概是45次 node:go 12:4.7左右

@TimLiu1 node 单线程,适合io密集型,,计算型的肯定比不上golang,,直接读文件node应该会好点,当然还是比不过golang多核一起干

@ganshiqingyuan 读文件的时候是调用系统的文件读取系统,是多线程操作,node只负责监听读取完成之后的事件和数据

用node 的express 框架写的服务端,现扫描出Slow HTTP Denial of Service Attack漏洞,要怎么弄??

回到顶部