图片服务器的Nodejs和Go版本性能测试

关于上一版本

  昨天完成了nodejs版本的图片服务器staticserv
之后,当时没有对请求的类型做判断,这只是我自己使用,如果是做成通用模块,需要考虑防范不合适的请求。之前,
首先考虑的是Go版本的服务器,只不过自己没有弄清go的资源地址都是相对于项目的GOPATH的地址,还是使用老方法
\a\b\c.txt去读取文件,结果都无法读到文件,所以写了nodejs版本。今天学习了path/filepath模块之后,终于掌握
了正确写法。比如要读取”./a/b.txt”,需要这么写:

1
2
absPath:_:=filepath.Abs("./a/b.txt")
bytes,err:=ioutil.ReadFile(absPath)

Go版本的主要功能

  1. 自定义资源文件位置
    主要是通过flag模块解析src参数来实现,比如
    1
    2
    3
    4
    5
    ./serv -src /tmp
    请求URL:
    http://xxx/123.jpg
    最终服务器查找的文件地址:
    /tmp/123.jpg

测试中对于”//“这种错误也能兼容,因为它使用的是Join转化路径,而不是拼接字符串。
关键代码如下:

1
2
relativePath := req.URL.Path
filename, err := filepath.Abs(filepath.Join(*curDir, relativePath))

  1. 判断请求类型
    这部分主要有忽略”favicon.ico”请求、判断路径是否正确和文件是否存在
    1
    2
    3
    4
    //忽略favicon请求:
    if relativePath == "/favicon.ico" {
    return
    }

路径是否正确直接判断上文中的err就好了,这里就不表述。实验时发现请求的是目录,服务
器立马输出错误,然后退出了。这怎么行,一点都不健壮,所以要判断是不是文件:

1
2
3
4
5
6
7
8
9
10
11
12
fileinfo, e := os.Stat(filename)
//文件不存在
if os.IsNotExist(e) {
log.Println(filename, " is not exists.")
res.WriteHeader(404)
return
}
//不是文件,返回500错误
if fileinfo.IsDir() {
res.WriteHeader(500)
return
}

  1. 判断文件类型并读取、发送文据
    判断文件类型主要是为了响应时的content-type,对于不是图片的请求,直接返回了text/plain:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    extname := filepath.Ext(reqfile)
    switch extname {
    case ".jpg", ".jpeg", ".jpe", ".jfif":
    return "image/jpeg"
    case ".png":
    return "image/png"
    case ".ico":
    return "image/x-icon"
    case ".gif":
    return "image/gif"
    case ".tif", ".tiff":
    return "image/jiff"
    default:
    return "text/plain"
    }

发送数据就比较简单了,为了不在传递参数时拷贝,我用了拷贝指针的办法:

1
2
3
4
5
var data []byte
//读取文件
ReadFileFromPath(&data, filename)
res.WriteHeader(200)
res.Write(data)

与上一版本的性能测试对比

这里主要用到了apache的ab工具,以及开源软件webbench。
两者都在同一环境下,均没有做优化。

  1. ab测试,并发请求200,总请求数4000:
    1
    ab -c 200 -n 4000 http://localhost:8080/fact10000.png

测试结果如下:

go 版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

Document Path: /img/fact10000.png
Document Length: 27488 bytes

