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方法。

  1. package service
  2. import (
  3. "errors"
  4. "github.com/gitstliu/go-id-worker"
  5. "imcs/common/config"
  6. "strconv"
  7. )
  8. var worker *idworker.IdWorker
  9. //初始化
  10. func init() {
  11. workerId := config.GetInt64("snowflake.worker-id")
  12. dataCenterId := config.GetInt64("snowflake.data-center-id")
  13. worker = &idworker.IdWorker{}
  14. if err := worker.InitIdWorker(workerId, dataCenterId); err != nil {
  15. panic(err)
  16. }
  17. }
  18. func GetName(mess string) (string, error) {
  19. replee := "worker test +++" + mess
  20. return replee, nil
  21. }

2.2 业务层

组合底层方法,实现业务功能。
注意:
server中的方法必须同下面proto buffer中定义的GetName方法一致。

  1. package server
  2. import (
  3. "context"
  4. "errors"
  5. "imcs/proto"
  6. "imcs/snowflake/service"
  7. )
  8. //grpc server
  9. type SnowflakeGRPCServer struct {
  10. }
  11. func (s *SnowflakeGRPCServer) GetName(ctx context.Context, request *proto.SnowflakeRequest) (*proto.SnowflakeResponse, error) {
  12. response := new(proto.SnowflakeResponse)
  13. if request.Messs != "" {
  14. if replee, err := service.GetName(request.Messs); err == nil {
  15. response.Replee = replee
  16. } else {
  17. return nil, err
  18. }
  19. } else {
  20. return nil, errors.New("The count should greater than 0!")
  21. }
  22. return response, nil
  23. }

2.3 proto buffer 转化层

定义客户端接口、服务端接口和代码语言,并完成调用;

  1. syntax = "proto3"; // 最新版,支持多种语言转化
  2. option java_package = "cc.iooc.common.rpc.snowflake.proto";
  3. option java_multiple_files = true;
  4. package proto;
  5. service Snowflake { // 定义服务方法
  6. rpc GetName (SnowflakeRequest) returns (SnowflakeResponse) {
  7. }
  8. }
  9. //定义参数
  10. message SnowflakeRequest {
  11. int32 count = 1;
  12. string messs = 2;
  13. }
  14. message SnowflakeResponse {
  15. repeated string ids = 1;
  16. string replee = 2;
  17. }

然后,使用不同的proto buffer 实现接口的语言转化和代码的生成;
操作:在proto文件同级目录下,使用命令
protoc -I proto —go_out=plugins=grpc:proto proto/snowflake.proto
自动生成代码snowflake.pb.go

2.4 客户接口层
动态获取客户,调用转化层的GetName接口;

  1. package client
  2. import (
  3. "context"
  4. "google.golang.org/grpc"
  5. "imcs/common/config"
  6. "imcs/common/log"
  7. "imcs/common/rpc"
  8. "imcs/proto"
  9. )
  10. type SnowflakeGRPCClient struct {
  11. Address string
  12. }
  13. func NewSnowflakeGRPCClient() *SnowflakeGRPCClient {
  14. return &SnowflakeGRPCClient{Address: config.GetString("grpc.client.snowflake.address")}
  15. }
  16. func (s *SnowflakeGRPCClient) GetName(mess string) string {
  17. // 到grpc连接池获取当前客户的grpc连接
  18. conn, err := rpc.GetConn(s.Address)
  19. if err != nil {
  20. log.Errorf("snowflake client: %v", err)
  21. return "nil"
  22. }
  23. // 方法最后,关闭连接
  24. defer rpc.Close(s.Address, conn)
  25. response, err := func(conn *grpc.ClientConn) (interface{}, error) {
  26. // 调用grpc生成的客户端
  27. client := proto.NewSnowflakeClient(conn)
  28. // 调用grpc生成的接口及其实现方法
  29. // 给proto生成的请求对象(SnowflakeRequest)的属性(Mess)设置值
  30. response, err := client.GetName(context.Background(), &proto.SnowflakeRequest{Messs: mess})
  31. return response, err
  32. }(conn)
  33. if err != nil {
  34. log.Error(err)
  35. return "nil"
  36. }
  37. // 从生成的相应对象(SnowflakeResponse)中获取属性值(Replee)作为返回值
  38. return response.(*proto.SnowflakeResponse).Replee
  39. }

2.5 测试层

使用go语言自带的测试类,对客户端获取到的接口进行测试,包括:功能测试、压力测试。
注意:
测试文件的名称和测试方法的名称按规范来,请网上查询。

  1. package client
  2. import (
  3. "fmt"
  4. "testing"
  5. )
  6. func TestGetName(t *testing.T) {
  7. model := NewSnowflakeGRPCClient()
  8. fmt.Println(model.GetName("name test ====>"))
  9. }

2.6.网关层

用于微服务之间的调用和拦截。
这层可以选配

  1. package server
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "imcs/common/response"
  7. "imcs/proto"
  8. "imcs/snowflake/service"
  9. )
  10. //api server
  11. type SnowflakeApiServer struct {
  12. }
  13. func (s *SnowflakeApiServer) Request(ctx context.Context, request *proto.GatewayRequest) (*proto.GatewayResponse, error) {
  14. resp := new(proto.GatewayResponse)
  15. method := request.Method
  16. params := map[string]interface{}{}
  17. err := json.Unmarshal(request.Param, &params)
  18. if err != nil {
  19. return nil, err
  20. }
  21. var baseResp *response.BaseResponse
  22. switch method {
  23. case "snowflake.id":
  24. baseResp, err = id()
  25. case "snowflake.ids":
  26. baseResp, err = ids(params)
  27. case "snowflake.GetName":
  28. baseResp, err = GetName(params)
  29. default:
  30. return nil, errors.New("snowflake method not found")
  31. }
  32. if err == nil {
  33. if respBytes, err := json.Marshal(*baseResp); err == nil {
  34. resp.Result = respBytes
  35. return resp, nil
  36. } else {
  37. return nil, err
  38. }
  39. }
  40. return nil, err
  41. }
  42. func GetName(params map[string]interface{}) (r *response.BaseResponse, err error) {
  43. countInter := params["mess"]
  44. if mess, ok := countInter.(string); ok {
  45. if replee, e := service.GetName(mess); e != nil {
  46. err = e
  47. } else {
  48. r = response.NewBaseResponseOkWithData(replee)
  49. }
  50. } else {
  51. err = errors.New("snowflake replee params error")
  52. }
  53. return
  54. }

————————————————

原文链接:https://blog.csdn.net/leinminna/java/article/details/104364612