0
点赞
收藏
分享

微信扫一扫

go-consul实战

consul简介

官网介绍地址 还有视频介绍不过是应为的

学习参考的资料
官网
中文文档

环境搭建

说明

# 虚拟机操作系统
> uname -a
> Linux n248-174-155 4.14.81.bm.15-amd64 #1 SMP Debian 4.14.81.bm.15 Sun Sep 8 05:02:31 UTC 2019 x86_64 GNU/Linux

下载安装

# 下载
wget https://releases.hashicorp.com/consul/1.11.1/consul_1.11.1_linux_amd64.zip
# 解压
unzip consul_1.11.1_linux_amd64.zip

解压后只有一个可执行文件,将这个可执行文件加入到环境变量PATH中即可,记得使用source 命令让PATH的变量重新加载

测试是否安装成功

# consul version 查看版本号
root@n248-174-155:~/file$ consul version
Consul v1.11.1
Revision 2c56447e
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)

另外由于启动时,指定了参数开始 web-ui 所以可以在web端可视化的展示服务的状态,将ip替换成你的ip即可
http://10.248.174.155:8500/

命令实战

启动 consul

# 后台启动方式,指定了日志文件路径/home/root/consul/consul.log
nohup consul agent -dev -client 0.0.0.0 -ui > /home/root/consul/consul.log 2>&1 &

查看进程

root@n248-174-155:~/file$ netstat -ntpl|grep consul
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 127.0.0.1:8300          0.0.0.0:*               LISTEN      793138/consul
tcp        0      0 127.0.0.1:8301          0.0.0.0:*               LISTEN      793138/consul
tcp        0      0 127.0.0.1:8302          0.0.0.0:*               LISTEN      793138/consul
tcp6       0      0 :::8500                 :::*                    LISTEN      793138/consul
tcp6       0      0 :::8502                 :::*                    LISTEN      793138/consul
tcp6       0      0 :::8600                 :::*                    LISTEN      793138/consul

新增kv

consul kv put services/svr1/001 '{"Addr":"192.168.4.5","Port":3358}'
consul kv put services/svr1/002 '{"Addr":"192.164.45.22","Port":3458}'
consul kv put services/svr2/001 '{"Addr":"192.138.44.55","Port":3456}'

新增key 指定额外flags

consul kv put -flags=25 service/svr1/003 '{"Addr":"192.174.35.67","Port":8890}'

查询kv

consul kv get service/svr1/001

查询kv详情

consul kv get -detailed service/svr1/001

查询所有kv 递归查询

consul kv get -recurse

根据key前缀查询,返回所有kv

consul kv get -recurse service/svr1/

根据key前缀查询,只返回key

consul kv get -keys service/svr1/

删除kv

consul kv delete service/svr1/001

根据前缀删除

consul kv delete -recurse service/svr1/

watch 某个前缀的结点,会一次性返回所有结点的信息

consul watch -type=keyprefix -prefix=/services/svr1/001

服务注册

# 指定服务ip地址、端口号、服务唯一id、服务名、服务的多个tag
consul services register -address=124.3.2.4 -port=4458 -id=1234001 -name=mysvr-rpc -tag=v.1.1 -tag=user

为服务注册添加健康检查

heath.json

{
  "ID": "service:1234001",
  "Name": "自定义结点健康检查",
  "Notes": "回调http接口查看",
  "DeregisterCriticalServiceAfter": "30s",
  "HTTP": "http://ip:port/consul/health/?id=555",
  "Method": "GET",
  "Interval": "10s",
  "Timeout": "5s",
  "ServiceID":"1234001"
}
- ID: 健康检查的唯一id,类似于db里面的主键
- Name: 健康检查的名字,后续可以在自带的web面板展示出来
- DeregisterCriticalServiceAfter: 代表服务停止多久后进行注销该服务
- HTTP: 去哪个地址检测服务的健康状态
- Method: 发送请求的方式
- Interval:健康检查时间间隔,即心跳间隔
- Timeout:请求超时时间
- ServiceID:额外参数,如果指定则是检测具体某个服务的健康状态,不指定则是consul的agent健康状态
# heath.json 定义的是只针对某个服务结点的健康检查,直接从文件中读取具体的数据
curl --request PUT --data @heath.json http://127.0.0.1:8500/v1/agent/check/register

服务卸载

# 根据服务的唯一id卸载服务
consul services deregister -id=1234001

获取所有健康检查条目

curl http://127.0.0.1:8500/v1/agent/checks

获取服务信息

# 只返回健康没问题的
curl http://127.0.0.1:8500/v1/health/service/mysvr-rpc?passing=1

go-consul实战

服务注册

package consul

import (
	"context"
	"fmt"
	"google.golang.org/grpc/health/grpc_health_v1"
	"log"
	"strings"

	"github.com/hashicorp/consul/api"
	uuid "github.com/satori/go.uuid"
)

const (
	consulIp   = "10.248.174.155"
	consulPort = "8500"
)

func RandomStr(len int) string {
	nUid := uuid.NewV4().String()
	str := strings.Replace(nUid, "-", "", -1)
	if len < 0 || len >= 32 {
		return str
	}
	return str[:len]
}

