Skip to main content

Consul

DNS解析

  1. 输入URL网址。
  2. 通过DNS服务器(或hosts文件)找到对应网址的IP地址。
  3. 向对应的IP地址服务器发送请求。
  4. 服务器接收请求并处理。
  5. 服务器向客户端响应相关资源。

微服务中心

微服务中心也叫服务发现,是微服务架构中的一个核心组件或工具,用于解决在分布式系统中各个服务如何相互定位和通信的问题,可以管理、协调和监控分布式微服务的运行。

  1. 统一管理服务配置。
  2. 监控服务的监控状况。
  3. 提供服务的发现与接入。
  4. 服务的注册、注销、服务的信息。
  5. HTTP访问、DNS解析等。
  6. 存储数据。

Client Side

API Gateway Layer

Microservices Center

Register

Register

Register

Discover

Discover

Discover

Routes

Routes

Routes

Request

Service Registry

Service A

Service B

Service C

Database A

Database B

Database C

API Gateway

Client

Docker

VM

软件开发时经常会遇到软件运行的环境问题,如不兼容、支持配置等。

为了解决此问题,虚拟机技术到来。它是一个小型的操作系统,可在操作系统中以软件的形式安装,并基于此系统运行相关软件。但也产生了一些问题:

  1. 虚拟机占用系统资源过多。
  2. 系统有一些访问权限,配置比较复杂。
  3. 性能与速度无法保证。

Docker

Docker是一种开源的平台,用于开发、部署和运行应用程序。它通过使用容器化技术,使应用程序可以在不同环境下轻松地运行,而不必担心环境差异引起的问题。

Docker是基于Linux操作系统开发的一套虚拟化技术,是Linux容器技术功能性封装的产物,它不是操作系统,而是基于宿主系统的一个进程隔离。

  1. 由于其不是操作系统,因此启动比较快。
  2. 动态资源分配,资源占用容易优化。
  3. 体积小,不是一个系统级的体量。
  4. 使用灵活,拓展性强。
// 安装
brew install --cask docker

// 查看版本
docker -v

// 查询docker镜像
docker images

// 查询容器
docker ps -a

Consul

Consul是一个服务发现与可视化管理服务的工具。

安装与启动

使用Docker安装Consul:

docker pull hashicorp/consul:latest

通过docker run命令启动Consul:

docker run -d -p 8500:8500 -p 8600:8600/udp -p 8300:8300 -p 8301:8301 -p 8302:8302 hashicorp/consul consul agent -dev -client=0.0.0.0
  • 8500:提供服务的列表、注册服务、注销服务、HTTP接口、可视化工具
  • 8600:提供DNS服务发现。
  • 8300:同一个数据中心,服务之间使用该端口通信。
  • 8301:同一个数据中心,客户端之间使用该端口通信。
  • 8302:不同的数据中心,服务之间使用该端口通信。
// 重启consul
docker container update --restart=always containerId

API

Consul提供了API接口,可通过接口进行相关操作,如注册、注销等。

服务注册

Consul 可直接进行 HTTP 服务的注册:

type ServiceMap = map[string]*api.AgentService

func ServiceRegister(
hostInfo config.Host,
consulInfo config.Consul,
serviceInfo config.UserWebApi,
) error {
// 创建 consul 客户端, 健康检查和服务注册需要通过客户端完成
client, err := createClient(hostInfo.IP, consulInfo.PORT)

if err != nil {
return err
}

// 健康检查配置
healthCheck := &api.AgentServiceCheck{
HTTP: fmt.Sprintf("%s://%s:%d%s", serviceInfo.Scheme, hostInfo.IP, serviceInfo.PORT, serviceInfo.Path),
Timeout: consulInfo.Timeout,
Interval: consulInfo.Interval,
DeregisterCriticalServiceAfter: consulInfo.Deregister,
}

// 注册服务的配置,一般通过配置文件提供
reg := new(api.AgentServiceRegistration)
reg.Address = hostInfo.IP
reg.Port = serviceInfo.PORT
reg.Name = serviceInfo.Name
reg.ID = serviceInfo.Name
// 关联健康检查
reg.Check = healthCheck
reg.Tags = serviceInfo.Tags

// 通过客户端注册服务
e := client.Agent().ServiceRegister(reg)

if e != nil {
return e
}

return nil
}

func createClient(addr string, port int) (*api.Client, error) {
cfg := api.DefaultConfig()
cfg.Address = fmt.Sprintf("%s:%d", addr, port)

client, err := api.NewClient(cfg)

if err != nil {
return nil, err
}

return client, nil
}

服务查询

Consul 也可通过 API 进行服务查询与过滤

func ServiceFilter(addr string, port int, filter string) (ServiceMap, error) {
client, err := createClient(addr, port)

if err != nil {
return nil, err
}

services, e := client.Agent().ServicesWithFilter(filter)

if e != nil {
return nil, e
}

return services, nil
}

// services, e := lib.ServiceList(cfg.Host.IP, cfg.Consul.PORT,"")
// services, e := lib.ServiceFilter(cfg.Host.IP, cfg.Consul.PORT, `Service == "user_web_api"`)
// services, e := lib.ServiceFilter(cfg.Host.IP, cfg.Consul.PORT, `api in Service`)

gRPC服务

由于 gRPC 不是普通的 HTTP服务,需要借助官方工具包进行注册:

import (
// Google官方健康检查包
"google.golang.org/grpc/health"
"google.golang.org/grpc/health/grpc_health_v1"
)

func main() {
// ...

// 注册服务健康检查
grpc_health_v1.RegisterHealthServer(gServer, health.NewServer())

// 注册 consul 服务
err := utils.ServiceRegister(*cfg.Consul, *cfg.GRPC)

// ...
}

func ServiceRegister(consulInfo config.Consul, serviceInfo config.GRPC) {
// ...

healthCheck := &api.AgentServiceCheck{
GRPC: fmt.Sprintf("%s:%d", serviceInfo.Host, serviceInfo.Port),
Timeout: consulInfo.Timeout,
Interval: consulInfo.Interval,
DeregisterCriticalServiceAfter: consulInfo.Deregister,
}

// ...
}

type Consul struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Timeout string `mapstructure:"timeout"`
Interval string `mapstructure:"interval"`
Deregister string `mapstructure:"deregister"`
}

type GRPC struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Name string `mapstructure:"name"`
Tags []string `mapstructure:"tags"`
}

开启多微服务

  • IDE 启动两次,会重启服务。
  • 终端启动两次服务,由于 Consul 的 ID 是同一个,Consul 认为是同一个实例,因此会覆盖。
  • 每次启动都创建不同的 ID 到 Consul 进行注册
import (
uuid "github.com/satori/go.uuid"
)

func main() {
// ...

serviceId := fmt.Sprintf("%s-%s", cfg.GRPC.Name, uuid.NewV4())

// ServiceRegister(serviceId)
}

负载均衡

实际业务中,微服务通常也需要进行负载均衡,而 GRPC 内置了对外的接口,方便进行配置:

import (
_ "github.com/mbobakov/grpc-consul-resolver"
)

func GrpcDial(cfg config.Consul) (*grpc.ClientConn, error) {
conn, err := grpc.NewClient(
// 服务集合
fmt.Sprintf("consul://%s:%d/%s?wait=14s", cfg.IP, cfg.PORT, cfg.Name),
grpc.WithTransportCredentials(insecure.NewCredentials()),
// 负载均衡轮询
grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy": "round_robin"}`),
)

return conn, err
}