go-kit 微服务 使用Grpc(并传递请求ID)

grpc

  • gRPC是一个高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发
  • grpc使用 案例

简介

  • 通过grpc实现一个用户中心实现简单的鉴权中心并返回用户token
  • 上篇文章《go-kit 微服务 身份认证(JWT)》已经实现的一个http的鉴权中心,所以我们只需要改变transport层逻辑
  • 编写ProtoBuf
//service.proto
syntax = "proto3";
package pb;
import "user.proto";
service User {
    rpc RpcUserLogin (Login) returns (LoginAck) {
    }
}
//user.proto
message Login {
    string Account = 1;
    string Password = 2;
}
message LoginAck {
    string Token = 1;
}
  • 编译ProtoBuf
protoc --go_out=plugins=grpc:. *.proto

transport层修改

  • 定义grpcServer结构体
type grpcServer struct {
	login grpctransport.Handler
}
  • 实现RpcUserLogin接口
func (s *grpcServer) RpcUserLogin(ctx context.Context, req *pb.Login) (*pb.LoginAck, error) {
	_, rep, err := s.login.ServeGRPC(ctx, req)
	if err != nil {
		return nil, err
	}
	return rep.(*pb.LoginAck), nil
}
  • 将endpoint的方法加载到grpcServer对象中
func NewGRPCServer(endpoint v5_endpoint.EndPointServer, log *zap.Logger) pb.UserServer {
	options := []grpctransport.ServerOption{
		grpctransport.ServerBefore(func(ctx context.Context, md metadata.MD) context.Context {
			ctx = context.WithValue(ctx, v5_service.ContextReqUUid, md.Get(v5_service.ContextReqUUid))
			return ctx
		}),
		grpctransport.ServerErrorHandler(NewZapLogErrorHandler(log)),
	}
	return &grpcServer{login: grpctransport.NewServer(
		endpoint.LoginEndPoint,
		RequestGrpcLogin,
		ResponseGrpcLogin,
		options...,
	)}
}

修改main方法

	utils.NewLoggerServer()
	golangLimit := rate.NewLimiter(10, 1)
	server := v5_service.NewService(utils.GetLogger())
	endpoints := v5_endpoint.NewEndPointServer(server, utils.GetLogger(), golangLimit)
	grpcServer := v5_transport.NewGRPCServer(endpoints, utils.GetLogger())
	utils.GetLogger().Info("server run :8881")
	grpcListener, err := net.Listen("tcp", ":8881")
	if err != nil {
		utils.GetLogger().Warn("Listen", zap.Error(err))
		os.Exit(0)
	}
	baseServer := grpc.NewServer(grpc.UnaryInterceptor(grpctransport.Interceptor))
	pb.RegisterUserServer(baseServer, grpcServer)
	if err = baseServer.Serve(grpcListener); err != nil {
		utils.GetLogger().Warn("Serve", zap.Error(err))
		os.Exit(0)
	}

编写客户端

  • go-kit 客户端
func NewGRPCClient(conn *grpc.ClientConn, log *zap.Logger) v5_service.Service {
	options := []grpctransport.ClientOption{
		grpctransport.ClientBefore(func(ctx context.Context, md *metadata.MD) context.Context {
			UUID := uuid.NewV5(uuid.Must(uuid.NewV4()), "req_uuid").String()
			log.Debug("给请求添加uuid", zap.Any("UUID", UUID))
			md.Set(v5_service.ContextReqUUid, UUID)
			ctx = metadata.NewOutgoingContext(context.Background(), *md)
			return ctx
		}),
	}
	var loginEndpoint endpoint.Endpoint
	{
		loginEndpoint = grpctransport.NewClient(
			conn,
			"pb.User",
			"RpcUserLogin",
			RequestLogin,
			ResponseLogin,
			pb.LoginAck{},
			options...).Endpoint()
	}
	return v5_endpoint.EndPointServer{
		LoginEndPoint: loginEndpoint,
	}
}
func RequestLogin(_ context.Context, request interface{}) (interface{}, error) {
	req := request.(*pb.Login)
	return &pb.Login{Account: req.Account, Password: req.Password}, nil
}
func ResponseLogin(_ context.Context, response interface{}) (interface{}, error) {
	resp := response.(*pb.LoginAck)
	return &pb.LoginAck{Token: resp.Token}, nil
}
  • go-kit 客户端 调用方法
