Go微服务框架go-kratos实战学习07:consul 作为服务注册和发现中心
一、Consul 简介
consul 是什么
HashiCorp Consul 是一种服务网络解决方案,它能够管理服务之间以及跨本地和多云环境和运行时的安全网络连接。Consul 它能提供服务发现、服务网格、流量管理和自动更新等功能。
Conslul 提供了一个控制平面,使得你能够注册、查询和保护跨网络部署的服务。
控制平面作用,它维护一个中央注册表来跟踪服务及其各自的 IP 地址,它是一个分布式系统,运行在节点集群上。
Consul 架构

(consul v1.15 的单集群架构)
Consul 还支持多数据中心架构,具体可以它的文档:https://developer.hashicorp.com/consul/docs/architecture。
Consul 也提供了 CLI 命令操作功能,https://developer.hashicorp.com/consul/commands。(v1.15.x)
Consul 也提供了 API 的功能,https://developer.hashicorp.com/consul/api-docs。
Consul 还提供了一个简单的 Web 查看操作界面。
Consul 提供的 API 功能
在这篇文档中,https://developer.hashicorp.com/consul/api-docs 可以看到 Consul 提供了很多 API 功能。
- KV Store:kv 存储
- Catalog:/catalog endpoints 在 Consul 中注册和注销节点、服务和检查,catalog 不应该与 agent 混淆,这个 API 方法看起来很相似。
- Agent:/agent endpoints 用于与本地 Consul 代理交互。通常,服务和检查信息是在代理上注册,然后由代理负责保持数据与集群同步。
- Checks:/agent/checks,返回本地代理注册的所有检查。这个 endpoints 还有其它很多功能比如 Register Check,Deregister Check,TTL Check Pass,TTL Check Fail,TTL Check Warn,TTL Check Update等。
- Service:/agent/service,这个 endpoints 与 Consul 中本地代理上服务交互。这个不应与 catalog 中的服务相混淆。它也有很多功能比如 Register Service,Deregister Service,Get local service health 等。更多功能请查看文档。
- Config:在 /config, 这个 endpoints 创建、删除、更新和查询向 Consul 注册的配置条目信息
- Health:这个 endpoints 查询与检查相关的信息。它是与 catalog 分开提供功能,因为用户可能不喜欢使用可选的健康检查机制。此外,这个 endpoints 提供查询信息时,会把 catalog 提供的原始信息过滤掉一些信息。
- Event:触发新事件,查询可用的事件。
- Operator:/operator, 这个 endpoints 为用户提供了一个查询集群信息的工具。比如与 Raft 子系统交互。
- Sessions:/session 提供操作 session 的功能。
- ACLs 管理基于ACL的令牌和策略
- Policies:/acl/policy,ACL Policy HTTP API,在 Consul 中创建、读取、更新、列出和删除 ACL 策略。
- Tokens:/acl/token,endpoints 提供了在 Consul 中创建、读取、更新、删除 ACL token 等功能。
- ACL Auth Method:/acl/auth-method。
- Roles:/acl/role,操作 role 功能。
- ACL Binding Rule:/acl/binding-rule,在 Consul 中操作 binding-rule。
更多 API 功能请查看文档:https://developer.hashicorp.com/consul/api-docs。
Consul 提供的 API SDK
Go API SDK:https://github.com/hashicorp/consul/tree/release/1.15.0/api
二、Consul 服务注册和发现
在上面 Consul 介绍中,它提供了很多 API 功能,与服务注册和发现功能相关的 API 有 agent、health 还有 kv store 等等,最重要的是 agent。
如果涉及到权限还可以用 ACL 功能。
高可用方面,Consul 不仅提供了单集群架构,也提供了多数据中心集群架构。
不过 Consul 都给我们提供了相关 API。
服务注册和发现相关API
相关文档:
https://developer.hashicorp.com/consul/docs/concepts/service-discovery (v1.15.x),对服务注册发现原理解释
https://developer.hashicorp.com/consul/api-docs/agent/service,Agent HTTP API,操作服务的API
- List Services,列出所有的服务
- Register Service,注册服务实例,向本地代理注册新的服务实例,也可以包含健康检查
- Deregister Service,删除服务实例。负责删除目录中的服务,如果有关联服务则一并删除
- Get Service Configuration,本地代理上注册的单个服务完整服务实例信息
- Get local service health,根据名称查询本地代理上所有服务实例状态
- Get local service health by ID,同过 ID 查询服务实例健康状态
- Enable Maintenance Mode,启用维护模式,在维护模式期间,该服务将被标记为不可用,并且不会出现在 DNS 或 API 查询中。维护模式是持久的,将在代理重新启动时自动恢复。
- Methods to Specify Namespace,指定命名空间(企业版才有功能)
服务发现使用的是服务名来标识服务发现的信息,而不是传统使用的 IP 地址和端口。允许你动态映射服务并跟踪服务信息的任务变更。
- 服务注册
服务实例注册使用 IP 地址和端口将自身服务信息注册到服务目录。当你注册的新实例注册到服务目录(the service catalog)时,他们将参与负载均衡池以处理服务消费者请求。

