Introduction

The GoFrame framework provides service registry and discovery components managed by the gsvc component, which primarily defines the interface for registry and discovery. The specific implementation is provided by community components: https://github.com/gogf/gf/tree/master/contrib/registry. Currently, community components offer multiple implementations for registry and discovery, such as etcd, zookeeper, polaris, etc. Developers can use them interchangeably as needed or implement their own registry and discovery components according to the API definition of the gsvc component.

Component Activation

The registry and discovery components are activated only when a specific interface implementation is introduced. For example, using etcd to implement registry and discovery:

  1. package main
  2. import (
  3. "github.com/gogf/gf/contrib/registry/etcd/v2"
  4. "github.com/gogf/gf/v2/net/gsvc"
  5. )
  6. func main() {
  7. gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))
  8. // ...
  9. }

Common Components

Component NameDocumentationRemarks
filehttps://github.com/gogf/gf/tree/master/contrib/registry/fileOnly for single-machine testing
etcdhttps://github.com/gogf/gf/tree/master/contrib/registry/etcd
polarishttps://github.com/gogf/gf/tree/master/contrib/registry/polaris
zookeeperhttps://github.com/gogf/gf/tree/master/contrib/registry/zookeeper

For more components, refer to: https://github.com/gogf/gf/tree/master/contrib/registry

Usage Example

HTTP

You can use gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`)) to set the registry and discovery with etcd. The etcd.New in this case denotes creating an interface implementation object of gsvc.Registry through a community component, and setting the global default registry and discovery interface implementation object via the gsvc.SetRegistry method.

server.go

  1. package main
  2. import (
  3. "github.com/gogf/gf/contrib/registry/etcd/v2"
  4. "github.com/gogf/gf/v2/frame/g"
  5. "github.com/gogf/gf/v2/net/ghttp"
  6. "github.com/gogf/gf/v2/net/gsvc"
  7. )
  8. func main() {
  9. gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))
  10. s := g.Server(`hello.svc`)
  11. s.BindHandler("/", func(r *ghttp.Request) {
  12. g.Log().Info(r.Context(), `request received`)
  13. r.Response.Write(`Hello world`)
  14. })
  15. s.Run()
  16. }

client.go

  1. package main
  2. import (
  3. "github.com/gogf/gf/contrib/registry/etcd/v2"
  4. "github.com/gogf/gf/v2/frame/g"
  5. "github.com/gogf/gf/v2/net/gsvc"
  6. "github.com/gogf/gf/v2/os/gctx"
  7. )
  8. func main() {
  9. gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))
  10. ctx := gctx.New()
  11. res := g.Client().GetContent(ctx, `http://hello.svc/`)
  12. g.Log().Info(ctx, res)
  13. }

