一文详解Golang中consul的基本使用

目录
  • consul
  • consul的安装和部署
    • docker安装
    • consul镜像的启动
  • 启动一个tcp_health_check的服务注册
    • http版
  • 服务发现

consul

consul是一个开源服务注册和服务发现的中心,可以用于微服务的注册和服务之间的调用的发现,帮助上游服务找到下游服务的具体ip:port或者是domain,也可以使用dns的方式让consul帮你去做转发,具体介绍请看consul的官网,consul区分server-agent和client-agent,client-agent的作用一般来说就是用来转发到server-agent的,所以本文只启动server-agent,他们的详细差距可以在google上查到,本文基于golang实现一个服务注册和服务发现的demo。demo地址

consul的安装和部署

consul有两种部署模式,一种是直接在cvm上安装consul的bin包,然后以server-agent的模式进行启动,一种是用docker直接启动镜像,本文直接使用docker启动镜像,将这个镜像的启动参数设置为server-agent,在这种模式下,如果要使用服务发现的功能需要区分主机ip和容器ip 不能使用127.0.0.1这种ip去让server维持go服务的心跳

本文使用的cvm系统为centos8,其他Linux发行版可以自行用包管理工具去安装一下的前置依赖

docker安装

curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
systemctl start docker

使用上文脚本一键安装docker

consul镜像的启动

docker pull consul
docker run -d -p 8500:8500 -v ~/consul:/consul/data -e CONSUL_BIND_INTERFACE='eth0' --name=consul1 consul agent -server -bootstrap -ui -client='0.0.0.0'

两步启动一个consul的server-agent,然后就可以通过ip:8500访问得到consul的一个web界面,如果ip访问不通可以使用下文的vscode的代理模式去访问或者是在自己厂商的cvm控制台去开端口的访问策略,web界面如下

启动一个tcp_health_check的服务注册

创建一个go项目

mkdir consul_demo
go mod init consul_demo
go get -u github.com/hashicorp/consul/api
touch main.go

// main.go
package main

import (
	"bufio"
	"fmt"
	"net"

	consulapi "github.com/hashicorp/consul/api"
)

type DiscoveryConfig struct {
	ID      string
	Name    string
	Tags    []string
	Port    int
	Address string
}

var consulAddress = "127.0.0.1:8500"

func RegisterService(dis DiscoveryConfig) error {
	config := consulapi.DefaultConfig()
	config.Address = consulAddress
	client, err := consulapi.NewClient(config)
	if err != nil {
		fmt.Printf("create consul client : %v\n", err.Error())
	}
	registration := &consulapi.AgentServiceRegistration{
		ID:      dis.ID,
		Name:    dis.Name,
		Port:    dis.Port,
		Tags:    dis.Tags,
		Address: dis.Address,
	}
	// 启动tcp的健康检测,注意address不能使用127.0.0.1或者localhost,因为consul-agent在docker容器里,如果用这个的话,
	// consul会访问容器里的port就会出错,一直检查不到实例
	check := &consulapi.AgentServiceCheck{}
	check.TCP = fmt.Sprintf("%s:%d", registration.Address, registration.Port)
	check.Timeout = "5s"
	check.Interval = "5s"
	check.DeregisterCriticalServiceAfter = "60s"
	registration.Check = check

	if err := client.Agent().ServiceRegister(registration); err != nil {
		fmt.Printf("register to consul error: %v\n", err.Error())
		return err
	}
	return nil
}

func startTcp() {
	ls, err := net.Listen("tcp", ":10111")
	if err != nil {
		fmt.Printf("start tcp listener error: %v\n", err.Error())
		return
	}
	for {
		conn, err := ls.Accept()
		if err != nil {
			fmt.Printf("connect error: %v\n", err.Error())
		}
		go func(conn net.Conn) {
			_, err := bufio.NewWriter(conn).WriteString("hello consul")
			if err != nil {
				fmt.Printf("write conn error: %v\n", err)
			}
		}(conn)
	}
}
func main() {
	ch := make(chan error)
	dis := DiscoveryConfig{
		ID:      "9527",
		Name:    "main_service",
		Tags:    []string{"a", "b"},
		Port:    10111,
		Address: "192.168.0.124", //通过ifconfig查看本机的eth0的ipv4地址
	}
	go startTcp()
	RegisterService(dis)
	// 阻塞等待
	<-ch
}

