Go 語言微服務框架 Kratos 服務注冊與發(fā)現(xiàn)
1.介紹
Go 語言微服務框架 Kratos 服務注冊與發(fā)現(xiàn),支持多種注冊中心,本文我們以 Consul 為例,介紹 Kratos 項目怎么實現(xiàn)服務注冊與發(fā)現(xiàn)。
以 blog 項目作為 RPC 服務端,我們再創(chuàng)建一個 blog-client 項目作為 RPC 客戶端。
2.服務注冊
我們通過改造 blog 項目的代碼,將 blog 服務作為 RPC 服務端,注冊到 Consul 中。
創(chuàng)建 Consul 注冊中心
在 blog/internal 目錄中,創(chuàng)建 registry 目錄,并創(chuàng)建 consul.go 和 registry.go 文件。
編寫 blog/internal/registry/consul.go 文件。
func NewConsulRegistry(c *conf.Registry) *consul.Registry {
client, err := api.NewClient(&api.Config{
Address: c.Consul.Addr,
Scheme: c.Consul.Schema,
})
if err != nil {
panic(err)
}
return consul.New(client)
}
編寫 blog/internal/registry/registry.go 文件。
var ProviderSet = wire.NewSet(NewConsulRegistry)
編寫 blog/cmd/blog/wire.go 文件。
func wireApp(*conf.Server, *conf.Data, *conf.Registry, log.Logger) (*kratos.App, func(), error) {
panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, registry.ProviderSet, newApp))
}
wire 生成文件
cd /root/go/src/blog/cmd/blog
wire
編寫 blog/cmd/blog/main.go 文件。
func newApp(conf *conf.Server, logger log.Logger, gs *grpc.Server, hs *http.Server, registry *consul.Registry) *kratos.App {
return kratos.New(
kratos.ID(id),
kratos.Name(conf.Name),
kratos.Version(conf.Version),
kratos.Metadata(map[string]string{}),
kratos.Logger(logger),
kratos.Server(
gs,
hs,
),
kratos.Registrar(registry),
)
}
運行項目
cd /root/go/src/blog/cmd/blog
kratos run
訪問 consul UI
在瀏覽器中訪問 http://IP:8500/ui/dc1/services,檢查 blog 服務的注冊狀態(tài)。
3.服務發(fā)現(xiàn)
使用 kratos 創(chuàng)建一個客戶端項目 blog-client。
創(chuàng)建 Consul 注冊中心
在 blog-client/internal 目錄中,創(chuàng)建 registry 目錄,并創(chuàng)建 consul.go 和 registry.go 文件。
編寫 blog-client/internal/registry/consul.go 文件。
func NewConsulRegistry(c *conf.Registry) *consul.Registry {
client, err := api.NewClient(&api.Config{
Address: c.Consul.Addr,
Scheme: c.Consul.Schema,
})
if err != nil {
panic(err)
}
return consul.New(client)
}
編寫 blog-client/internal/registry/registry.go 文件。
var ProviderSet = wire.NewSet(NewConsulRegistry)
創(chuàng)建 RPC 客戶端
在 blog-client/internal 目錄中,創(chuàng)建 client 目錄,并創(chuàng)建 blog_client.go 和 client.go 文件。
編寫 blog-client/internal/client/blog_client.go 文件。
func NewBlogClient(registry *consul.Registry, logger log.Logger) (v1.UserClient, error) {
conn, err := grpc.DialInsecure(
context.Background(),
grpc.WithEndpoint("discovery:///blog"),
grpc.WithDiscovery(registry),
grpc.WithMiddleware(
recovery.Recovery(),
),
grpc.WithNodeFilter(
filter.Version("1.0.0")),
)
if err != nil {
log.NewHelper(logger).WithContext(context.Background()).Errorw("err", err)
return nil, err
}
return v1.NewUserClient(conn), nil
}
編寫 blog-client/internal/client/client.go 文件。
var ProviderSet = wire.NewSet(NewBlogClient)
拷貝 pb 文件
拷貝 /root/go/src/blog/api/user 目錄,粘帖到 /root/go/src/blog-client/api 目錄。
創(chuàng)建 domain 和 usecase 層
創(chuàng)建 blog-client/internal/biz/user.go 文件。
type User struct {
Id int64 `xorm:"autoincr"`
Name string
Email string
Password string
Created int64 `xorm:"created"`
Updated int64 `xorm:"updated"`
}
type UserUsecase struct {
rpcClient v1.UserClient
}
func NewUserUsecase(client v1.UserClient) *UserUsecase {
return &UserUsecase{
rpcClient: client,
}
}
func (u *UserUsecase) GetUser(ctx context.Context, user *User) (reply *v1.GetUserReply, err error) {
req := &v1.GetUserRequest{
Id: user.Id,
}
reply, err = u.rpcClient.GetUser(ctx, req)
if err != nil {
return nil, err
}
return
}
編寫 blog-client/internal/biz/biz.go 文件。
var ProviderSet = wire.NewSet(NewUserUsecase)
生成 server 源碼
cd /root/go/src/blog-client
kratos proto server api/user/v1/user.proto
編寫生成文件 internal/service/user.go。
func (s *UserService) GetUser(ctx context.Context, req *v1.GetUserRequest) (*v1.GetUserReply, error) {
user := &biz.User{
Id: req.Id,
}
reply, err := s.userUcase.GetUser(ctx, user)
if err != nil {
return nil, err
}
return &v1.GetUserReply{
Name: reply.Name,
}, nil
}
編寫 blog-client/internal/service/service.go 文件。
var ProviderSet = wire.NewSet(NewUserService)
添加 wire 提供者
編寫 blog-client/cmd/blog-client/wire.go 文件。
func wireApp(*conf.Server, *conf.Data, *conf.Registry, log.Logger) (*kratos.App, func(), error) {
panic(wire.Build(server.ProviderSet, biz.ProviderSet, registry.ProviderSet, service.ProviderSet, client.ProviderSet, newApp))
}
wire 生成文件
cd /root/go/src/blog-client/cmd/blog-client
wire
運行項目
cd /root/go/src/blog-client/cmd/blog
kratos run
curl 請求示例
curl -H "Content-Type: application/json" -X GET http://192.168.110.209:8001/user/get/1
{"name":"frank"}
4.總結
本文我們通過示例代碼,介紹 Kratos 項目怎么實現(xiàn)服務注冊與發(fā)現(xiàn)。
需要注意的是,RPC 服務端和 RPC 客戶端的端口不能相同。