基于go语言的高性能的数据库分表中间件介绍:Gorm Sharding

2023-06-01 00:00:00 语言 中间件 高性能

Gorm Sharding 是一个高性能的数据库分表中间件。

它基于 Conn 层做 SQL 拦截、AST 解析、分表路由、自增主键填充,带来的额外开销极小。

对开发者友好、透明,使用上与普通 SQL、Gorm 查询无差别,只需要额外注意一下分表键条件。

官方文档:
https://gorm.io/docs/sharding.html
中文版:
https://gorm.io/zh_CN/docs/sharding.html
github:
https://github.com/go-gorm/sharding
功能特点
非侵入式设计, 加载插件,指定配置,既可实现分表。
轻快, 非基于网络层的中间件,像 Go 一样快
支持多种数据库。 PostgreSQL 已通过测试,MySQL 和 SQLite 也在路上。
多种主键生成方式支持(Snowflake, PostgreSQL Sequence, 以及自定义支持)Snowflake 支持从主键中确定分表键。

安装

go get -u gorm.io/sharding


测试表结构

// ProjectLog 结构体
type ProjectLog struct {
    global.GVA_MODEL
    ID             int64                               `gorm:"primarykey"` // 主键ID
    ProjectId      int64                               `json:"project_id" form:"project_id" gorm:"column:project_id;comment:;"`
    UpdateContent  datatypes.JSONType[project.Project] `json:"update_content" form:"update_content" gorm:"type:json;column:update_content;comment:;"`
    UpdateContent2 datatypes.JSONType[project.Project] `json:"update_content2" form:"update_content2" gorm:"-"`
    ParentId       int64                               `json:"parent_id" form:"parent_id" gorm:"column:parent_id;comment:;"`
}
// TableName ProjectLog 表名
func (p ProjectLog) TableName() string {
    return "project_log"
}

迁移生成测试表

import (
    "fmt"
    "strconv"
    "testing"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)
func TestMigrate(t *testing.T) {
    mysqlConfig := mysql.Config{
        DSN:                       "root:[email protected](127.0.0.1:3306)/admin_project?charset=utf8mb4&parseTime=True&loc=Local", // DSN data source name
        DefaultStringSize:         191,                                                                                             // string 类型字段的默认长度
        SkipInitializeWithVersion: false,                                                                                           // 根据版本自动配置
    }
    DB, err := gorm.Open(mysql.New(mysqlConfig))
    if err != nil {
        fmt.Println(err.Error())
        return
    }
    //生成128张project_log表,具体数量看自己需要了。
    for i := 0; i < 128; i++ {
        tableName := fmt.Sprintf("project_log_%0*d", 3, i) //表名
        DB.Table(tableName).AutoMigrate(&project_log.ProjectLog{})
    }
}

迁移成功:

Sharding.png

配置 Sharding 中间件,为需要分表的业务表定义他们分表的规则

import (
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/sharding"
)
    mysqlConfig := mysql.Config{
        DSN:                       "root:[email protected](127.0.0.1:3306)/admin_project?charset=utf8mb4&parseTime=True&loc=Local", // DSN data source name
        DefaultStringSize:         191,                                                                                             // string 类型字段的默认长度
        SkipInitializeWithVersion: false,                                                                                           // 根据版本自动配置
    }
    DB, err := gorm.Open(mysql.New(mysqlConfig))
    DB.Use(sharding.Register(sharding.Config{
        ShardingKey:         "company_id",
        NumberOfShards:      128,
        PrimaryKeyGenerator: sharding.PKSnowflake,
    },   "project_log"))
    //创建数据
     DB.Create(&project_log.ProjectLog{Company_id: 1, ParentId: 1})
     DB.Create(&project_log.ProjectLog{Company_id: 1, ParentId: 2})
     DB.Create(&project_log.ProjectLog{Company_id: 1, ParentId: 3})
     DB.Create(&project_log.ProjectLog{Company_id: 1, ParentId: 4})

依然保持原来的方式使用 db 来查询数据库。 

你只需要注意在 CURD 动作的时候,明确知道 Sharding Key 对应的分表,

查询条件带 Sharding Key,以确保 Sharding 能理解数据需要对应到哪一个子表。


//查询数据

    var data []project.ProjectLog
     DB.Unscoped().Select("company_id,parent_id").Where("company_id =  ?", 1).
        Where("parent_id IN ?", []int{1, 2, 3, 4}).Find(&data)
    for _, v := range data {
        fmt.Printf("公司Company_id: %d,Parent_id: %d \n", v.Company_id, v.ParentId)
    }

2.png

相关文章