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中
  • 其他不是本文核心代码不做举例
相关推荐
stark张宇19 小时前
微服务架构必备:Gin + gRPC + Consul + Nacos + GORM 打造用户服务
微服务·gin·grpc
阿里云云原生4 天前
MSE Nacos Prompt 管理:让 AI Agent 的核心配置真正可治理
微服务·云原生
阿里云云原生4 天前
阿里云微服务引擎 MSE 及 API 网关 2026 年 1 月产品动态
微服务
花酒锄作田4 天前
Gin 框架中的规范响应格式设计与实现
golang·gin
麦聪聊数据5 天前
统一 Web SQL 平台如何收编企业内部的“野生数据看板”?
数据库·sql·低代码·微服务·架构
qwfys2005 天前
How to install golang 1.26.0 to Ubuntu 24.04
ubuntu·golang·install
云司科技codebuddy5 天前
技术支持过硬Trae核心代理
大数据·运维·python·微服务
codeejun5 天前
每日一Go-25、Go语言进阶:深入并发模式1
开发语言·后端·golang
递归尽头是星辰5 天前
微服务事务分级治理:从 Seata 全模式到 TDSQL 实战
微服务·云原生·架构·分布式事务·事务分级治理
没有bug.的程序员5 天前
订单系统重构史诗:从单体巨兽到微服务矩阵的演进、数据一致性内核与分布式事务
java·微服务·矩阵·重构·分布式事务·数据一致性·订单系统