logger := logtool.NewLogger(
		logtool.SetAppName("go-kit"),
		logtool.SetDevelopment(true),
		logtool.SetLevel(zap.DebugLevel),
	)
	conn, err := grpc.Dial("127.0.0.1:8881", grpc.WithInsecure())
	if err != nil {
		t.Error(err)
		return
	}
	defer conn.Close()
	svr := NewGRPCClient(conn, logger)
	ack, err := svr.Login(context.Background(), &pb.Login{
		Account:  "hwholiday",
		Password: "123456",
	})
	if err != nil {
		t.Error(err)
		return
	}
	t.Log(ack.Token)
  • grpc原生客户端
	serviceAddress := "127.0.0.1:8881"
	conn, err := grpc.Dial(serviceAddress, grpc.WithInsecure())
	if err != nil {
		panic("connect error")
	}
	defer conn.Close()
	userClient := pb.NewUserClient(conn)
	UUID := uuid.NewV5(uuid.Must(uuid.NewV4()), "req_uuid").String()
	md := metadata.Pairs( v5_service.ContextReqUUid, UUID)
	ctx := metadata.NewOutgoingContext(context.Background(), md)
	res, err := userClient.RpcUserLogin(ctx, &pb.Login{
		Account:  "hw",
		Password: "123",
	})
	if err != nil {
		t.Error(err)
		return
	}
	t.Log(res.Token)

传递客户端请求ID到服务端代码

  • 客户端
......
UUID := uuid.NewV5(uuid.Must(uuid.NewV4()), "req_uuid").String()
log.Debug("给请求添加uuid", zap.Any("UUID", UUID))
md.Set(v5_service.ContextReqUUid, UUID)
ctx = metadata.NewOutgoingContext(context.Background(), *md)
......
  • 服务端
......
ctx = context.WithValue(ctx, v5_service.ContextReqUUid, md.Get(v5_service.ContextReqUUid))
......

运行日志


//客户端
2020-01-07 15:42:24	INFO	logtool/log.go:89	[NewLogger] success
2020-01-07 15:42:24	DEBUG	client/client.go:20	给请求添加uuid	{"UUID": "a8360f58-6f0d-588f-83c9-b3dc00fe60f6"}
--- PASS: TestGrpcClient (0.00s)
    grpc_test.go:36: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJOYW1lIjoiaHdob2xpZGF5IiwiRGNJZCI6MSwiZXhwIjoxNTc4MzgyOTc0LCJpYXQiOjE1NzgzODI5NDQsImlzcyI6ImtpdF92NCIsIm5iZiI6MTU3ODM4Mjk0NCwic3ViIjoibG9naW4ifQ.PSd1mWjfePR0IP3cw8gF9yN3IaNQDt9TaDpSk4QzUDc
PASS


//服务端
2020-01-07 15:42:16     INFO    logtool/log.go:89       [NewLogger] success
2020-01-07 15:42:16     INFO    v5_user/main.go:23      server run :8881
2020-01-07 15:42:24     DEBUG   v5_service/service.go:28        [a8360f58-6f0d-588f-83c9-b3dc00fe60f6]  {"调用 v5_service rvice": "Login 处理请求"}
2020-01-07 15:42:24     DEBUG   v5_service/service.go:35        [a8360f58-6f0d-588f-83c9-b3dc00fe60f6]  {"调用 v5_service rvice": "Login 处理请求", "处理返回值": "Token:\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJOYW1lIjoiaHdob2xpZGF5IiwiRGNJZCI6joxNTc4MzgyOTc0LCJpYXQiOjE1NzgzODI5NDQsImlzcyI6ImtpdF92NCIsIm5iZiI6MTU3ODM4Mjk0NCwic3ViIjoibG9naW4ifQ.PSd1mWjfePR0IP3cw8gF9yN3IaNQDt9TaDpSk4QzUDc\" "}
2020-01-07 15:42:24     DEBUG   v5_service/middleware.go:31     [a8360f58-6f0d-588f-83c9-b3dc00fe60f6]  {"调用 Login logMilewareServer": "Login", "req": "Account:\"hwholiday\" Password:\"123456\" ", "res": "Token:\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJOYW1lIjoiaHdob2xpZGF5IiwiRGNJZCI6MSwiZXhwIjoxNTc4MzgyOTc0LCJpYXQiOjE1NzgzODI5NDQsImlzcyI6ImtpdF92NCIsIm5iZiI6MTU3ODM4Mjk0NCwic3ViIjoibG9naW4ifQ.PSd1mWjfePR0IP3cw8gF9yN3IaNQDt9TaDpSk4QzUDc\" ", "err": null}
2020-01-07 15:42:24     DEBUG   v5_endpoint/middleware.go:18    [a8360f58-6f0d-588f-83c9-b3dc00fe60f6]  {"调用 v4_endpointoggingMiddleware": "处理完请求", "耗时毫秒": 0}

结语

  • 这里只实现了一个煎蛋的grpc在go-kit的使用场景
  • 欢迎添加QQ一起讨论

完整代码地址

联系 QQ: 3355168235