// HttpReg 服务注册时候提供一个健康检查地址,支持http,grpc
func HttpReg(svrName string, ipAddr string, port int) string {
	// 创建Consul客户端连接
	client, err := api.NewClient(&api.Config{
		Address: fmt.Sprintf("http://%v:%v", consulIp, consulPort),
	})
	if err != nil {
		log.Fatalf("client 创建失败,退出:%v\n", err)
	}
	svrID := RandomStr(32)
	// 设置Consul对服务健康检查的参数
	check := api.AgentServiceCheck{
		HTTP:                           fmt.Sprintf("http://%v:%v/consul/health/?id=%v", "127.0.0.1", 80, svrID), // 健康检查地址,自定义ip和端口
		Interval:                       "3s",                                                                        // 健康检查频率
		Timeout:                        "2s",                                                                        // 健康检查超时
		Notes:                          "Consul 代码健康检查",
		DeregisterCriticalServiceAfter: "5s", // 健康检查失败30s后 consul自动将注册服务删除
		Name:                           "代码自定义检查svr1",
		//GRPC:     fmt.Sprintf("%v:%v/%v", svcHost, svcPort, "svrName"),
	}

	//设置微服务向Consul注册信息
	reg := &api.AgentServiceRegistration{
		ID:      svrID,                      // 服务节点的ID
		Name:    svrName,                    // 服务名称
		Address: ipAddr,                     // 服务IP
		Port:    port,                       // 服务端口
		Tags:    []string{"v1.1", "backup"}, // 标签,可在服务发现时筛选服务,类似v1.1
		Check:   &check,                     // 健康检查
	}

	// 执行注册
	if err := client.Agent().ServiceRegister(reg); err != nil {
		log.Fatalln(err)
	}
	return svrID
}
//HttpUnReg 服务卸载
func HttpUnReg(svrID string) {
	// 创建Consul客户端连接
	client, err := api.NewClient(&api.Config{
		Address: fmt.Sprintf("http://%v:%v", consulIp, consulPort),
	})
	if err != nil {
		log.Fatalf("client 创建失败,退出:%v\n", err)
	}

	// 执行服务卸载
	if err := client.Agent().ServiceDeregister(svrID); err != nil {
		log.Fatalln(err)
	}
}

//========如果使用grpc接口实现健康检查,则需要实现HealthServer 接口,服务启动时候注册这个pb==========

// HealthImpl 健康检查实现
type HealthImpl struct{}

// Check 实现健康检查接口,这里直接返回健康状态
func (h *HealthImpl) Check(ctx context.Context, req *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) {
	return &grpc_health_v1.HealthCheckResponse{
		Status: grpc_health_v1.HealthCheckResponse_SERVING,
	}, nil
}

// Watch 让HealthImpl实现RegisterHealthServer内部的interface接口
func (h *HealthImpl) Watch(req *grpc_health_v1.HealthCheckRequest, w grpc_health_v1.Health_WatchServer) error {
	return nil
}

服务注册单元测试

package consul

import (
	"fmt"
	"github.com/hashicorp/consul/api"
	"log"
	"testing"
	"time"
)

func TestClient(t *testing.T) {

	// Get a new client
	client, err := api.NewClient(&api.Config{
		Address: "http://10.248.174.155:8500",
	})
	if err != nil {
		log.Fatalln(err)
	}

	// Get a handle to the KV API
	kv := client.KV()

	// PUT a new KV pair
	p := &api.KVPair{Key: "my-svr", Value: []byte("1000"), Flags: 32}
	_, err = kv.Put(p, nil)
	if err != nil {
		log.Fatalln(err)
	}

	// Lookup the pair
	pair, _, err := kv.Get("my-svr", nil)
	if err != nil {
		log.Fatalln(err)
	}

	fmt.Printf("KV: %v %s\n", pair.Key, pair.Value)
}

func TestHttpReg(t *testing.T) {
	svrID := HttpReg("mysvr-rpc", "127.0.0.1", 3456)
	log.Printf("服务注册成功:%v\n", svrID)
	for true {
		// 制定一个定时器,模拟20s后摘除服务
		t := time.NewTicker(20 * time.Second)
		select {
		case tt := <-t.C:
			HttpUnReg(svrID)
			log.Printf("服务卸载,tt:%v\n", tt)
			return
		}
	}
}

服务发现

package consul

import (
	"fmt"
	"github.com/hashicorp/consul/api"
	"log"
)

// GetNode 没有watch的api 无法感知结点的变更,如果做本地缓存则需要启动协程去定时轮询,全量更新到本地缓存
func GetNode(svrName string) {
	// 创建Consul客户端连接
	client, err := api.NewClient(&api.Config{
		Address: fmt.Sprintf("http://%v:%v", consulIp, consulPort),
	})
	if err != nil {
		log.Fatalf("client 创建失败,退出:%v\n", err)
	}

	// 根据服务名和tag 是否健康检查通过 以及其它option 筛选service实例
	service, meta, serr := client.Health().Service(svrName, "", true, nil)
	log.Printf("结束svr%+v,meta:%+v, err:%v\n", service, meta, serr)
	for _, s := range service {
		fmt.Printf("服务:%+v\n", s.Service)
	}

}

服务发现单元测试

package consul

import "testing"

func TestGetNode(t *testing.T) {
	GetNode("mysvr-rpc")
}

总结

举报

相关推荐

0 条评论