一、简介

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

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

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

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

二、服务注册和服务发现

2.1 接口定义

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

注册和反注册服务:

type Registrar interface {
// 注册实例
Register(ctx context.Context, service *ServiceInstance) error
// 反注册实例
Deregister(ctx context.Context, service *ServiceInstance) error
}

获取服务:

type 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(r)

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

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

package 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(r)

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

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

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

package 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.运行服务端

$ cd ./etcd/server
$ go run ./main.go
INFO msg=[HTTP] server listening on: [::]:8080
INFO msg=[gRPC] server listening on: [::]:9000

3.运行客户端

$ 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 运行日志:

2022-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:<ID:7587862969930594823 > put:<key:\"/microservices/helloworld/8fc08b88-e37b-11ec-bb6f-88d7f62323b4\" value_size:162 lease:7587862969930594821 >" with result "size:4" took too long (113.4545ms) to execute

2.3 简析服务注册程序

一图解千言:

  • etcdregitry.New(client)

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

// 对 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()

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

// 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

// 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(r)

    选择哪个服务中心(etcd,consul,zookeeper,nacos 等等)作为 kratos 的服务中心。

    这个参数传入到上面 func New(opts ...Option) *App

// 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() 方法把服务实例注册到服务中心。

// 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 包含了一个服务实例所需的字段。

// 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"`
}

三、参考

Go微服务框架go-kratos实战04:kratos中服务注册和服务发现的使用的更多相关文章

  1. Taurus.MVC 微服务框架 入门开发教程:项目集成:1、服务端:注册中心、网关(提供可运行程序下载)。

    系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...

  2. SpringCloud微服务实战:一、Eureka注册中心服务端

    1.项目启动类application.java类名上增加@EnableEurekaServer注解,声明是注册中心 1 import org.springframework.boot.SpringAp ...

  3. rc-local.service服务启动失败,导致rc.local中的开机启动服务不能启动

    chmod  +x   /etc/rc.d/rc.local 打开/etc/rc.local文件,将启动非后台执行的指令的最后添加 &,以使相关指令后台运行,然后启动服务 systemctl  ...

  4. kratos微服务框架学习笔记一(kratos-demo)

    目录 kratos微服务框架学习笔记一(kratos-demo) kratos本体 demo kratos微服务框架学习笔记一(kratos-demo) 今年大部分时间飘过去了,没怎么更博和githu ...

  5. 微服务框架Dubbo与Springcloud的区别

    微服务框架Dubbo与Springcloud的区别 微服务主要的优势如下: 1.降低复杂度 将原来偶合在一起的复杂业务拆分为单个服务,规避了原本复杂度无止境的积累.每一个微服务专注于单一功能,并通过定 ...

  6. 简单Spring Cloud 微服务框架搭建

    微服务是现在比较流行的技术,对于程序猿而言,了解并搭建一个基本的微服务框架是很有必要滴. 微服务包含的内容非常多,一般小伙伴们可以根据自己的需求不断添加各种组件.框架. 一般情况下,基本的微服务框架包 ...

  7. 面试都在问的微服务、服务治理、RPC、下一代微服务框架... 一文带你彻底搞懂!

    文章每周持续更新,「三连」让更多人看到是对我最大的肯定.可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) 单体式应用程序 与微服务相对的另一个概念是传统的单体式应用程序( ...

  8. silky微服务框架服务注册中心介绍

    目录 服务注册中心简介 服务元数据 主机名称(hostName) 服务列表(services) 终结点 时间戳 使用Zookeeper作为服务注册中心 使用Nacos作为服务注册中心 使用Consul ...

  9. Taurus.MVC 微服务框架 入门开发教程:项目部署:1、微服务应用程序常规部署实现多开,节点扩容。

    系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...

  10. Taurus.MVC 微服务框架 入门开发教程:项目部署:2、让Kestrel支持绑定多个域名转发,替代Ngnix使用。

    系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...

随机推荐

  1. hql常用查询语句

    // HQL: Hibernate Query Language.// 特点:// >> 1,与SQL相似,SQL中的语法基本上都可以直接使用.// >> 2,SQL查询的是表 ...

  2. Python Turtle库绘制蟒蛇

    使用Python Turtle库来绘制蟒蛇 import turtle引入了海龟绘图体系 使用setup函数,设定了一个宽650像素和高350像素的窗体,其位置左上角坐标是200,200 说明位置在距 ...

  3. 使用cookie/session实现简单的用户信息的保存

    cookie一般用来存储非关键信息 , 用户名和密码等敏感信息一般采用session 来存储:cookie和session的最大区别是当服务器端存储session 之后,用户再次请求时候只是请求了一个 ...

  4. title与h1的区别、b与strong的区别、i与em的区别

    strong标签有语义,是起到加重语气的效果,而b标签是没有的,b标签只是一个简单加粗标签.b标签之间的字符都设为粗体,strong标签加强字符的语气都是通过粗体来实现的,而搜索引擎更侧重strong ...

  5. win11拖动窗口造成崩溃的问题

    问题描述 拖动窗口,随机概率出现 屏幕闪烁 屏幕黑屏 屏幕瞬间分屏 解决方法 windowes11贴吧大神给的方案 1,按下 win键+R 输入 regedit 进入注册表,进入以下路径:计算机\HK ...

  6. php实验一专属跳转博文

    今天完成了php关于设计个人博客主页的实验一作业. 这是php实验一作业中博客的跳转链接页.  

  7. ArcGIS使用技巧(三)——关于投影

    新手,若有错误还请指正! 简单记录一下自己所理解的ArcGIS中的有关投影的知识点. 在数据处理过程中,基本都是需要将相关数据放在同一投影坐标系下,需要用到投影转换工具,但若有的数据没有坐标信息,则首 ...

  8. 还在用em strong吗?快来试试 text-emphasis

    大家好,我是半夏,一个刚刚开始写文的沙雕程序员.如果喜欢我的文章,可以关注 点赞 加我微信:frontendpicker,一起学习交流前端,成为更优秀的工程师-关注公众号:搞前端的半夏,了解更多前端知 ...

  9. DevOps转型到底值不值?

    摘要:企业进行DevOps转型是否有价值?是否能计算出明确的投资回报率呢?本文将为您解惑. 本文分享自华为云社区<DevOps转型到底值不值?>,作者:敏捷小智 . 引言 企业都是以盈利为 ...

  10. @Resource与构造函数踩坑

    (虽然解决了需求,但我还是没搞懂为什么构造函数结束后,调用userMapper注入还是为空!) 首先,我有一个没有问题的userMapper类,用于处理user的数据库处理. 其次,我在另一个类里面使 ...