1 grpc中的要点:
1.1 grpc 是什么?
grpc是一个服务器,用于定义服务,指定方法,客户端可以通过他直接调用不同服务器上的方法。轻松创建分布式服务。
1.2 在代码中有什么用?
实现客户端跨语言调用不同服务器服务端的方法
1.3 proto buffers 是什么?
proto buffer 称为协议缓冲区,用于定义结构化数据,并使用编译器,将数据生成指定语言的接口方法,其中包括客户端和服务器代码,还有其他序列化代码;
1.4 proto buffers 如何定义和使用?
结构化定义(定义方法和参数),参考:Protocol Buffers官方文档
由定义生成go代码,使用命令
protoc —go_out=. snowflake.proto
或
protoc —go_out=plugins=grpc:. snowflake.proto
或
protoc -I proto —go_out=plugins=grpc:proto proto/snowflake.proto
其他语言转化
protoc —proto_path=IMPORT_PATH —cpp_out=DST_DIR —java_out=DST_DIR —python_out=DST_DIR path/to/file.proto
2 grpc实战代码:
使用grpc完成GetName接口,从数据持久化到测试。
2.1 数据库持久化层
用于持久化数据库;实现最基础的底层GetName方法。
package serviceimport ("errors""github.com/gitstliu/go-id-worker""imcs/common/config""strconv")var worker *idworker.IdWorker//初始化func init() {workerId := config.GetInt64("snowflake.worker-id")dataCenterId := config.GetInt64("snowflake.data-center-id")worker = &idworker.IdWorker{}if err := worker.InitIdWorker(workerId, dataCenterId); err != nil {panic(err)}}func GetName(mess string) (string, error) {replee := "worker test +++" + messreturn replee, nil}
2.2 业务层
组合底层方法,实现业务功能。
注意:
server中的方法必须同下面proto buffer中定义的GetName方法一致。
package serverimport ("context""errors""imcs/proto""imcs/snowflake/service")//grpc servertype SnowflakeGRPCServer struct {}func (s *SnowflakeGRPCServer) GetName(ctx context.Context, request *proto.SnowflakeRequest) (*proto.SnowflakeResponse, error) {response := new(proto.SnowflakeResponse)if request.Messs != "" {if replee, err := service.GetName(request.Messs); err == nil {response.Replee = replee} else {return nil, err}} else {return nil, errors.New("The count should greater than 0!")}return response, nil}
2.3 proto buffer 转化层
定义客户端接口、服务端接口和代码语言,并完成调用;
syntax = "proto3"; // 最新版,支持多种语言转化option java_package = "cc.iooc.common.rpc.snowflake.proto";option java_multiple_files = true;package proto;service Snowflake { // 定义服务方法rpc GetName (SnowflakeRequest) returns (SnowflakeResponse) {}}//定义参数message SnowflakeRequest {int32 count = 1;string messs = 2;}message SnowflakeResponse {repeated string ids = 1;string replee = 2;}
然后,使用不同的proto buffer 实现接口的语言转化和代码的生成;
操作:在proto文件同级目录下,使用命令
protoc -I proto —go_out=plugins=grpc:proto proto/snowflake.proto
自动生成代码snowflake.pb.go
2.4 客户接口层
动态获取客户,调用转化层的GetName接口;
package clientimport ("context""google.golang.org/grpc""imcs/common/config""imcs/common/log""imcs/common/rpc""imcs/proto")type SnowflakeGRPCClient struct {Address string}func NewSnowflakeGRPCClient() *SnowflakeGRPCClient {return &SnowflakeGRPCClient{Address: config.GetString("grpc.client.snowflake.address")}}func (s *SnowflakeGRPCClient) GetName(mess string) string {// 到grpc连接池获取当前客户的grpc连接conn, err := rpc.GetConn(s.Address)if err != nil {log.Errorf("snowflake client: %v", err)return "nil"}// 方法最后,关闭连接defer rpc.Close(s.Address, conn)response, err := func(conn *grpc.ClientConn) (interface{}, error) {// 调用grpc生成的客户端client := proto.NewSnowflakeClient(conn)// 调用grpc生成的接口及其实现方法// 给proto生成的请求对象(SnowflakeRequest)的属性(Mess)设置值response, err := client.GetName(context.Background(), &proto.SnowflakeRequest{Messs: mess})return response, err}(conn)if err != nil {log.Error(err)return "nil"}// 从生成的相应对象(SnowflakeResponse)中获取属性值(Replee)作为返回值return response.(*proto.SnowflakeResponse).Replee}
2.5 测试层
使用go语言自带的测试类,对客户端获取到的接口进行测试,包括:功能测试、压力测试。
注意:
测试文件的名称和测试方法的名称按规范来,请网上查询。
package clientimport ("fmt""testing")func TestGetName(t *testing.T) {model := NewSnowflakeGRPCClient()fmt.Println(model.GetName("name test ====>"))}
2.6.网关层
用于微服务之间的调用和拦截。
这层可以选配
package serverimport ("context""encoding/json""errors""imcs/common/response""imcs/proto""imcs/snowflake/service")//api servertype SnowflakeApiServer struct {}func (s *SnowflakeApiServer) Request(ctx context.Context, request *proto.GatewayRequest) (*proto.GatewayResponse, error) {resp := new(proto.GatewayResponse)method := request.Methodparams := map[string]interface{}{}err := json.Unmarshal(request.Param, ¶ms)if err != nil {return nil, err}var baseResp *response.BaseResponseswitch method {case "snowflake.id":baseResp, err = id()case "snowflake.ids":baseResp, err = ids(params)case "snowflake.GetName":baseResp, err = GetName(params)default:return nil, errors.New("snowflake method not found")}if err == nil {if respBytes, err := json.Marshal(*baseResp); err == nil {resp.Result = respBytesreturn resp, nil} else {return nil, err}}return nil, err}func GetName(params map[string]interface{}) (r *response.BaseResponse, err error) {countInter := params["mess"]if mess, ok := countInter.(string); ok {if replee, e := service.GetName(mess); e != nil {err = e} else {r = response.NewBaseResponseOkWithData(replee)}} else {err = errors.New("snowflake replee params error")}return}
————————————————
原文链接:https://blog.csdn.net/leinminna/java/article/details/104364612
