Go微服务: go-micro集成consul的注册中心和配置中心

微服务与注册中心的关系图

  • 这个图很好说明了微服务之间的关系,以及consul注册中心的重要性

环境准备

1 )consul 集群

  • 假设consul 集群已经搭建,已有5台server和2台client
  • 这里2台client被nginx做负载均衡,假设最终本地的访问地址是: http://localhost:8500
  • 如何做 consul 环境搭建,请在我的博客列表中搜索关键字: "consul"

2 )consul 中设置mysql的配置文件

  • 假设目前只有一个数据中心,如果有多个,则配置多个即可

  • 在consul的ui界面上的 Key / Value 菜单中配置,点击 Create 按钮

  • Key or folder 中 填入:micro/config/mysql

  • Value 中填入下面的json文件

    json 复制代码
    {
    	"host": "127.0.0.1",
    	"port": 3307,
    	"user": "root",
    	"pwd": "123456_mysql",
    	"database": "micro"
    }
  • 以上只是举例一种简单的mysql的配置,到生产环境,则进行生产的配置

  • 以此我们就完成了 consul 的搭建和配置 (搭建部分这里省略)

go-micro 代码集成

1 )结构介绍

  • 在当前项目中,假设目前当前模块仓库是 gitee.com/go-micro-services/category
  • 从命名中我们知道,当前这个仓库会同步到远程,不做赘述
  • common 目录作为通用的工具函数目录
  • domain 目录中分别定义了三个目录:model, repository, service
    • model 是定义的实体类,数据模型
    • repository 是基本数据库操作类,编写与数据库的映射关系
    • service 是基于repository封装的业务类
  • handler 目录暴露出来的服务
    • 在 proto 里面生成的服务,必须在 handler 中有所体现

2 )common 核心代码参考 common/config.go

go 复制代码
package common

import (
	"encoding/json"
	"log"

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

// 定义一个map,key是字符串,value是api客户端或nil
var consulClients = make(map[string]*api.Client)

// 获取配置中心客户端
func getConsulClient(address string) (*api.Client, error) {
	// 1. 从map中获取客户端
	client := consulClients[address]
	// 2. 如果存在,则直接返回
	if client != nil {
		return client, nil
	}
	// 3. 如果不存在,则新建
	config := api.DefaultConfig()
	config.Address = address
	client, err := api.NewClient(config)
	if err == nil {
		consulClients[address] = client // 没有错误进行挂载
	}
	// 4. 返回
	return client, err
}

// 设置配置中心
func getConsulConfig(Address string, path string) (*api.KVPair, error) {
	// 1. 获取 Consul客户端
	client, clientErr := getConsulClient(Address)
	if clientErr != nil {
		log.Fatal(clientErr)
	}

	// 2. 创建KV客户端
	kv := client.KV()

	// 3. 基于path读取pair
	pair, _, getErr := kv.Get(path, nil)
	return pair, getErr
}

func GetConsulMysqlConfig(address string, path string) (MysqlConfig, error) {
	// 1. 获取 pair
	pair, consulErr := getConsulConfig(address, path)
	if consulErr != nil {
		log.Fatal(consulErr)
	}

	// 2. 解析JSON字符串为 MysqlConfig 结构体
	var mysqlConfig MysqlConfig
	err := json.Unmarshal(pair.Value, &mysqlConfig)
	return mysqlConfig, err
}
  • 可以看到,在上述代码中使用一个map来缓存客户端的创建过程
  • 以便后期可能调用其他可能的consul服务进行了扩展,提升一个性能
  • 同时,这里也有个mysql的配置封装

3 )main.go 核心代码

go 复制代码
package main