Concurrency Level: 200
Time taken for tests: 2.493 seconds
Complete requests: 4000
Failed requests: 0
Total transferred: 110276000 bytes
HTML transferred: 109952000 bytes
Requests per second: 1604.80 [#/sec] (mean)
Time per request: 124.626 [ms] (mean)
Time per request: 0.623 [ms] (mean, across all concurrent requests)
Transfer rate: 43205.78 [Kbytes/sec] received //网络传输速度,排除网路问题

/*网络上消耗的时间的分解*/
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 4 39.6 0 1003
Processing: 3 117 143.3 56 1184
Waiting: 2 65 41.9 50 173
Total: 4 121 147.3 57 1184

*下面的内容为整个场景中所有请求的响应情况。在场景中每个请求都有一个响应时间,
其中 50% 的用户响应时间小于 57 毫秒,66 % 的用户响应时间小于 100 毫秒,
最大的响应时间小于 1184 毫秒*/

Percentage of the requests served within a certain time (ms)
50% 57
66% 109
75% 150
80% 157
90% 290
95% 406
98% 583
99% 739
100% 1184 (longest request)

nodejs版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Concurrency Level:      200
Time taken for tests: 3.019 seconds
Complete requests: 4000
Failed requests: 0
Total transferred: 110352000 bytes
HTML transferred: 109952000 bytes
Requests per second: 1325.07 [#/sec] (mean)
Time per request: 150.935 [ms] (mean)
Time per request: 0.755 [ms] (mean, across all concurrent requests)
Transfer rate: 35699.34 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 24 150.8 0 1003
Processing: 67 119 50.4 103 420
Waiting: 67 118 50.3 103 420
Total: 71 143 156.3 105 1116

Percentage of the requests served within a certain time (ms)
50% 105
66% 125
75% 141
80% 145
90% 160
95% 303
98% 1093
99% 1099
100% 1116 (longest request)

二者情况是差不多的,go略微好于nodejs。

  1. 连续3次请求测试平均值,选取用户最关心的三项参数
    go:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Requests per second:    1604.80 [#/sec] (mean)    //吞吐率
    Time per request: 124.626 [ms] (mean) //用户平均请求等待时间
    Time per request: 0.623 [ms] (mean, across all concurrent requests) //服务器平均请求等待时间

    Requests per second: 1627.66 [#/sec] (mean)
    Time per request: 122.876 [ms] (mean)
    Time per request: 0.614 [ms] (mean, across all concurrent requests)

    Requests per second: 1747.35 [#/sec] (mean)
    Time per request: 114.459 [ms] (mean)
    Time per request: 0.572 [ms] (mean, across all concurrent requests)

nodejs:

1
2
3
4
5
6
7
8
9
10
11
Requests per second:    1325.07 [#/sec] (mean)      
Time per request: 150.935 [ms] (mean)
Time per request: 0.755 [ms] (mean, across all concurrent requests)

Requests per second: 1156.69 [#/sec] (mean)
Time per request: 172.908 [ms] (mean)
Time per request: 0.865 [ms] (mean, across all concurrent requests)

Requests per second: 1231.65 [#/sec] (mean)
Time per request: 162.383 [ms] (mean)
Time per request: 0.812 [ms] (mean, across all concurrent requests)

可以看出二者在吞吐率上,Go好于nodejs,平均等待时间上二者相差无几。

  1. webbench 压力测试
    压力测试30秒内,并发请求数200,连续测试3次
    1
    webbench -t 30 -c 200 http://127.0.0.1:8080/img/fact10000.png

go的表现:

1
2
3
4
5
6
7
8
9
Speed=111574 pages/min, 51317124 bytes/sec. //速度,111574页/每分钟,51317124字节/秒
Speed=100538 pages/min, 46228920 bytes/sec.
Speed=103186 pages/min, 47440784 bytes/sec.

资源占用:
VIRT RES SHR CPU MEM TIME
364756 26252 4336 S 61.9 0.0 0:15.26 serv
364884 25960 4044 S 58.7 0.0
364884 25960 4044 R 57.9 0.0

nodejs的表现:

1
2
3
4
5
6
7
8
9
Speed=78864 pages/min, 36259112 bytes/sec.
Speed=42868 pages/min, 19710708 bytes/sec.
Speed=36340 pages/min, 16708262 bytes/sec.

资源占用:
VIRT RES SHR CPU MEM TIME
955320 74196 14252 R 73.6 0.1 0:10.49 node
960768 79408 14252 R 33.2 0.1
961604 79256 14252 R 34.7 0.1

二者都是0错误,可以看出nodejs在速度和资源占用率都比Go表现的差,
速度大概只有go的一半不到,内存占用率却是go的3倍左右,CPU使用率
稍好于go。

总结

从测试里可以看到,Go的http性能是好于nodejs的,不过对于这么
简单的应用,可能无法完全反应Go和nodejs的http性能高低吧,但是go的
http的模块我觉得很好用,写代码也是同步方式,不像nodejs我写到逻辑越来
越复杂的时候就有点越发要好好学一学异步编程的思想,这种思维转换一时还
无法适应,所以我往往选择javascript先完成一部分功能,打开思路后使用Go
去实现。
 另外今天的收获就是学会了做网络测试了,这对我来说又增长了能力。

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 关于上一版本
  2. 2. Go版本的主要功能
  3. 3. 与上一版本的性能测试对比
  4. 4. 总结
,