在学完Golang语言HTTP客户端实践、Go语言HTTPServer开发的六种实现之后,我自然开始了Java&Go两种语言的HTTP客户端性能测试。
之前在写10万QPS,K6、Gatling和FunTester终极对决!这个文章以及单机12万QPS——FunTester复仇记的时候,都是把CPU跑满了,为了达到12万QPS,我把所有除了统计以外的代码都删除了,这次就不搞这么极端了。而且在我自己初测的时候发现笔记本电脑最多只能跑到80%CPU,不知道是不是macOS限制了,再说消耗自己电脑,我也是心疼。
服务端
服务端依旧采取moco_FunTester
框架的moco服务,代码如下:
class Share extends MocoServer {
static void main(String[] args) {
def util = new ArgsUtil(args)
def server = getServerNoLog(util.getIntOrdefault(0,12345))
server.response("Have Fun ~ Tester !")
// server.response(delay(textRes("Have Fun ~ Tester !"),10))
def run = run(server)
waitForKey("fan")
run.stop()
}
}
本次测试两种服务状态,一种无延迟HTTP服务,另外一种是低延迟(5ms以及10ms),总计三种HTTP服务。由于Go语言HTTP的库自带了HTTP服务开发功能,后面我会再写一篇文章,对比一下三种HTTP服务的性能:Java netty、Go(net/http)以及Go(/valyala/fasthttp)。
测试用例
FunTester
FunTester测试框架用的是Java HttpClient,对HttpClient API做了封装,然后配合FunTester性能测试框架完成本次测试。实测中封装和框架对性能影响可忽略。
代码语言:javascript复制class HttpClientTest extends FunLibrary {
static final String uri = "http://localhost:12345/test/fun"
static final HttpRequestBase get = FunLibrary.getHttpGet(uri)
static final int thread = 10
static final int times = 10000
public static void main(String[] args) {
RUNUP_TIME = 0
def tester = new FunTester()
new Concurrent(tester, thread, DEFAULT_STRING).start()
}
private static class FunTester extends FixedThread<HttpRequestBase> {
FunTester() {
super(get, times, true)
}
@Override
protected void doing() throws Exception {
FunLibrary.executeOnly(get)
}
@Override
FixedThread clone() {
return new FunTester()
}
}
}
Go(net/http)
这里我写了一个测试方法,使用了Go语言的协程和chan知识点,比较粗糙,但能用。代码时有改动,后台回复git可以获取多个项目的git仓库地址,包含本项目。
代码语言:javascript复制var key bool = false
const (
url = "http://localhost:8001/test/fun"
thread = 20
times = 10000
)
func TestPer(t *testing.T) {
get := funtester.Get(url, nil)
c := make(chan int)
start := time.Now().UnixMilli()
for i := 0; i < thread; i {
go func() {
sum := 0
for i := 0; i < times; i {
if key {
break
}
funtester.Response(get)
sum
}
key = true
c <- sum
}()
}
total := 0
for i := 0; i < thread; i {
num := <-c
total = num
}
end := time.Now().UnixMilli()
diff := end - start
log.Printf("总耗时: %f", float64(diff)/1000)
log.Printf("请求总数: %d", total)
log.Printf("QPS: %f", float64(total)/float64(diff)*1000.0)
}
Go(/valyala/fasthttp)
与net/http类似,不同之处是/valyala/fasthttp无法使用同一个对象进行压测。所以每次都要创建一个对象,但是实测居然效率更高,fasthttp对象池果然牛。而且传说中10倍于net/http,着实有点吹牛了。
代码语言:javascript复制var key bool = false
const (
url = "http://localhost:8001/test/fun"
thread = 20
times = 10000
)
func TestPerFast(t *testing.T) {
c := make(chan int)
start := time.Now().UnixMilli()
for i := 0; i < thread; i {
go func() {
sum := 0
for i := 0; i < times; i {
if key {
break
}
get := funtester.FastGet(url, nil)
funtester.FastResponse(get)
sum
}
key = true
c <- sum
}()
}
total := 0
for i := 0; i < thread; i {
num := <-c
total = num
}
end := time.Now().UnixMilli()
diff := end - start
//total := thread * times
log.Printf("总耗时: %f", float64(diff)/1000)
log.Printf("请求总数: %d", total)
log.Printf("QPS: %f", float64(total)/float64(diff)*1000.0)
}
测试
无延迟服务
1线程
框架 | CPU | 内存 | QPS |
---|---|---|---|
FunTester | 51.04 | 354.9 MB | 17715 |
Go(net/http) | 104.26 | 14.8 MB | 13120 |
Go(/valyala/fasthttp) | 81.67 | 5.3 MB | 20255 |
5线程
框架 | CPU | 内存 | QPS |
---|---|---|---|
FunTester | 230.08 | 555.5 MB | 59626 |
Go(net/http) | 323.45 | 14.9 MB | 43143 |
Go(/valyala/fasthttp) | 215.73 | 6.4 MB | 68659 |
10线程
框架 | CPU | 内存 | QPS |
---|---|---|---|
FunTester | 356.43 | 685.2 MB | 81795 |
Go(net/http) | 573.08 | 1.36 GB | 36431 |
Go(/valyala/fasthttp) | 321.85 | 6.8 MB | 82093 |
截止到此,CPU已经基本满荷运行,实际80%,不知道是不是macOS的限制,现在CPU只能跑到80%左右。
实际测试结果非常明显,总体CPU指标,FunTester
和/valyala/fasthttp
相差不多,/valyala/fasthttp
在CPU方面有些许优势,但是在内存上,简直无法理解。见鬼了一样。相比之下net/http逊色很多,在低并发的时候除了内存表现较好意外,CPU和QPS均低于FunTester
和/valyala/fasthttp
,但是在10线程的情况下,CPU跑满,内存直线飙升,着实无法理解。等我再深入学习之后,估计能明白这个问题了。
延迟5ms服务
10线程
框架 | CPU | 内存 | QPS |
---|---|---|---|
FunTester | 19.63 | 163.9 MB | 1671 |
Go(net/http) | 31.18 | 14.2 MB | 1440 |
Go(/valyala/fasthttp) | 15.63 | 6.8 MB | 1709 |
20线程
框架 | CPU | 内存 | QPS |
---|---|---|---|
FunTester | 36.88 | 235.3 MB | 3318 |
Go(net/http) | 48.47 | 14.4 MB | 2400 |
Go(/valyala/fasthttp) | 32.81 | 7.5 MB | 3339 |
结论跟无延迟服务差不多。总体讲/valyala/fasthttp
> FunTester
> net/http
。即使Go语言加成,net/http
除了内存以外,其他两项指标均不如Java写的FunTester。
结论
/valyala/fasthttp
真心牛逼,建议使用Go语言进行HTTP性能测试的,直接跳过net/http
。
PS:下一次我将测试三种HTTP服务端的性能,敬请期待。