這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
面對著數百G的資料,數萬的TPS,一直在找合適的資料庫及RPC架構。最近對aerospike和google grpc、apache thrift進行了簡單的測試。
測試的內容比較簡單,就是用戶端根據KEY到服務端進行尋找,返回value。為了測試簡單,資料庫中只有一對key_value。資料庫用的aerospike,RPC架構分別用grpc\thrift,用戶端、服務端都用GO語言開發。
grpc定義如下:
syntax = "proto3";package inf;message AuthRq { string clientId = 1; string token = 2;}message AuthRp { string token = 1;}message DataTypeRq { AuthRq authRq = 1; string groupName = 101; string enName = 102;}message DataTypeRp { AuthRp authRp = 1; int64 codeId = 101; string cnName = 102;}service Data { rpc DataType (DataTypeRq) returns (DataTypeRp){};}
thrift定義如下:
namespace go infnamespace java infnamespace cpp infstruct 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相關代碼如下:
//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", request) // if authRsp, 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 // } else { // return nil, err // }}
服務端與aerospike相關代碼,DataType調用如下函數:
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}
用戶端代碼如下,與RPC架構無關的代碼完全一樣:
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上,需要越獄擷取,很不方便。
著作權聲明:歡迎轉載。