面对着数百G的数据,数万的TPS,一直在找合适的数据库及RPC框架。最近对aerospike和google grpc、apache thrift进行了简单的测试。
测试的内容比较简单,就是客户端根据KEY到服务端进行查找,返回value。为了测试简单,数据库中只有一对key_value。数据库用的aerospike,RPC框架分别用grpc\thrift,客户端、服务端都用GO语言开发。
grpc定义如下:
thrift定义如下:
- namespace go inf
- namespace java inf
- namespace cpp inf
- struct AuthRq {
- 1: string clientId;
- 2: string token;
- }
- struct AuthRp {
- 1: required string token;
- }
- struct DataTypeRq {
- 1: required AuthRq authrq;
- 2: required string groupName;
- 3: required string enName;
- }
- struct DataTypeRp {
- 1: required AuthRp authrp;
- 2: required i64 codeId;
- 3: required string CnName;
- }
- service Data {
- DataTypeRp DataType (1: DataTypeRq dataTypeRq);
- }
服务端与grpc相关代码如下:
@H_502_5@//DataType 将请求参数转化为DataTypeM的请求参数,调用DataTypeM,并将结果返回 func (t *Data) DataType(ctx context.Context,request *inf.DataTypeRq) (response *inf.DataTypeRp,err error) { //log.Printf("App request: %#v",request) // if authRsp,err := t.Auth(ctx,request.AuthRq); err == nil { var req DataTypeReq req.EnName = request.EnName req.GroupName = request.GroupName result,err := dataTypeM(req) response = &inf.DataTypeRp{ AuthRp: &inf.AuthRp{Token: authRsp.Token},CnName: result.CnName,CodeId: result.CodeId,} return response,err // } else { // return nil,err // } }服务端与thrift相关代码如下:
- func (t *Data) DataType(request *inf.DataTypeRq) (response *inf.DataTypeRp,err error) {
- //log.Printf("App request: %#v",err := t.Auth(request.Authrq); err == nil {
- var req DataTypeReq
- req.EnName = request.EnName
- req.GroupName = request.GroupName
- result,err := dataTypeM(req)
- response = inf.NewDataTypeRp()
- response.Authrp.Token = authRsp.Token
- response.CnName = result.CnName
- response.CodeId = result.CodeId
- //log.Printf("DataType response: %#v",response)
- return response,err
- // }
- }
服务端与aerospike相关代码,DataType调用如下函数:
@H_502_5@func dataTypeM(request DataTypeReq) (response DataTypeRsp,err error) { //log.Printf("DataTypeM request: %#v",request) cacheTable := "data_type_def" key := request.GroupName + "|" + request.EnName keys,err := NewKey("test",cacheTable,key) result,err := asClient.Get(nil,keys) if result == nil { for { hostname,_ := os.Hostname() serverId := hostname + strconv.Itoa(os.Getpid()) + strconv.Itoa(time.Now().Nanosecond()) if ok := tdp.DLock(key,serverId); ok { bin1 := NewBin("cnname","语音接通") bin2 := NewBin("code_id",101) asClient.PutBins(nil,keys,bin1,bin2) result,_ = asClient.Get(nil,keys) tdp.UnDLock(key,serverId) break } else { time.Sleep(tryLockSleep * time.Millisecond) result,_ := asClient.Get(nil,keys) if result != nil { break } } } } if result != nil { response.CnName,_ = result.Bins["cnname"].(string) tmp,_ := result.Bins["code_id"].(int) //log.Printf("code_id: %d",tmp) response.CodeId = int64(tmp) } else { log.Printf("can't get result: %#v",request) } return response,err } @H_502_5@func dataType(client inf.DataClient,t string) { var request inf.DataTypeRq var reqAuth inf.AuthRq reqAuth.ClientId = clientId reqAuth.Token = token request.AuthRq = &reqAuth // request.ClientId = clientId // request.Token = "1" request.EnName = "app_call_connect_success" request.GroupName = "USER_EVENT" response,err := client.DataType(context.Background(),&request) //thrift中是: response,err := client.DataType(request) if err == nil { token = response.AuthRp.Token log.Printf("token: %s",response.AuthRp.Token) if response.CodeId != 101 { log.Printf("DataType %#v",response) } } else if err.Error() == "1" { log.Printf("auth failer: %#v",err) } }测试服务器是两台,都是两颗Intel E5 2630 cpu,服务端在A服务器上,192G内存,aerospike和客户端在B服务器上,128G内存;多客户端用goroutine实现。
以下是客户端并发数在50时的截图
grpc:
服务端
客户端
thrift:
服务端
客户端
在整个测试过程中,客户端并发数无论是50,还是800,资源使用情况都相差不大。总体来看,thrift服务端或者客户端,对cpu的使用率偏少,而grpc的使用率偏多,在客户端50时服务端grpc比thrift多使用30%的cpu。
以下是性能测试结果:
从测试来看grpc性能普遍好于thrift,但两者性能相差很小。最好的成绩是好于17%,最差好于3%。不过,grpc刚出来,还处于alpha阶段,所用的protobuf3协议,也处于alpha阶段。相信等正式版后,GPRC的性能会有一个提升的。 另外,从开发的角度看,thrift和grpc协议在使用上相差很小,从学习曲线上来讲,从一方转向另一方是比较容易的。目前grpc-go依赖的第三方包,大部分都在googlecode上,需要越狱获取,很不方便。