 优质资源分享 

学习路线指引(点击解锁)知识定位人群定位李 Python实战微信订餐小程序 李进阶级本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。Python量化交易实战入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

一、简介

关于服务注册和服务发现介绍,我前面的文章有介绍过 - 服务注册和发现的文章。

作为服务中心的软件有很多,比如 etcd,consul,nacos,zookeeper 等都可以作为服务中心。

go-kratos 把这些服务中心的功能作为插件,集成进了 kratos 中。

下面就用 etcd 作为服务中心来说说 kratos 里服务注册和服务发现功能的使用。

二、服务注册和服务发现

2.1 接口定义

从 go-kratos 服务注册和发现文档中,我们知道它的接口定义非常简单:

注册和反注册服务:

Copytype Registrar interface {

// 注册实例

Register(ctx context.Context, service *ServiceInstance) error

// 反注册实例

Deregister(ctx context.Context, service *ServiceInstance) error

}

获取服务:

Copytype Discovery interface {

// 根据 serviceName 直接拉取实例列表

GetService(ctx context.Context, serviceName string) ([]*ServiceInstance, error)

// 根据 serviceName 阻塞式订阅一个服务的实例列表信息

Watch(ctx context.Context, serviceName string) (Watcher, error)

}

2.2 简单使用

服务端注册服务

使用 etcd 作为服务中心。

1.新建 etcd连接client, etcdregitry.New(client)

2.把 regitry传入 kratos.Registrar®

3.传入服务名称 kratos.Name(“helloworld”)

看官方的示例代码,server/main.go:

Copypackage main

import (

"context"

"fmt"

"log"

etcdregitry "github.com/go-kratos/kratos/contrib/registry/etcd/v2"

"github.com/go-kratos/kratos/v2"

"github.com/go-kratos/kratos/v2/middleware/recovery"

"github.com/go-kratos/kratos/v2/transport/grpc"

"github.com/go-kratos/kratos/v2/transport/http"

pb "github.com/go-kratos/examples/helloworld/helloworld"

etcdclient "go.etcd.io/etcd/client/v3"

)

type server struct {

pb.UnimplementedGreeterServer

}

func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {

return &pb.HelloReply{Message: fmt.Sprintf("welcome %+v!", in.Name)}, nil

}

func main() {

// 创建 etcd client 连接

client, err := etcdclient.New(etcdclient.Config{

Endpoints: []string{"127.0.0.1:2379"},

})

if err != nil {

log.Fatal(err)

}

// 初始化 http server

httpSrv := http.NewServer(

http.Address(":8080"),

http.Middleware(

recovery.Recovery(),

),

)

// 初始化 grpc server

grpcSrv := grpc.NewServer(

grpc.Address(":9000"),

grpc.Middleware(

recovery.Recovery(),

),

)

// 在服务器上注册服务

s := &server{}

pb.RegisterGreeterServer(grpcSrv, s)

pb.RegisterGreeterHTTPServer(httpSrv, s)

// 创建一个 registry 对象,就是对 ectd client 操作的一个包装

r := etcdregitry.New(client)

app := kratos.New(

kratos.Name("helloworld"), // 服务名称

kratos.Server(

httpSrv,

grpcSrv,

),

kratos.Registrar(r), // 填入etcd连接(etcd作为服务中心)

)

if err := app.Run(); err != nil {

log.Fatal(err)

}

}

etcd作为服务中心的使用步骤图解:

客户端获取服务

客户端的服务发现,主要也是 3 个步骤.

1.新建 etcd连接, 传入到 etcdregitry.New(client)

2.将 registry 传入 WithDiscovery®

