Service Example

Overview

go-zero provides a gRPC server that provides:

  1. Service discovery capability (etcd as registration centre)
  2. Load Balancer(p2c algorithms)
  3. Node Affinity
  4. Multi-node direct connection mode
  5. Timeout processing
  6. Traffic limiting, breaking
  7. Authentication capacity
  8. Exception Capture

Examples

In go-zero, we can use goctl to quickly sound a gRPC service or create an example of a gRPC service using the goctl 0 code.

Service Example - 图1Tips

Quickly generate and start a goctl service example for a gRPC service that can be referenced Quick Start Microservice Book

We’re here to create a full gRPC service with a proto.

1. Create a service directory and initialize the go module project

  1. $ mkdir demo && cd demo
  2. $ go mod init demo

2. 快速生成一个 proto 文件

  1. $ goctl rpc -o greet.proto

3. Proto generate gRPC services

  1. $ goctl rpc protoc greet.proto --go_out=. --go-grpc_out=. --zrpc_out=.

::tip Tips

  1. goctl installation please refer to Goctl Installation
  2. rpc code generation command tutorial reference goctl rpc
  3. Proto use related questions refer to Proto Code Generating FAQ :::

4. Layout

  1. demo
  2. ├── etc
  3. └── greet.yaml
  4. ├── go.mod
  5. ├── greet
  6. ├── greet.pb.go
  7. └── greet_grpc.pb.go
  8. ├── greet.go
  9. ├── greet.proto
  10. ├── greetclient
  11. └── greet.go
  12. └── internal
  13. ├── config
  14. └── config.go
  15. ├── logic
  16. └── pinglogic.go
  17. ├── server
  18. └── greetserver.go
  19. └── svc
  20. └── servicecontext.go
  21. 8 directories, 11 files
Service Example - 图2hint

service directory structure introduction refer to Project Structure

5. Discovery/direct service mode

In go-zero we support the etcd service registration and direct connection mode and we only adjust the static configuration files in the etc directory.

Service Example - 图3hint

gRPC service configuration accessible GRPC Service Configuration

In addition to a go-zero built-in ecd as a service, the community also provides support for the discovery of services such as nacos, consul, etc. More Services found components for details

  • etcd 服务注册
  • 直连模式

To use etcd as a registry, simply add the etcd configuration to the static configuration file, with the following minimal reference configuration (gray underlined section):

demo/etc/greet.yaml

  1. Name: greet.rpc
  2. ListenOn: 0.0.0.0:8080
  3. Etcd:
  4. Hosts:
  5. - 127.0.0.1:2379
  6. Key: greet.rpc

The service is registered with the key greet.rpc, which we can see in etcd by the following method:

  1. $ etcdctl get --prefix greet.rpc
  2. greet.rpc/7587870460981677828
  3. 192.168.72.53:8080

Since the key registered by etcd is greet.rpc, from the business presentation layer, it is a key registered to etcd, but go-zero is actually storing the key with an etcd The go-zero layer is actually storing the key with a tenant id of etcd, so during service discovery, it will also fetch all available ip nodes with the etcdctl get --prefix command.

By contrast, using direct link mode removes the etcd configuration, go-zero auto-identification, with a minimum configuration reference:

demo/etc/greet.yaml

  1. Name: greet.rpc
  2. ListenOn: 0.0.0.0:8080

Stubi implementation

The code generated by goctl does not require the user to implement the stub. The goctl tool will help you to implement all of this, referencing the following:

demo/internal/server/greetserver.go

  1. // Code generated by goctl. DO NOT EDIT.
  2. // Source: greet.proto
  3. package server
  4. import (
  5. "context"
  6. "demo/greet"
  7. "demo/internal/logic"
  8. "demo/internal/svc"
  9. )
  10. type GreetServer struct {
  11. svcCtx *svc.ServiceContext
  12. greet.UnimplementedGreetServer
  13. }
  14. func NewGreetServer(svcCtx *svc.ServiceContext) *GreetServer {
  15. return &GreetServer{
  16. svcCtx: svcCtx,
  17. }
  18. }
  19. func (s *GreetServer) Ping(ctx context.Context, in *greet.Request) (*greet.Response, error) {
  20. l := logic.NewPingLogic(ctx, s.svcCtx)
  21. return l.Ping(in)
  22. }