After execution, the server output:

  1. $ go run server.go
  2. 2023-03-15 20:55:56.256 [INFO] pid[3358]: http server started listening on [:60700]
  3. 2023-03-15 20:55:56.256 [INFO] openapi specification is disabled
  4. 2023-03-15 20:55:56.256 [DEBU] service register: &{Head: Deployment: Namespace: Name:hello.svc Version: Endpoints:10.35.12.81:60700 Metadata:map[insecure:true protocol:http]}
  5. 2023-03-15 20:55:56.297 [DEBU] etcd put success with key "/service/default/default/hello.svc/latest/10.35.12.81:60700", value "{"insecure":true,"protocol":"http"}", lease "7587869265945813002"
  6. SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
  7. ------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
  8. hello.svc | default | :60700 | ALL | / | main.main.func1 |
  9. ------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
  10. hello.svc | default | :60700 | ALL | /* | github.com/gogf/gf/v2/net/ghttp.internalMiddlewareServerTracing | GLOBAL MIDDLEWARE
  11. ------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
  12. 2023-03-15 20:56:45.739 [INFO] {880eaa8104994c17ffb384495cd4c613} request received

Client output:

  1. $ go run client.go
  2. 2023-03-15 20:56:45.739 [INFO] {880eaa8104994c17ffb384495cd4c613} Hello world

GRPC

Service Registry and Discovery - 图1warning

For the GRPC protocol, you must use the grpcx.Resolver module from grpcx to set the service registry and discovery component. On the Server side, if the grpc.name value is not set in the config.yaml, the default value is default.

server.go

In the code, etcd.New denotes creating an interface implementation object of gsvc.Registry through a community component, and setting the global grpc registry and discovery interface implementation object via grpcx.Resolver.Register.

  1. package main
  2. import (
  3. "github.com/gogf/gf/contrib/registry/etcd/v2"
  4. "github.com/gogf/gf/contrib/rpc/grpcx/v2"
  5. "github.com/gogf/gf/example/registry/etcd/grpc/controller"
  6. )
  7. func main() {
  8. grpcx.Resolver.Register(etcd.New("127.0.0.1:2379"))
  9. s := grpcx.Server.New()
  10. controller.Register(s)
  11. s.Run()
  12. }

config.yaml

The default configuration file for the server:

  1. grpc:
  2. name: "demo" # Service name
  3. address: ":8000" # Custom service listening address
  4. logPath: "./log" # Log storage directory path
  5. logStdout: true # Whether the log is output to the terminal
  6. errorLogEnabled: true # Whether to enable error log recording
  7. accessLogEnabled: true # Whether to enable access log recording
  8. errorStack: true # Whether to record the error stack when an error occurs

client.go

  1. package main
  2. import (
  3. "github.com/gogf/gf/contrib/registry/etcd/v2"
  4. "github.com/gogf/gf/contrib/rpc/grpcx/v2"
  5. "github.com/gogf/gf/example/registry/etcd/grpc/protobuf"
  6. "github.com/gogf/gf/v2/frame/g"
  7. "github.com/gogf/gf/v2/os/gctx"
  8. )
  9. func main() {
  10. grpcx.Resolver.Register(etcd.New("127.0.0.1:2379"))
  11. var (
  12. ctx = gctx.New()
  13. conn = grpcx.Client.MustNewGrpcClientConn("demo")
  14. client = protobuf.NewGreeterClient(conn)
  15. )
  16. res, err := client.SayHello(ctx, &protobuf.HelloRequest{Name: "World"})
  17. if err != nil {
  18. g.Log().Error(ctx, err)
  19. return
  20. }
  21. g.Log().Debug(ctx, "Response:", res.Message)
  22. }

After execution, the server output:

  1. $ go run server.go
  2. 2023-03-15 21:06:57.204 [DEBU] service register: &{Head: Deployment: Namespace: Name:demo Version: Endpoints:10.35.12.81:61978 Metadata:map[protocol:grpc]}
  3. 2023-03-15 21:06:57.257 [DEBU] etcd put success with key "/service/default/default/demo/latest/10.35.12.81:61978", value "{"protocol":"grpc"}", lease "7587869265945813015"
  4. 2023-03-15 21:06:57.257 [INFO] pid[5786]: grpc server started listening on [:61978]
  5. 2023-03-15 21:07:04.955 {08f0aead94994c1731591d2b653ddc18} /protobuf.Greeter/SayHello, 0.002ms, name:"World", message:"Hello World"

Client output:

  1. $ go run client.go
  2. 2023-03-15 21:07:04.950 [DEBU] Watch key "/service/default/default/demo/latest/"
  3. 2023-03-15 21:07:04.952 [DEBU] client conn updated with addresses [{"Addr":"10.35.12.81:61978","ServerName":"demo","Attributes":{},"BalancerAttributes":null,"Type":0,"Metadata":null}]
  4. 2023-03-15 21:07:04.953 [DEBU] client conn updated with addresses [{"Addr":"10.35.12.81:61978","ServerName":"demo","Attributes":{},"BalancerAttributes":null,"Type":0,"Metadata":null}]
  5. 2023-03-15 21:07:04.955 [DEBU] {08f0aead94994c1731591d2b653ddc18} Response: Hello World

Frequently Asked Questions

How to disable the discovery feature for specific requests when globally enabling the service registry and discovery

Question: When using gclient, if the service registry and discovery feature are globally enabled, all requests from gclient will go through the discovery service. However, for services that are not maintained in the service registry and discovery, such as a request to an IP:PORT address or an external network service request, it will also go through the discovery service, resulting in a service not found error. How can this be avoided?

Answer: When globally enabling the discovery feature, gclient requests will by default use the globally set discovery service. If a specific request does not use the discovery service, you can disable the discovery service for the current request using the Discovery(nil) chain operation method of gclient.Client or disable the discovery service for the current client using the SetDiscovery(nil) configuration method. This way, the request will not go through the discovery service.

Example:

  1. // Disable the discovery service for the current request via chain operation method
  2. g.Client().Discovery(nil).Get(ctx, "http://192.168.1.1/api/v1/user")
  3. // Disable the discovery service for the current client via configuration method
  4. client := g.Client()
  5. client.SetDiscovery(nil)
  6. client.Get(ctx, "http://192.168.1.1/api/v1/user")