微服务系列Consul的介绍与安装

Posted 清风拂山岗

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微服务系列Consul的介绍与安装相关的知识,希望对你有一定的参考价值。

微服务系列(三)Consul的介绍与安装

1.Consul简介

Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置。包含多个组件,但是作为一个整体,为你的基础设施提供服务发现和服务配置的工具.他提供以下关键特性:

  • 服务发现:consul提供服务,服务端主动向consul发起注册。

  • 健康检查:健康检测使consul可以快速的告警在集群中的操作。和服务发现的集成,可以防止服务转发到故障的服务上面。(心跳机制)

  • 键/值存储:一个用来存储动态配置的系统。提供简单的HTTP接口,可以在任何地方操作。

  • 多数据中心:无需复杂的配置,即可支持任意数量集群搭建。

2.Consul 安装说明

Consul用Golang实现,因此具有天然可移植性 (支持 Linux、windows和macOS)。安装包仅包含一个可执行文件。 Consul安装非常简单,只需要下载对应系统的软件包并解压后就可使用。

安装步骤如下:

# 这里以 ubuntu系统为例:
$ wget https://releases.hashicorp.com/consul/1.5.2/consul_1.5.2_linux_amd64.zip
$ unzip consul_1.5.2_linux_amd64.zip
$ sudo mv consul /usr/local/bin/

输入consul -h命令显示如下信息即为安装成功:

image-20210604212840033

3.Consul 常用命令

consul agent:是consul的核心指令,它运行agent来维护成员的重要信息、运行检查、服务宣布、查询处理等等。其中重要的参数如下:

-bind=0.0.0.0			指定 consul所在机器的IP地址。 默认值:0.0.0.0
-http-port=8500		consul 自带一个web访问的默认端口:8500
-client=127.0.0.1		表明哪些机器可以访问consul 。 默认本机。0.0.0.0 所有机器均可访问。
-config-dir=foo      	所有主动注册服务的 描述信息
-data-dir=path        储存所有注册过来的server机器的详细信息。
-dev                  开发者模式,直接以默认配置启动 consul
-node=hostname  		服务发现的名字。
-rejoin               consul 启动的时候,加入到的 consul集群
-server               以服务方式开启consul, 允许其他的consul 连接到开启的 consul上 (形成集群)。如果不加 -server, 表示以 “客户端” 的方式开启。不能被连接。
-ui 		            可以使用 web 页面 来查看服务发现的详情

测试上述命令:

# 在终端中,键入:
consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -node=n1 -bind=192.168.19.101 -ui -rejoin -config-dir=/etc/consul.d/ -client 0.0.0.0

#看到提示:
==> Consul agent running!

启动浏览器,输入192.168.19.101:8500(虚拟机+端口号)测试:

image-20210605093031850

注册服务到 consul 并查看

步骤:

  1. 进入配置文件路径

    cd  /etc/consul.d/
    
  2. 创建 json 文件

     sudo vim web.json
    
  3. shell按 json 的语法,填写 服务信息。

    {"service": {
        "name": "myfirstconsul",
        "tags": ["first","consul"],
        "port": 8800
    	}
    }
    
  4. 重新启动 consul

    consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -node=n1 -bind=192.168.19.101 -ui -rejoin -config-dir=/etc/consul.d/ -client 0.0.0.0
    
  5. 查询服务

    image-20210605095809359

健康检查

健康检查是服务发现的关键组件,预防使用到不健康的服务。和服务注册类似,一个检查可以通过检查定义或HTTP API请求来注册。

  1. 打开配置文件

    sudo vim /etc/consul.d/check.json  
    
  2. 写入 服务的配置信息。

    {
    	"service":{
    		"name":"web",
    		"tags":["ahnu","computer"],
    		"address":"192.168.19.101",
    		"port":8800,
    		"check":{
    			"id":"api",
    			"name":"Health check",
    			"http":"http://192.168.19.101:8800", // http形式的健康检查
    			"interval":"5s", // 按照预设的时间间隔创建一个HTTP “get”请求
    			"timeout":"1s"	// 服务没有给consul回复的超时时间
    		}
    	}
    }
    
    
  3. 执行命令consul reload重新加载配置文件关闭consul 再重启。

  4. 使用 浏览器 键入 192.168.19.101:8500 查看 “web” 这个服务 的健康状况

    image-20210605101826848

    不健康!服务web没有给 consul 实时回复!

注意:consul做健康检查的必须是HTTP、Script脚本、TCP、TTL中的一种。

4.Consul 和 grpc 结合

安装 consul 源码包:

$ go get -u -v github.com/hashicorp/consul

使用整体流程

  1. 创建 proto文件 , 指定 rpc 服务
  2. 启动 consul 服务发现 consul agent -dev开发者模式
  3. 启动server
    1. 获取consul 对象
    2. 使用 consul对象,将 server 信息,注册给 consul
    3. 启动服务
  4. 启动client
    1. 获取consul 对象
    2. 使用consul对象,从consul 获取健康的服务
    3. 再访问服务 (grpc远程调用)