然后我们运行这个代码

go run main.go

就可以看到consul的web界面上多了一个服务实例

http版

如果不使用tcp作为健康检查的方式,可以使用Http_server去实现,逻辑是一样的,需要给consul返回一个消息,让consul确认你的心跳即可

check := &consulapi.AgentServiceCheck{}
check.HTTP = fmt.Sprintf("http://%s:%d/", registration.Address, registration.Port)
func startHttp() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Printf("consul get uri: %s\n", r.RequestURI)
		w.Write([]byte("hello consul"))
	})
	if err := http.ListenAndServe(":10111", nil); err != nil {
		fmt.Printf("start http server error: %v\n", err)
	}
}
go startHttp()

服务发现

服务发现其实就是通过http请求向consul请求指定的service下的实例,获取到他们对应的ip:port和一些其他的元信息,然后在客户端根据需要筛选得出一个ip:port的实例进行通讯,由于向consul发起http请求的sdk已经在consul官方实现了,所以我们不需要自己建一个httpclient去调用这些api,而是直接构建一个struct交给sdk去查询即可

package main

import (
	"fmt"
	"testing"

	consulapi "github.com/hashicorp/consul/api"
)

func Discovery(serviceName string) []*consulapi.ServiceEntry {
	config := consulapi.DefaultConfig()
	config.Address = "127.0.0.1:8500"
	client, err := consulapi.NewClient(config)
	if err != nil {
		fmt.Printf("consul client error: %v", err)
	}
	service, _, err := client.Health().Service(serviceName, "", false, nil)
	if err != nil {
		fmt.Printf("consul client get serviceIp error: %v", err)
	}
	return service
}

func TestDiscoeryFromConsul(t *testing.T) {
	t.Logf("client discovery start")
	se := Discovery("main_service")
	for i := 0; i < len(se); i++ {
		t.Logf("the instance Node is %+v\n", se[i].Node)
		t.Logf("the isntance Service is %+v\n", se[i].Service)
		t.Logf("\n")
	}
}

ut的结果如下,证明我们通过consul找到了下游服务的ip:port即可发起通讯

[root@hecs-74066 consul_demo]# go test -v main_test.go 
=== RUN   TestDiscoeryFromConsul
    main_test.go:25: client discovery start
    main_test.go:28: the instance Node is &{ID:278ba4f1-0309-fc92-d641-a312b5797779 Node:241f8a20d7fb Address:172.17.0.2 Datacenter:dc1 TaggedAddresses:map[lan:172.17.0.2 lan_ipv4:172.17.0.2 wan:172.17.0.2 wan_ipv4:172.17.0.2] Meta:map[consul-network-segment:] CreateIndex:13 ModifyIndex:16 Partition: PeerName:}
    main_test.go:29: the isntance Service is &{Kind: ID:9527 Service:main_service Tags:[a b] Meta:map[] Port:10111 Address:192.168.0.124 SocketPath: TaggedAddresses:map[lan_ipv4:{Address:192.168.0.124 Port:10111} wan_ipv4:{Address:192.168.0.124 Port:10111}] Weights:{Passing:1 Warning:1} EnableTagOverride:false CreateIndex:43 ModifyIndex:43 ContentHash: Proxy:0xc0000c44d0 Connect:0xc000091a50 PeerName: Namespace: Partition: Datacenter:}
    main_test.go:30: 
--- PASS: TestDiscoeryFromConsul (0.00s)