import (
	"fmt"
	"log"
	"strconv"

	"github.com/go-micro/plugins/v4/registry/consul"
	"go-micro.dev/v4"
	"go-micro.dev/v4/registry"

	"gitee.com/go-micro-services/category/common"

	"gitee.com/go-micro-services/category/domain/repository"
	"gitee.com/go-micro-services/category/domain/service"
	"gitee.com/go-micro-services/category/handler"
	pbcategory "gitee.com/go-micro-services/category/proto/category"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

var (
	serviceName = "go.micro.service.category"
	version     = "latest"
	host        = "127.0.0.1"
	port        = 8500
	address     = host + ":" + strconv.Itoa(port)
	configPath  = "/micro/config/mysql"
)

func main() {
	// 1. 注册中心
	consulReg := consul.NewRegistry(
		registry.Addrs(address),
	)

	// 2. 创建服务
	srv := micro.NewService()
	srv.Init(
		micro.Name(serviceName),
		micro.Version(version),
		micro.Registry(consulReg),
	)

	// 3. 从配置中心获取mysql配置并创建处理
	mysqlConfig, consulConfigErr := common.GetConsulMysqlConfig(address, configPath)
	if consulConfigErr != nil {
		log.Fatal(consulConfigErr)
	}
	mysqlUrl := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local", mysqlConfig.User, mysqlConfig.Pwd, mysqlConfig.Host, mysqlConfig.Port, mysqlConfig.Database)
	db, dbErr := gorm.Open("mysql", mysqlUrl)
	if dbErr != nil {
		log.Fatal(dbErr)
	}
	defer db.Close()
	db.SingularTable(false) // true 则 表就是单数

	// 数据库表初始化,只执行一次, 如果本来就设计好了,则无需下面2行
	// rp := repository.NewCategoryRepository(db)
	// rp.InitTable()

	// 4. 创建服务实例
	categoryDataService := service.NewCategoryDataService(repository.NewCategoryRepository(db))

	// 5. 注册 handler
	if handlerErr := pbcategory.RegisterCategoryHandler(srv.Server(), &handler.Category{CategoryDataService: categoryDataService}); handlerErr != nil {
		log.Fatal(handlerErr)
	}

	// 6. 运行服务
	if runErr := srv.Run(); runErr != nil {
		log.Fatal(runErr)
	}
}
  • 以上展示了服务集成的所有步骤,从 consul 配置中心中获取配置信息
  • 之后基于这些数据连接mysql, 进行数据和服务的初始化
  • 这里代码一目了然,不再一一进行解释

4 )其他说明

  • 这里不对其他模块的代码做一一说明,我们的目的是在go-micro中集成完成 consul
  • 这里 category 这个代码仓库是一个微服务,也就是说,每个微服务都需要注册到consul, 以便对微服务进行有效的管理
  • 同时,后期网关在调用微服务的时候,网关服务也要注册到consul中
  • 其他不是本文核心代码不做举例
相关推荐
tyler_download2 小时前
golang 实现比特币内核:处理椭圆曲线中的天文数字
golang·blockchain·bitcoin
想进大厂的小王3 小时前
Spring-cloud 微服务 服务注册_服务发现-Eureka
微服务·eureka·服务发现
疯狂的程需猿3 小时前
一个百度、必应搜索引擎图片获取下载的工具包
golang·图搜索
明月看潮生5 小时前
青少年编程与数学 02-003 Go语言网络编程 09课题、Cookie
青少年编程·golang·网络编程·编程与数学
明月看潮生5 小时前
青少年编程与数学 02-003 Go语言网络编程 15课题、Go语言URL编程
开发语言·网络·青少年编程·golang·编程与数学
明月看潮生5 小时前
青少年编程与数学 02-003 Go语言网络编程 14课题、Go语言Udp编程
青少年编程·golang·网络编程·编程与数学
Gemini19957 小时前
分布式和微服务的区别
分布式·微服务·架构
hlsd#7 小时前
go 集成go-redis 缓存操作
redis·缓存·golang
茶馆大橘15 小时前
微服务系列五:避免雪崩问题的限流、隔离、熔断措施
java·jmeter·spring cloud·微服务·云原生·架构·sentinel
coding侠客16 小时前
揭秘!微服务架构下,Apollo 配置中心凭啥扮演关键角色?
微服务·云原生·架构