(来自:consul 文档service-discovery)
- 服务发现(查询)
服务的消费者可以通过注册的实例服务名来查询相关服务信息。

(来自:consul 文档service-discovery)
- 服务更新
随着新服务实例的添加或旧的不健康服务实例的删除,服务目录会动态更新。移除的服务将不再参与服务消费者请求的负载均衡池。

(来自:consul 文档service-discovery)
服务发现的2种主要类型
两种主要的服务发现类型:
1、client-side discovery 客户端发现模式
2、server-side discovery 服务端发现模式
- 客户端发现
客户服务发现模式中,服务消费者负责确定可用服务实例的访问信息以及他们之间的负载均衡请求。
一般步骤:
- 服务消费者查询服务目录
- 对服务目录进行检索并返回所有的服务信息
- 服务消费者选择健康的服务实例并直接向其发送请求

(来自:consul 文档service-discovery)
- 服务端发现
服务端服务发现模式,服务消费者使用中介来查询服务目录并向他们发送请求。步骤如下:
- 服务消费者查询中介(Consul)
- 中介查询服务目录并将请求路由到可用的服务实例

(来自:consul 文档service-discovery)
三、代码实现服务注册和发现
安装 Consul
安装地址:consul intall。
也可以直接用 docker 安装:docker pull consul。
好多年前我也写了一个 consul 的基本配置和使用:https://www.cnblogs.com/jiujuan/p/9356772.html。
因为我用的 win,直接下载 bin 安装了。
启动用 dev 模式:consul agenet -dev。
代码例子
关于服务发现和注册的 2 个主要 API 文档:
在 /agent/service/register 这个 API 里,请求的 Body 里定义了一些 JSON 类型参数,
比如 Name,ID,Tags,Address,TaggedAddress,Meta,Port,Checks,Weights 等等参数,可以去文档看看。
一个最简单的服务信息 json格式:
{
"service": {
"id": "hello-service",
"name": "hello-service",
"tags": ["test"],
"port": 80,
"address": "127.0.0.1",
}
}
例子代码:
consul: v1.15.0
consul api: github.com/hashicorp/consul/api v1.18.0
go: v1.18
- 添加服务实例接口和查询服务接口
import consulapi "github.com/hashicorp/consul/api"
// 添加服务实例接口
type Registry interface {
Register(string, string, string, string, int) error
Deregister(string) error
}
type Service interface {
GetServices() (map[string]*consulapi.AgentService, error)
GetService(string) (*consulapi.AgentService, *consulapi.QueryMeta, error)
FilterService(string) (map[string]*consulapi.AgentService, error)
}
- consul客户端配置和链接
type client struct {
client *consulapi.Client
}
func NewConfig(addr string) *consulapi.Config {
config := consulapi.DefaultConfig()
if addr != "" {
config.Address = addr
}
return config
}
func NewClient(addr string) (*client, error) {
config := NewConfig(addr)
c, err := consulapi.NewClient(config)
if err != nil {
return nil, err
}
return &client{client: c}, nil
}
- 注册服务实例
func (c *client) Register(name, id, tags, ip string, port int) error {
// 服务注册信息
reg := &consulapi.AgentServiceRegistration{
ID: id, // 唯一服务 ID
Name: name, // 服务名
Tags: []string{tags}, // 标签,可以标识相同服务
Port: port, // 端口号
Address: ip, // 所在节点 ip 地址
}
// 服务健康检查
reg.Check = &consulapi.AgentServiceCheck{
HTTP: fmt.Sprintf("http://%s:%d%s", ip, port, "/health-check"), // http形式检查,健康检测/health-check路径
Timeout: "5s",
Interval: "5s", // 每隔5s检查一次
DeregisterCriticalServiceAfter: "40s", // 服务40s不可达时,注销服务
Status: "passing", // 默认服务状态正常
}
return c.client.Agent().ServiceRegister(reg)
}
然后添加获取服务的函数 GetService(),最后在 main 函数里写测试例子,完整代码请查看 github:
写完后运行:go run registry.go,然后在浏览器上查看注册的服务实例,http://localhost:8500/ui/dc1/services,注册服务成功(如下图).
如果停掉运行的 go run registry.go,它会在 40s 后自动注销服务实例,40s 后查看页面,注册的2个服务实例已经被删除。