Writing business code

Once the code is generated with goctl, we simply need to fill in our business code in the log file, reference business code (grey bottom texture part):

demo/internal/logic/pinglogic.go

  1. package logic
  2. import (
  3. "context"
  4. "demo/greet"
  5. "demo/internal/svc"
  6. "github.com/zeromicro/go-zero/core/logx"
  7. )
  8. type PingLogic struct {
  9. ctx context.Context
  10. svcCtx *svc.ServiceContext
  11. logx.Logger
  12. }
  13. func NewPingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PingLogic {
  14. return &PingLogic{
  15. ctx: ctx,
  16. svcCtx: svcCtx,
  17. Logger: logx.WithContext(ctx),
  18. }
  19. }
  20. func (l *PingLogic) Ping(in *greet.Request) (*greet.Response, error) {
  21. return &greet.Response{
  22. Pong: "pong",
  23. }, nil
  24. }

8. Enable gRPC debug switch

gRPC provides debugging capabilities so that we can debug with tools like grpcurl, In go-zero, it is recommended to turn it on in development and test environments, and off in pre-production and official environments,So we configure the environment mode in the static configuration file as dev or test (default is dev environment), the relevant code is as follows:

  • demo/greet.go
  • demo/etc/greet.yaml
  1. package main
  2. ...
  3. func main() {
  4. flag.Parse()
  5. var c config.Config
  6. conf.MustLoad(*configFile, &c)
  7. ctx := svc.NewServiceContext(c)
  8. s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
  9. greet.RegisterGreetServer(grpcServer, server.NewGreetServer(ctx))
  10. if c.Mode == service.DevMode || c.Mode == service.TestMode {
  11. reflection.Register(grpcServer)
  12. }
  13. })
  14. ...
  15. }
  1. Name: greet.rpc
  2. ListenOn: 0.0.0.0:8080
  3. Mode: dev
  4. Etcd:
  5. Hosts:
  6. - 127.0.0.1:2379
  7. Key: greet.rpc

9. Middleware Usage

Built Middleware

go-zero rpc is embedded in a very rich intermediary, seeserverinterceptors

  • StreamAuthorizeInterceptor|UnaryAuthorizeInterceptor
  • StreamBreakerInterceptor|UnaryBreakerInterceptor
  • UnaryPrometheusInterceptor
  • StreamRecoverInterceptor|UnaryRecoverInterceptor
  • UnarySheddingInterceptor
  • UnaryStatInterceptor
  • UnaryTimeoutInterceptor
  • StreamTraceInterceptor|UnaryTraceInterceptor

In the above built-in intermediates, link tracking intermediates, indicator statistical intermediary, time statistical intermediary, abnormal capture medium, melting intermediation can be configured to turn on or off and other intermediates will be enabled by default. Specific configuration can be consultedservice configuration

Custom Middleware

  1. package main
  2. ...
  3. var configFile = flag.String("f", "etc/greet.yaml", "the config file")
  4. func main() {
  5. flag.Parse()
  6. var c config.Config
  7. conf.MustLoad(*configFile, &c)
  8. ctx := svc.NewServiceContext(c)
  9. s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
  10. greet.RegisterGreetServer(grpcServer, server.NewGreetServer(ctx))
  11. if c.Mode == service.DevMode || c.Mode == service.TestMode {
  12. reflection.Register(grpcServer)
  13. }
  14. })
  15. defer s.Stop()
  16. s.AddUnaryInterceptors(exampleUnaryInterceptor)
  17. s.AddStreamInterceptors(exampleStreamInterceptor)
  18. fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
  19. s.Start()
  20. }
  21. func exampleUnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
  22. // TODO: fill your logic here
  23. return handler(ctx, req)
  24. }
  25. func exampleStreamInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
  26. // TODO: fill your logic here
  27. return handler(srv, ss)
  28. }

10. Metadata transfer

Reference Metata