编码实现

  • 用到的函数:

    // 从 consul 服务发送上获取 健康服务
    func (h *Health) Service(service, tag string, passingOnly bool, q *QueryOptions) ([]*ServiceEntry, *QueryMeta, error)
    
    // 参数:
    service: 服务名。 -- 注册服务时,指定该string
    tag:外名/别名。 如果有多个,任选一个
    passingOnly:是否通过健康检查。 true
    q:查询参数。 通常传 nil
    // 返回值:
    ServiceEntry: 存储服务的切片,一个集群共用一个服务名。
    QueryMeta:额外查询返回值。 nil
    error: 错误信息
    
  • proto文件

    // 默认proto2
    syntax="proto3";
    
    package pb;
    option go_package="../pb";
    
    // 设置消息
    message Person{
      string name=1;
      int32 age=2;
    }
    
    // 添加 rpc服务
    service hello{
      rpc sayHello(Person) returns (Person);
    }
    

    编译protobuf文件protoc --go_out=plugins=grpc:./ *.proto

  • 服务端

    package main
    
    import (
    	"context"
    	"fmt"
    	"github.com/hashicorp/consul/api"
    	"google.golang.org/grpc"
    	"iHome/day02/pb"
    	"net"
    )
    
    type Children struct {
    
    }
    
    func (c *Children) SayHello(ctx context.Context,p *pb.Person) (*pb.Person,error)  {
    	p.Name += "你好"
    	p.Age = 18
    	return p,nil
    }
    
    
    func main(){
    	// 把 grpc 服务注册到consul上
    	// 1.初始化consul配置
    	consulConfig := api.DefaultConfig()
    
    	// 2.创建 consul 对象
    	consulClient, err := api.NewClient(consulConfig)
    	if err != nil {
    		fmt.Printf("创建consul对象失败:%v",err)
    		return
    	}
    
    	// 3.告诉 consul ,即将注册的服务的配置信息
    	registration := api.AgentServiceRegistration{
    		ID:      "web",
    		Tags:    []string{"grpc", "consul"},
    		Name:    "Consul and gRPC",
    		Port:    8800,
    		//Address: "127.0.0.1",
    		Address: "192.168.19.101",
    		Check: &api.AgentServiceCheck{
    			CheckID:  "consul grpc test",
    			//TCP: "127.0.0.1:8800",
    			TCP: "192.168.19.101:8800",
    			Interval: "5s",
    			Timeout:  "1s",
    		},
    	}
    
    	// 4.注册 grpc 服务到 consul 上
    	err = consulClient.Agent().ServiceRegister(&registration)
    	if err != nil {
    		fmt.Printf("注册grpc到consul上失败:%v",err)
    		return 
    	}
    ///////////////////////以下为 grpc 服务的远程调用////////////////////////
    	// 1.初始化一个grpc对象
    	grpcServer := grpc.NewServer()
    
    	// 2.注册服务
    	pb.RegisterHelloServer(grpcServer,new(Children))
    
    	// 3.设置监听并建立连接,指定ip和端口号
    	//listener, err := net.Listen("tcp","127.0.0.1:8800")
    	listener, err := net.Listen("tcp","192.168.19.101:8800")
    	if err != nil {
    		fmt.Printf("监听失败:%v",err)
    		return
    	}
    	defer listener.Close()
    	//fmt.Println("开始监听127.0.0.1:8800 ...")
    	fmt.Println("开始监听192.168.19.101:8800 ...")
    
    	// 4.启动服务 Serve()
    	err = grpcServer.Serve(listener)
    	if err != nil {
    		panic(err)
    	}
    
    }
    
  • 客户端

    package main
    
    import (
    	"context"
    	"fmt"
    	"github.com/hashicorp/consul/api"
    	"google.golang.org/grpc"
    	"iHome/day02/pb"
    	"strconv"
    )
    
    func main(){
    	// 1.初始化Consul配置
    	consulConfig := api.DefaultConfig()
    
    	// 2.创建consul对象  (可以重新指定consul的属性)
    	consulClient, err := api.NewClient(consulConfig)
    	if err != nil {
    		fmt.Printf("创建consul对象失败:%v",err)
    		return
    	}
    
    	// 3.服务发现 从 consul 上获取健康的服务
    	service, _, err := consulClient.Health().Service("Consul and gRPC", "grpc", true, nil)
    	if err != nil {
    		fmt.Printf("服务发现阶段错误:%v",err)
    		return
    	}
    
    	// 获取ip地址+端口号的地址
    	ip := service[0].Service.Address
    	port := service[0].Service.Port
    	target := ip+":"+strconv.Itoa(port)
        
    ///////////////////////以下为 grpc 服务的远程调用///////////////////////
    	// 1.连接grpc服务
    	//grpcConn, err := grpc.Dial("127.0.0.1:8800",grpc.WithInsecure())
    	grpcConn, err := grpc.Dial(target,grpc.WithInsecure())
    	if err != nil {
    		fmt.Printf("连接拨号失败:%v",err)
    		return
    	}
    	defer grpcConn.Close()
    
    	// 2.初始化grpc客户端
    	grpcClient := pb.NewHelloClient(grpcConn)
    
    	var child pb.Person
    	child.Name = "小宝"
    
    	// 3.调用远程服务
    	hello, err := grpcClient.SayHello(context.TODO(), &child)
    	if err != nil {
    		fmt.Printf("调用远程服务失败:%v",err)
    		return
    	}
    	fmt.Println(hello)
    }
    
    

服务注销

package main

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

func main() {
	// 1.初始化consul配置
	consulConfig := api.DefaultConfig()

	// 2.创建consul对象
	consulClient, err := api.NewClient(consulConfig)
	if err != nil {
		fmt.Printf("创建consul对象失败:%v",err)
		return
	}

    
	// 3.注销服务
	err = consulClient.Agent().ServiceDeregister("web")
	if err != nil {
		panic(err)
	}
}

以上是关于微服务系列Consul的介绍与安装的主要内容,如果未能解决你的问题,请参考以下文章

微服务-SpringCloud学习系列:注册中心Consul

Spring Boot实战系列集成Consul配置中心

Golang 语言微服务的服务发现组件 Consul 的系统架构介绍

3分钟就会系列使用Ocelot+Consul搭建微服务吧!

Centos安装Consul微服务

.NETCore微服务之:基于Consul实现服务治理