完整代码
完整代码例子:github registry
四、go-kratos中的consul
主要接口分析
go-kratos 为服务注册和发现抽象了 2 个最重要的接口。
- 注册服务接口:
// https://github.com/go-kratos/kratos/blob/v2.5.4/registry/registry.go
// Registrar is service registrar
type Registrar interface {
// 注册实例
Register(ctx context.Context, service *ServiceInstance) error
// 注销实例
Deregister(ctx context.Context, service *ServiceInstance) error
}
- 发现服务接口:
// https://github.com/go-kratos/kratos/blob/v2.5.4/registry/registry.go#L17
// Discovery is service discovery
type Discovery interface {
// 根据 serviceName 直接拉取实例列表
GetService(ctx context.Context, serviceName string) ([]*ServiceInstance, error)
// 根据 serviceName 阻塞式订阅一个服务的实例列表信息
Watch(ctx context.Context, serviceName string) (Watcher, error)
}
还有一个 watcher 接口
// https://github.com/go-kratos/kratos/blob/v2.5.4/registry/registry.go#L25
type Watcher interface {
// Next returns services in the following two cases:
// 1.the first time to watch and the service instance list is not empty.第一次查看服务列表是否为空
// 2.any service instance changes found. 发现服务实例改变
// if the above two conditions are not met, it will block until context deadline exceeded or canceled
Next() ([]*ServiceInstance, error)
// Stop close the watcher.
Stop() error
}
Consul 对 go-kratos 中定义服务注册和发现接口的实现在 contrib/registry/consul 目录里:

