golang grpc thrift with aerospike

面对着数百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 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相关代码如下:

//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:
grpc服务端 服务端
grpc客户端 客户端

thrift:
thrift服务端 服务端
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上,需要越狱获取,很不方便。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值