微服务与注册中心的关系图
- 这个图很好说明了微服务之间的关系,以及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文件
{ "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
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 核心代码
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中
- 其他不是本文核心代码不做举例