3.获取服务WithEndpoint(“discovery:///helloworld”)

步骤与服务没有多大区别。

官方的示例代码,client/main.go:

Copypackage main

import (

"context"

"log"

"time"

"github.com/go-kratos/examples/helloworld/helloworld"

etcdregitry "github.com/go-kratos/kratos/contrib/registry/etcd/v2"

"github.com/go-kratos/kratos/v2/transport/grpc"

"github.com/go-kratos/kratos/v2/transport/http"

etcdclient "go.etcd.io/etcd/client/v3"

srcgrpc "google.golang.org/grpc"

)

func main() {

client, err := etcdclient.New(etcdclient.Config{

Endpoints: []string{"127.0.0.1:2379"},

})

if err != nil {

log.Fatal(err)

}

r := etcdregitry.New(client) // 传入 etcd client,也就是选择 etcd 为服务中心

connGRPC, err := grpc.DialInsecure(

context.Background(),

grpc.WithEndpoint("discovery:///helloworld"), // 服务发现

grpc.WithDiscovery(r), // 传入etcd registry

)

if err != nil {

log.Fatal(err)

}

defer connGRPC.Close()

connHTTP, err := http.NewClient(

context.Background(),

http.WithEndpoint("discovery:///helloworld"),

http.WithDiscovery(r),

http.WithBlock(),

)

if err != nil {

log.Fatal(err)

}

defer connHTTP.Close()

for {

callHTTP(connHTTP)

callGRPC(connGRPC)

time.Sleep(time.Second)

}

}

func callHTTP(conn *http.Client) {

client := helloworld.NewGreeterHTTPClient(conn)

reply, err := client.SayHello(context.Background(), &helloworld.HelloRequest{Name: "go-kratos"})

if err != nil {

log.Fatal(err)

}

log.Printf("[http] SayHello %+v\n", reply)

}

func callGRPC(conn *srcgrpc.ClientConn) {

client := helloworld.NewGreeterClient(conn)

reply, err := client.SayHello(context.Background(), &helloworld.HelloRequest{Name: "go-kratos"})

if err != nil {

log.Fatal(err)

}

log.Printf("[grpc] SayHello %+v\n", reply)

}

运行程序

1.运行etcd,没有安装etcd的请自行百度或gg安装

2.运行服务端

Copy$ cd ./etcd/server

$ go run ./main.go

INFO msg=[HTTP] server listening on: [::]:8080

INFO msg=[gRPC] server listening on: [::]:9000

3.运行客户端

Copy$ cd ./client

$ go run .\main.go

INFO msg=[resolver] update instances: [{"id":"8fc08b88-e37b-11ec-bb6f-88d7f62323b4","name":"helloworld","version":"","metadata":null,"endpoints":["http://192.168.56.1:8080","grpc://192.168.56.1:9000"]}]

2022/06/04 04:28:21 [http] SayHello message:"welcome go-kratos!"

2022/06/04 04:28:21 [grpc] SayHello message:"welcome go-kratos!"

INFO msg=[resolver] update instances: [{"id":"8fc08b88-e37b-11ec-bb6f-88d7f62323b4","name":"helloworld","version":"","metadata":null,"endpoints":["http://192.168.56.1:8080","grpc://192.168.56.1:9000"]}]

2022/06/04 04:28:22 [http] SayHello message:"welcome go-kratos!"

2022/06/04 04:28:22 [grpc] SayHello message:"welcome go-kratos!"

2022/06/04 04:28:23 [http] SayHello message:"welcome go-kratos!"

2022/06/04 04:28:23 [grpc] SayHello message:"welcome go-kratos!"

2022/06/04 04:28:24 [http] SayHello message:"welcome go-kratos!"

2022/06/04 04:28:24 [grpc] SayHello message:"welcome go-kratos!"

... ...

程序运行成功

看看 etcd 运行日志:

Copy2022-06-04 04:26:03.896230 W | wal: sync duration of 1.1565369s, expected less than 1s

2022-06-04 04:26:03.991356 N | embed: serving insecure client requests on 127.0.0.1:2379, this is strongly discouraged!

2022-06-04 04:27:18.187663 W | etcdserver: request "header: put:" with result "size:4" took too long (113.4545ms) to execute

2.3 简析服务注册程序

一图解千言:

etcdregitry.New(client)

这里是对 etcd client 的包装处理,那么选择的服务中心就是 etcd。也可以使用consul,zookeeper 等,kratos 对它们都有封装。

Copy// 对 etcd client 的包装在处理

r := etcdregitry.New(client)

// https://github.com/go-kratos/kratos/contrib/registry/etcd/registry.go#L56

// New creates etcd registry

func New(client *clientv3.Client, opts ...Option) (r *Registry) {

op := &options{

ctx: context.Background(),

namespace: "/microservices",

ttl: time.Second * 15,

maxRetry: 5,

}

for _, o := range opts {

o(op)

}

return &Registry{

opts: op,

client: client,

kv: clientv3.NewKV(client),

}

}

kratos.New()

对应用程序初始化化,应用程序参数初始化 - 默认参数或接受传入的参数。

Copy// https://github.com/go-kratos/kratos/blob/v2.3.1/app.go#L39

func New(opts ...Option) *App {

o := options{

ctx: context.Background(),

sigs: []os.Signal{syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT},

registrarTimeout: 10 * time.Second,

stopTimeout: 10 * time.Second,

}

... ...

return &App{

ctx: ctx,

cancel: cancel,

opts: o,

}

}

kratos.Name(“helloworld”)

处理应用的服务参数。这个参数传入到上面 func New(opts ...Option) *App。

Copy// https://github.com/go-kratos/kratos/options.go#L41

// Name with service name.

func Name(name string) Option {

return func(o *options) { o.name = name }

}

kratos.Registrar®

选择哪个服务中心(etcd,consul,zookeeper,nacos 等等)作为 kratos 的服务中心。 这个参数传入到上面 func New(opts ...Option) *App。

Copy// https://github.com/go-kratos/kratos/blob/v2.3.1/options.go#L81

func Registrar(r registry.Registrar) Option {

return func(o *options) { o.registrar = r }

}

registrar.Register()

真正把服务注册到服务中心的是 app.Run() 这个方法里的 a.opts.registrar.Register() 方法,Register() 方法把服务实例注册到服务中心。

Copy// https://github.com/go-kratos/kratos/app.go#L84

if err := a.opts.registrar.Register(rctx, instance); err != nil {

return err

}

参数 instance 就是方法 buildInstance() 返回的服务实例 ServiceInstance,ServiceInstance struct 包含了一个服务实例所需的字段。

Copy// https://github.com/go-kratos/kratos/app.go#L154

func (a *App) buildInstance() (*registry.ServiceInstance, error)

// https://github.com/go-kratos/kratos/registry/registry.go#L33

type ServiceInstance struct {

ID string `json:"id"`

Name string `json:"name"`

Version string `json:"version"`

Metadata map[string]string `json:"metadata"`

Endpoints []string `json:"endpoints"`

}

三、参考

https://go-kratos.dev/docs/component/registry 服务注册和服务发现https://github.com/go-kratos/examples/blob/main/registry/etcd etcd registryhttps://github.com/go-kratos/kratos