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:
package main
import (
"github.com/gogf/gf/contrib/registry/etcd/v2"
"github.com/gogf/gf/v2/net/gsvc"
)
func main() {
gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))
// ...
}
Common Components
Component Name | Documentation | Remarks |
---|---|---|
file | https://github.com/gogf/gf/tree/master/contrib/registry/file | Only for single-machine testing |
etcd | https://github.com/gogf/gf/tree/master/contrib/registry/etcd | |
polaris | https://github.com/gogf/gf/tree/master/contrib/registry/polaris | |
zookeeper | https://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
package main
import (
"github.com/gogf/gf/contrib/registry/etcd/v2"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/net/gsvc"
)
func main() {
gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))
s := g.Server(`hello.svc`)
s.BindHandler("/", func(r *ghttp.Request) {
g.Log().Info(r.Context(), `request received`)
r.Response.Write(`Hello world`)
})
s.Run()
}
client.go
package main
import (
"github.com/gogf/gf/contrib/registry/etcd/v2"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/gsvc"
"github.com/gogf/gf/v2/os/gctx"
)
func main() {
gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))
ctx := gctx.New()
res := g.Client().GetContent(ctx, `http://hello.svc/`)
g.Log().Info(ctx, res)
}
After execution, the server output:
$ go run server.go
2023-03-15 20:55:56.256 [INFO] pid[3358]: http server started listening on [:60700]
2023-03-15 20:55:56.256 [INFO] openapi specification is disabled
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]}
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"
SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
hello.svc | default | :60700 | ALL | / | main.main.func1 |
------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
hello.svc | default | :60700 | ALL | /* | github.com/gogf/gf/v2/net/ghttp.internalMiddlewareServerTracing | GLOBAL MIDDLEWARE
------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
2023-03-15 20:56:45.739 [INFO] {880eaa8104994c17ffb384495cd4c613} request received
Client output:
$ go run client.go
2023-03-15 20:56:45.739 [INFO] {880eaa8104994c17ffb384495cd4c613} Hello world
GRPC
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
.
package main
import (
"github.com/gogf/gf/contrib/registry/etcd/v2"
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
"github.com/gogf/gf/example/registry/etcd/grpc/controller"
)
func main() {
grpcx.Resolver.Register(etcd.New("127.0.0.1:2379"))
s := grpcx.Server.New()
controller.Register(s)
s.Run()
}
config.yaml
The default configuration file for the server:
grpc:
name: "demo" # Service name
address: ":8000" # Custom service listening address
logPath: "./log" # Log storage directory path
logStdout: true # Whether the log is output to the terminal
errorLogEnabled: true # Whether to enable error log recording
accessLogEnabled: true # Whether to enable access log recording
errorStack: true # Whether to record the error stack when an error occurs
client.go
package main
import (
"github.com/gogf/gf/contrib/registry/etcd/v2"
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
"github.com/gogf/gf/example/registry/etcd/grpc/protobuf"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
)
func main() {
grpcx.Resolver.Register(etcd.New("127.0.0.1:2379"))
var (
ctx = gctx.New()
conn = grpcx.Client.MustNewGrpcClientConn("demo")
client = protobuf.NewGreeterClient(conn)
)
res, err := client.SayHello(ctx, &protobuf.HelloRequest{Name: "World"})
if err != nil {
g.Log().Error(ctx, err)
return
}
g.Log().Debug(ctx, "Response:", res.Message)
}
After execution, the server output:
$ go run server.go
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]}
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"
2023-03-15 21:06:57.257 [INFO] pid[5786]: grpc server started listening on [:61978]
2023-03-15 21:07:04.955 {08f0aead94994c1731591d2b653ddc18} /protobuf.Greeter/SayHello, 0.002ms, name:"World", message:"Hello World"
Client output:
$ go run client.go
2023-03-15 21:07:04.950 [DEBU] Watch key "/service/default/default/demo/latest/"
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}]
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}]
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:
// Disable the discovery service for the current request via chain operation method
g.Client().Discovery(nil).Get(ctx, "http://192.168.1.1/api/v1/user")
// Disable the discovery service for the current client via configuration method
client := g.Client()
client.SetDiscovery(nil)
client.Get(ctx, "http://192.168.1.1/api/v1/user")