Detailed benchmark for grpc-go and thrift-go
Benchmark for grpc-go and thrift-go
Machines
Two with same configuration, one for client, one for server
Comparison
Work Pattern
Thrift-go and gRPC-go hava a same backend work pattern, one goroutine for each connection.
func (p *TSimpleServer) AcceptLoop() error {
for {
client, err := p.serverTransport.Accept()
if err != nil {
... ...
return err
}
if client != nil {
p.Add(1)
go func() {
if err := p.processRequests(client); err != nil {
log.Println("error processing request:", err)
}
}()
}
}
}
func (p *TSimpleServer) Serve() error {
err := p.Listen()
if err != nil {
return err
}
p.AcceptLoop()
return nil
}
// Serve accepts incoming connections on the listener lis, creating a new
// ServerTransport and service goroutine for each. The service goroutines
// read gRPC requests and then call the registered handlers to reply to them.
func (s *Server) Serve(lis net.Listener) error {
... ...
for {
rawConn, err := lis.Accept()
if err != nil {
... ...
}
tempDelay = 0
// Start a new goroutine to deal with rawConn
// so we don't stall this Accept loop goroutine.
go s.handleRawConn(rawConn)
}
}
Protocal
syntax = "proto3";
package main;
service Hello {
// Sends a greeting
rpc Say (BenchmarkMessage) returns (BenchmarkMessage) {}
}
message BenchmarkMessage {
string field1 = 1;
string field9 = 9;
string field18 = 18;
bool field80 = 80 ;
bool field81 = 81 ;
int32 field2 = 2;
int32 field3 = 3;
int32 field280 = 280;
int32 field6 = 6 ;
int64 field22 = 22;
string field4 = 4;
repeated fixed64 field5 = 5;
bool field59 = 59 ;
string field7 = 7;
int32 field16 = 16;
int32 field130 = 130 ;
bool field12 = 12 ;
bool field17 = 17 ;
bool field13 = 13 ;
bool field14 = 14 ;
int32 field104 = 104 ;
int32 field100 = 100 ;
int32 field101 = 101 ;
string field102 = 102;
string field103 = 103;
int32 field29 = 29 ;
bool field30 = 30 ;
int32 field60 = 60 ;
int32 field271 = 271 ;
int32 field272 = 272 ;
int32 field150 = 150;
int32 field23 = 23 ;
bool field24 = 24 ;
int32 field25 = 25 ;
bool field78 = 78;
int32 field67 = 67 ;
int32 field68 = 68;
int32 field128 = 128 ;
string field129 = 129 ;
int32 field131 = 131 ;
}
namespace go main
struct BenchmarkMessage
{
1: string field1,
2: i32 field2,
3: i32 field3,
4: string field4,
5: i64 field5,
6: i32 field6,
7: string field7,
9: string field9,
12: bool field12,
13: bool field13,
14: bool field14,
16: i32 field16,
17: bool field17,
18: string field18,
22: i64 field22,
23: i32 field23,
24: bool field24,
25: i32 field25,
29: i32 field29,
30: bool field30,
59: bool field59,
60: i32 field60,
67: i32 field67,
68: i32 field68,
78: bool field78,
80: bool field80,
81: bool field81,
100: i32 field100,
101: i32 field101,
102: string field102,
103: string field103,
104: i32 field104,
128: i32 field128,
129: string field129,
130: i32 field130,
131: i32 field131,
150: i32 field150,
271: i32 field271,
272: i32 field272,
280: i32 field280,
}
service Greeter {
BenchmarkMessage say(1:BenchmarkMessage name);
}
Benchmark
All RPCs are successful below.
clients | Latency(median) | Latency(mean) | Latency(P99) | Latency(max) | QPS | CPU |
---|---|---|---|---|---|---|
100 | 0 | 1ms | 8ms | 200ms | 95k | 2000% |
1000 | 2ms | 7ms | 400ms | 2s | 130k | 2000% |
5000 | 5ms | 35ms | 800ms | 20s | 130k | 2000% |
10000 | 8ms | 65ms | 1.6s | 30s | 100k | 2000% |
clients | Latency(median) | Latency(mean) | Latency(P99) | Latency(max) | QPS | CPU |
---|---|---|---|---|---|---|
10 | 1ms | 1ms | 4ms | 41ms | 6k | 600% |
50 | 4ms | 4ms | 16ms | 1s | 10k | 2000% |
100 | 4ms | 6ms | 1s | 3s | 13k | 2700% |
clients | Latency(median) | Latency(mean) | Latency(P99) | Latency(max) | QPS | CPU |
---|---|---|---|---|---|---|
100 | 0 | 1ms | 4ms | 40ms | 100k | 1200% |
1000 | 5ms | 7ms | 220ms | 3s | 120k | 1200% |
5000 | 11ms | 37ms | 900ms | 25s | 110k | 1200% |
10000 | 13ms | 73ms | 1.7s | 54s | 90k | 1200% |
clients | Latency(median) | Latency(mean) | Latency(P99) | Latency(max) | QPS | CPU |
---|---|---|---|---|---|---|
10 | 0 | 0 | 2ms | 27ms | 12k | 300% |
50 | 0 | 1ms | 13ms | 200ms | 28k | 1400% |
100 | 0 | 1ms | 200ms | 210ms | 31k | 1600% |
Conclusion
grpc: addrConn.resetTransport failed to create client transport: connection error: desc = "transport: dial tcp: getsockopt: connection refused"
Thanks
Inspired by and thanks to rpcx-ecosystem/rpcx-benchmark.