- consul registry struct:
kratos 中的 Registry struct
- consul Client struct:
kratos 中的 Client struct
代码例子
go-kratos 官方代码例子,client/main.go:
func main() {
consulClient, err := api.NewClient(api.DefaultConfig()) // consul client
if err != nil {
panic(err)
}
r := consul.New(consulClient) // 把 consulClient 客户端连接添加到 go-kratos 中的registry
// grpc client
conn, err := grpc.DialInsecure(
context.Background(),
grpc.WithEndpoint("discovery:///helloworld"),
grpc.WithDiscovery(),
)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
gClient := helloworld.NewGreeterClient(conn) // gRPC 方式调用 helloworld 中方法
// http client
hConn, err := http.NewClient(
context.Background(),
http.WithMiddleware(
recovery.Recovery(),
),
http.WithEndpoint("discovery:///helloworld"), // 服务名
http.WithDiscovery(r), // 这里用 consul 作为服务发现中心
)
if err != nil {
log.Fatal(err)
}
defer hConn.Close()
hClient := helloworld.NewGreeterClient(hConn) // http 方式调用 helloworld 中方法
for {
time.Sleep(time.Second)
callGRPC(gClient)
callHTTP(hClient)
}
}
go-kratos 官方代码例子,server/main.go:
func main() {
logger := log.NewStdLogger(os.Stdout)
log := log.NewHelper(logger)
// consul client
consulClient, err := api.NewClient(api.DefaultConfig())
if err != nil {
log.Fatal(err)
}
r := consul.New(consulClient) // 把 consulClient 客户端连接添加到 go-kratos 中的registry
// http server
httpSrv := http.NewServer(
http.Address(":8000"),
http.Middleware(
recovery.Recovery(),
logging.Server(logger),
),
)
// grpc server
grpcSrv := grpc.NewServer(
grpc.Address(":9000"),
grpc.Middleware(
recovery.Recovery(),
logging.Server(logger),
),
)
s := &server{}
helloworld.RegisterGreeterServer(grpcSrv, s) // grpc 方式调用方法
helloworld.RegisterGreeterHTTPServer(httpSrv, s) // http 方式调用方法
app := kratos.New(
kratos.Name("helloworld"),
kratos.Server(
grpcSrv,
httpSrv,
),
kratos.Registrar(r), // 这里用 consul 作为服务发现中心
)
if err := app.Run(); err != nil {
log.Fatal(err)
}
}
完整代码请查看 github:https://github.com/jiujuan/go-kratos-demos/tree/master/registry/consul
也欢迎到我的公众号 九卷技术录:go-kratos实战学习07:consul 作为服务注册和发现中心 讨论
五、参考
- https://developer.hashicorp.com/consul/docs Consul文档(v1.15.x)
- https://developer.hashicorp.com/consul/api-docs Consul API Overview(v1.15.x)
- https://developer.hashicorp.com/consul/tutorials consul tutorial
- https://developer.hashicorp.com/consul/api-docs/agent/service api agent service
- https://github.com/hashicorp/consul/tree/release/1.15.0/api api SDK
- https://developer.hashicorp.com/consul/api-docs/agent/service#json-request-body-schema JSON Request Body Schema
- https://developer.hashicorp.com/consul/docs/concepts/service-discovery consul service discovery
- https://developer.hashicorp.com/consul/docs/install consul install
- https://github.com/go-kratos/kratos/blob/v2.5.4/contrib/registry/consul/
- https://github.com/go-kratos/examples kratos examples
- https://github.com/jiujuan/go-exercises/tree/main/registerservices 完整代码例子
Go微服务框架go-kratos实战学习07:consul 作为服务注册和发现中心的更多相关文章
- 微服务框架SpringCloud(Dalston版)学习 (一):Eureka服务注册与发现
eureka-server eureka服务端,提供服务的注册与发现,类似于zookeeper 新建spring-boot工程,pom依赖: <dependency> <groupI ...
- 转载 (三)surging 微服务框架使用系列之我的第一个服务(审计日志)
(三)surging 微服务框架使用系列之我的第一个服务(审计日志) 前言:前面准备了那么久的准备工作,现在终于可以开始构建我们自己的服务了.这篇博客就让我们一起构建自己的第一个服务---审计日志 ...
- SpringCloud服务注册与发现中心-Eureka
1.服务注册与发现的好处: 假设没有这个东西,那么如果存在a,b,c三个同样的服务: 而现在有一个u服务需要用到a或b或c提供的接口,那么u里面肯定是需要配置这三个服务的地址,然后调用的时候还有问题就 ...
- (三)surging 微服务框架使用系列之我的第一个服务(审计日志)
前言:前面准备了那么久的准备工作,现在终于可以开始构建我们自己的服务了.这篇博客就让我们一起构建自己的第一个服务---审计日志. 首先我们先创建两个项目,一个控制台的服务启动项目,一个业务的实现项目. ...
- 用Nacos做微服务架构里的服务注册与发现中心
转自:https://www.jianshu.com/p/61608ff86344 Nacos 另一个非常重要的特性就是服务注册与发现,说到服务的注册与发现相信大家应该都不陌生,在微服务盛行的今天,服 ...
- SpringCloud用Zookeeper做服务注册与发现中心代码实现
一:Zookeeper用的是3.5.5版本,SpringBoot用的是2.1.6版本,SpringCloud用的是Greenwich.SR2版本,JDK用的是1.8: 服务提供者product-ser ...
- 【微服务】使用spring cloud搭建微服务框架,整理学习资料
写在前面 使用spring cloud搭建微服务框架,是我最近最主要的工作之一,一开始我使用bubbo加zookeeper制作了一个基于dubbo的微服务框架,然后被架构师否了,架构师曰:此物过时.随 ...
- 003-读书笔记-企业IT架构转型之道-阿里巴巴中台战略思想与架构实战-分布式服务框架的选择
3.1.淘宝平台“服务化”历程 大约2007年,淘宝500人团队,维护一个war包,200多个功能模块. 1)项目团队协同成本高,业务响应越来越慢 2)应用复杂度超出人的认知负载. 3)错误难于隔离[ ...
- Dubbo阿里Alibaba开源的分布式服务框架
[获奖公布]"我的2016"主题征文活动 程序猿全指南,让[移动开发]更简单! [观点]移动原生App开发和HTML 5开发,你更看好哪个? 博客的神秘功能 D ...
- 微言Netty:分布式服务框架
1. 前言 几年前,我就一直想着要设计一款自己的实时通讯框架,于是出来了TinySocket,她是基于微软的SocketAsyncEventArgs来实现的,由于此类提供的功能很简洁,所以当时自己实现 ...
随机推荐
- [转帖]RAC环境下误操作将数据文件添加到本地存储
https://www.cnblogs.com/jyzhao/p/7986729.html 今天碰到个有意思的事情,有客户在Oracle RAC环境,误操作将新增的数据文件直接创建到了其中一个节点的本 ...
- [转帖]Jmeter正则提取器常用的几种方式
https://www.cnblogs.com/a00ium/p/10483741.html 使用jmeter的同学都知道,jmeter提供了各种各样的提取器,如jsonpath.Beanshell. ...
- 【转帖】nginx变量使用方法详解-3
https://www.diewufeiyang.com/post/577.html 也有一些内建变量是支持改写的,其中一个例子是 $args. 这个变量在读取时返回当前请求的 URL 参数串(即请求 ...
- [转帖]Linux 防火墙开放特定端口 (iptables)
查看状态: iptables -L -n 下面添加对特定端口开放的方法: 使用iptables开放如下端口 /sbin/iptables -I INPUT -p tcp --dport 8000 -j ...
- [转帖]Perf IPC以及CPU性能
https://plantegg.github.io/2021/05/16/Perf%20IPC%E4%BB%A5%E5%8F%8ACPU%E5%88%A9%E7%94%A8%E7%8E%87/ Pe ...
- Linux 一行命令 仅显示某一个网卡的ip地址
最简答的方法 1. 先使用 ifconfig 查看网卡的设备名 2. 然后输入命令 ifconfig ens192 |grep 'inet ' |cut -d " " -f 10命 ...
- 一文详解 Netty 组件
作者:京东物流 张弓言 一.背景 Netty 是一款优秀的高性能网络框架,内部通过 NIO 的方式来处理网络请求,在高负载下也能可靠和高效地处理 I/O 操作 作为较底层的网络通信框架,其被广泛应用在 ...
- 人工智能创新挑战赛:助力精准气象和海洋预测Baseline[3]:TCNN+RNN模型、SA-ConvLSTM模型
"AI Earth"人工智能创新挑战赛:助力精准气象和海洋预测Baseline[3]:TCNN+RNN模型.SA-ConvLSTM模型 1.气象海洋预测-模型建立之TCNN+RNN ...
- 21.7 Python 使用Request库
Request库可以用来发送各种HTTP请求,该框架的特点是简单易用,同时支持同步和异步请求,支持HTTP协议的各种方法和重定向.它还支持Cookie.HTTPS和认证等特性. Request库的使用 ...
- 设置两个Chrome浏览器 一个正常使用 一个无图片版
添加两个Chrome浏览器 双击打开Chrome浏览器,点击右上角头像,点击添加 选择"在不登录帐号的情况下继续",创建一个名字,选个配色,勾选下面的创建桌面快捷方式 此时会打开一 ...