到此这篇关于一文详解Golang中consul的基本使用的文章就介绍到这了,更多相关Golang consul内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • go学习笔记读取consul配置文件详解

    目录 新建yaml文件 读取远程配置 新建yaml文件 在上文我们的 go学习笔记:使用 consul 做服务发现和配置共享 这里我们单独来用viper实现读取consul的配置, 我习惯与用yaml格式, 所以 首先 新建yaml文件 store: book: - author: john price: 10 - author: ken price: 12 bicycle: color: red price: 19.95 读取远程配置 可以直接调用viper.AddRemoteProvider

  • go使用consul实现服务发现及配置共享实现详解

    目录 使用consul四大特性 通过docker安装consul 实现代码 运行结果 使用consul四大特性 1. 服务发现:利用服务注册,服务发现功能来实现服务治理. 2. 健康检查:利用consul注册的检查检查函数或脚本来判断服务是否健康,若服务不存在则从注册中心移除该服务,减少故障服务请求. 3. k/v数据存储:存储kv数据,可以作为服务配置中心来使用. 4. 多数据中心:可以建立多个consul集群通过inter网络进行互联,进一步保证数据可用性. 通过docker安装consul

  • Golang使用Consul详解

    目录 常用指令 常用功能 定义服务 服务管理 服务健康检查 go使用官方api包来定义服务\查询服务 常用指令 agent指令 -bind=0.0.0.0 指定consul所在机器的ip地址 -http-port 指定web接口服务端口 -client 指定哪些机器可以访问consul, 0.0.0.0表示所有机器 -data-dir=path 指定服务数据文件存储位置 -dev 开发者模式,直接以默认模式启动consul -node=hostname 服务发现的名字 -rejoin consu

  • 详解golang consul-grpc 服务注册与发现

    在微服务架构里面,每个小服务都是由很多节点组成,节点的添加删除故障希望能对下游透明,因此有必要引入一种服务的自动注册和发现机制,而 consul 提供了完整的解决方案,并且内置了对 GRPC 以及 HTTP 服务的支持 总体架构 服务调用: client 直连 server 调用服务 服务注册: 服务端将服务的信息注册到 consul 里 服务发现: 客户端从 consul 里发现服务信息,主要是服务的地址 健康检查: consul 检查服务器的健康状态 服务注册 服务端将服务信息注册到 con

  • 一文详解Golang中consul的基本使用

    目录 consul consul的安装和部署 docker安装 consul镜像的启动 启动一个tcp_health_check的服务注册 http版 服务发现 consul consul是一个开源服务注册和服务发现的中心,可以用于微服务的注册和服务之间的调用的发现,帮助上游服务找到下游服务的具体ip:port或者是domain,也可以使用dns的方式让consul帮你去做转发,具体介绍请看consul的官网,consul区分server-agent和client-agent,client-ag

  • 一文详解Golang中net/http包的实现原理

    目录 前言 http包执行流程 http包源码分析 端口监听 请求解析 路由分配 响应处理 前言 Go语言自带的net/http包提供了HTTP客户端和服务端的实现,实现一个简单的http服务非常容易,其自带了一些列结构和方法来帮助开发者简化HTTP服务开发的相关流程,因此我们不需要依赖任何第三方组件就能构建并启动一个高并发的HTTP服务器,net/http包在编写web应用中有很重要的作用,这篇文章会学习如何用 net/http 自己编写实现一个 HTTP Server 并探究其实现原理,具体

  • 一文详解Golang中的切片数据类型

    目录 含义 定义 三个要素 切片与数组的区别 示例代码 切片内存分布 切片定义分类 数组生成切片 示例代码 切片索引 直接声明切片 定义语法 代码示例 使用make定义切片 常用操作 长度计算 容量计算 判断是否为空 切片追加 语法格式 尾部追加 开始位置追加 中间位置追加 复制 引用和复制 切片的删除 删除开头 删除中间 删除结尾 指定位置 排序 迭代器 含义 切片是一个种特殊的数组.是对数组的一个连续片段的引用,所以切片是一个引用类型.切片可以是数组中的一部分,也可以是由起始和终止索引标识的

  • 一文详解Golang协程调度器scheduler

    目录 1. 调度器scheduler的作用 2. GMP模型 3. 调度机制 1. 调度器scheduler的作用 我们都知道,在Go语言中,程序运行的最小单元是gorouines. 然而程序的运行最终都是要交给操作系统来执行的,以Java为例,Java中的一个线程对应的就是操作系统中的线程,以此来实现在操作系统中的运行.在Go中,gorouines比线程更轻量级,其与操作系统的线程也不是一一对应的关系,然而,最终我们想要执行程序,还是要借助操作系统的线程来完成,调度器scheduler的工作就

  • 一文详解Golang 定时任务库 gron 设计和原理

    目录 cron 简介 gron 定时参数 源码解析 Cron Entry 按照时间排序 新增定时任务 启动和停止 Schedule 扩展性 经典写法-控制退出 结语 cron 简介 在 Unix-like 操作系统中,有一个大家都很熟悉的 cli 工具,它能够来处理定时任务,周期性任务,这就是: cron. 你只需要简单的语法控制就能实现任意[定时]的语义.用法上可以参考一下这个Crontab Guru Editor,做的非常精巧. 简单说,每一个位都代表了一个时间维度,* 代表全集,所以,上面

  • 详解Golang中的各种时间操作

    需求 时间格式的转换比较麻烦,自己写了个工具,可以通过工具中的这些方法相互调用转成自己想要的格式,代码如下,后续有新的函数再添加 实现代码 package utils import "time" const ( TIMEFORMAT = "20060102150405" NORMALTIMEFORMAT = "2006-01-02 15:04:05" ) // 当前时间 func GetTime() time.Time{ return time.

  • 详解Golang中Channel的用法

    如果说goroutine是Go语言程序的并发体的话,那么channels则是它们之间的通信机制.一个channel是一个通信机制,它可以让一个goroutine通过它给另一个goroutine发送值信息. 1 创建channel 每个channel都有一个特殊的类型,也就是channels可发送数据的类型.一个可以发送int类型数据 的channel一般写为chan int.使用内置的make函数,如果第二个参数大于0,则表示创建一个带缓存的channel. ch := make(chan in

  • 详解golang中的method

    什么是method(方法)?method是函数的另外一种形态,隶属于某个类型的方法. method的语法: func (r Receiver) funcName (parameters) (result) receiver可以看作是method的第一个参数,method并且支持继承和重写. Go中虽没有class,但依旧有method 通过显示说明receiver来实现与某个类型的结合 只能为同一个包中的类型定义方法 receiver可以是类型的值或者指针 不存在方法重载 可以使用值或指针来调用

  • 一文详解JS中的事件循环机制

    目录 前言 1.JavaScript是单线程的 2.同步和异步 3.事件循环 前言 我们知道JavaScript 是单线程的编程语言,只能同一时间内做一件事,按顺序来处理事件,但是在遇到异步事件的时候,js线程并没有阻塞,还会继续执行,这又是为什么呢?本文来总结一下js 的事件循环机制. 1.JavaScript是单线程的 JavaScript 是一种单线程的编程语言,只有一个调用栈,决定了它在同一时间只能做一件事.在代码执行的时候,通过将不同函数的执行上下文压入执行栈中来保证代码的有序执行.在

  • 一文详解Java中的类加载机制

    目录 一.前言 二.类加载的时机 2.1 类加载过程 2.2 什么时候类初始化 2.3 被动引用不会初始化 三.类加载的过程 3.1 加载 3.2 验证 3.3 准备 3.4 解析 3.5 初始化 四.父类和子类初始化过程中的执行顺序 五.类加载器 5.1 类与类加载器 5.2 双亲委派模型 5.3 破坏双亲委派模型 六.Java模块化系统 一.前言 Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最 终形成可以被虚拟机直接使用的Java类型,这个过程

随机推荐