go-kit微服务,服务注册与发现,负载均衡(二)

consul简介

Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案,Consul的方案更“一站式”,内置了服务注册与发现框 架、具有以下性质:

分布一致性协议实现、
健康检查、
Key/Value存储、
多数据中心方案,
不再需要依赖其他工具(比如ZooKeeper等)。

使用起来也较 为简单。Consul使用Go语言编写,因此具有天然可移植性(支持Linux、windows和Mac OS X);安装包仅包含一个可执行文件,方便部署,与Docker等轻量级容器可无缝配合 。
基于 Mozilla Public License 2.0 的协议进行开源. Consul 支持健康检查,并允许 HTTP 和 DNS 协议调用 API 存储键值对.
一致性协议采用 Raft 算法,用来保证服务的高可用. 使用 GOSSIP 协议管理成员和广播消息, 并且支持 ACL 访问控制.

consul安装

这里使用consul,当然用etcd等也ok
详细内容参见官网文档:https://www.consul.io/api-docs/agent/service
首先搭建一个注册中心,可以直接docker起,这里部署一个单节点

sudo docker run --name=consul -itd -p 8500:8500 consul agent -server -bootstrap -ui -client 0.0.0.0

执行结果如下
在这里插入图片描述

说明:

  • 8500端口是consul需要访问的端口
  • -server 表示以服务端启动consul
  • -bootstrap 不需要选举,直接指定自己为leader
  • -ui 启动ui界面
  • -client 0.0.0.0 监听地址

测试访问虚拟机地址加8500端口即可访问consul界面,此时还没有任何数据
在这里插入图片描述

手动操作

这里基于apizza手动注册一个服务
consul service 是一个web服务,所有相关操作通过请求完成,请求内容和url参考文档如下截图:

  • Method : PUT
  • URL: http://192.168.10.10:8500/v1/agent/service/register?replace-existing-checks=true 注意,这里的地址192.168.10.10:8500 是我的安装consul服务的虚拟机的地址和consul开放的端口
  • Header:Content-Type:application/json
  • Body : 参考官方文档
    在这里插入图片描述
    点击发送后,通过浏览器查看注册情况,这里已经注册了我们的服务
    在这里插入图片描述

其余略,参考官方文档:https://www.consul.io/api-docs/agent/service

代码操作

首先下载cansul包,cansul也是go开发的项目,我大golang在分布式服务领域天下无双

go get github.com/hashicorp/consul/api

代码注册的本质还是http请求,但是consul自带的api包帮我们实现很多功能,不bb,上代码

首先声明一个控制类,并实现连接consul服务的方法

type ConsulContrl struct {
	Client *api.Client
	Config * api.AgentServiceRegistration
}

func ConnConsul(addr string)(*ConsulContrl,error){
	csc := new(ConsulContrl)
	config := api.DefaultConfig()
	config.Address = addr
	var err error
	csc.Client,err = api.NewClient(config)
	return csc,err
}

服务注册

这里我自己写了一个默认的配置

func (c * ConsulContrl)Regist(config *api.AgentServiceRegistration)error{
	if config !=nil{
		c.Config = config
	}else {
		c.Config = &api.AgentServiceRegistration{
			Kind:              "HTTP",
			ID:                "mytestserver",
			Name:              "myserver",
			Tags:              []string{"haha","hehe"},
			Port:              666,
			Address:           "192.168.10.106",
			EnableTagOverride: false,
			Meta: map[string]string{"haha":"hehe"},
			Weights:           &api.AgentWeights{
				Passing: 10,
				Warning: 1,
			},
			Check:             &api.AgentServiceCheck{
				Interval:                       "10s",
				Timeout:                        "5s",
				HTTP:                           "http://192.168.10.106:666/health",
				Method:                         "GET",
			},
		}
	}
	var err error
	if err = c.Client.Agent().ServiceRegister(c.Config);err!=nil{
		return err
	}
	return nil
}

服务反注册

func (c * ConsulContrl)Deregister()error{
	return c.Client.Agent().ServiceDeregister(c.Config.ID)
}

拉取服务list

func (c*ConsulContrl)ServiceList()(map[string]*api.AgentService,error){
	return c.Client.Agent().Services()
}

服务发现

//consul方法
func (c *ConsulContrl)GetServiceConfiguration(serverid string)(*api.AgentService,error){
	server,_,err:= c.Client.Agent().Service(serverid,nil)
	return server,err
}

//结合gokit的服务发现
//返回一个发现实例,引用:github.com/go-kit/kit/sd/consul
func (c * ConsulContrl)GetInstancer(service string,tage []string)*consul.Instancer{
	return consul.NewInstancer(consul.NewClient(c.Client) ,log.NewLogfmtLogger(os.Stdout),service,tage,true)
}


测试代码

	go func(){
		<- time.After(time.Second*3)
		s,err := cscontrol.ConnConsul("192.168.10.10:8500")
		if err!=nil{
			fmt.Println(err)
			return
		}
		if s.Regist(nil)!=nil{
			fmt.Println(err)
			return
		}
		list,err :=s.ServiceList()
		if err!=nil{
			fmt.Println(err)
			return
		}
		fmt.Printf("%v\n",*list["mytestserver"])

		self ,err := s.GetServiceConfiguration("mytestserver")
		if err!=nil{
			fmt.Println(err)
			return
		}
		fmt.Printf("%v\n",self)
		s.Deregister()
	}()

输出打印
在这里插入图片描述

负载均衡

结合服务发现,写一个创建负载均衡的方法

//添加引用  kithttp "github.com/go-kit/kit/transport/http"
func GetUserEndpointer(service string,tag []string,methond string,e kithttp.EncodeRequestFunc,d kithttp.DecodeResponseFunc,logf log.Logger) lb.Balancer {
	//func(ctx context.Context, request interface{}) (response interface{}, err error)
	f := func(instance string) (endpoint.Endpoint, io.Closer, error){
	    //这里的instance 是从consul中读取到的service的address,就是ip+端口
		u,err:= url.Parse("http://"+instance)
		if err!=nil{
			return nil,nil,err
		}
		//NewClient创建一个http的客户端,先编码函数,再解码函数,和server相反
		client:= kithttp.NewClient(methond,u,e,d)
		return client.Endpoint(),nil,nil
	}
	//结合服务发现创建负载均衡
	//第一个参数中的util.DefaultConsul是ConsulContrl 
	per:= sd.NewEndpointer(util.DefaultConsul.GetInstancer(service,tag),f,logf)
	//创建轮询负载均衡
	return lb.NewRoundRobin(per)
	//创建随机负载均衡
	//return lb.NewRandom(per,time.Now().UnixNano())
}

生成一个子服务的负载均衡

//连接consul后,创建负载均衡
bal = GetUserEndpointer("usermanage",[]string{"user"},"GET",EncodeUser,DecodeUser,log.NewLogfmtLogger(os.Stdout))


func EncodeUser(_ context.Context,r *http.Request,requ interface{}) error{
	//TODO
	//编码方法,执行完此方法后访问子服务
	return nil
}
func DecodeUser(_ context.Context,r *http.Response) (response interface{}, err error){
	//TODO
	//解码方法
	return string(data),nil
}

使用这个负载均衡

//具体的业务调用
func (u *UserService) GetName(userid int) string {
    //从负载均衡中取出一个服务方法
	end,err := bal.Endpoint()
	if err!=nil{
		return err.Error()
	}
	//执行这个方法
	resp,err:= end(context.Background(),nil)
	if err!=nil{
		return err.Error()
	}
	return resp.(string)
}

未完待续

猜你喜欢

转载自blog.csdn.net/qq_25490573/article/details/106802494