Gaea数据库中间件实现MySQL读写分离

1.Gaea简介

Gaea是小米中国区电商研发部研发的基于mysql协议的数据库中间件,目前在小米商城大陆和海外得到广泛使用,包括订单、社区、活动等多个业务。Gaea支持分库分表、sql路由、读写分离等基本特性,更多详细功能可以参照下面的功能列表。其中分库分表方案兼容了mycat和kingshard两个项目的路由方式。Gaea在设计、实现阶段参照了mycat、kingshard和vitess,并使用tidb parser作为内置的sql parser,在此表达诚挚感谢。为了方便使用和学习Gaea,我们也提供了详细的使用和设计文档,也欢迎大家多多参与。

接下来将详细介绍如何使用Gaea实现MySQL的读写分离。

2.准备工作

  1. 使用Gaea需要依赖MySql的主从复制环境
  2. 主从复制环境搭建请参考本博客MySQL系列博文
IP 描述
192.168.2.181 Gaea中间件部署服务器
192.168.2.170 MySQL主节点master
192.168.2.180 MySQL从节点Slave

3.安装

当前文章基于v1.2.5版本,不同版本有可能安装过程、配置会有不一致的地方,请自行更正。

3.1下载安装包

  1. 创建gaea数据目录

    [root@localhost ~]# mkdir /gaea
  2. 创建gaea用户组、用户

    [root@localhost ~]# groupadd gaea
    [root@localhost ~]# useradd gaea -g gaea -s /sbin/nologin
  3. 授权数据目录并切换gaea用户

    [root@localhost ~]# chown -R gaea:gaea /gaea
    [root@localhost ~]# su gaea -s /bin/bash
    [gaea@localhost ~]$ 
  4. 下载gaea安装包

    [gaea@localhost ~]$ cd /gaea
    [gaea@localhost ~]$ mkdir -p v1.2.5/etc/
    [gaea@localhost v1.2.5]$ wget https://github.com/XiaoMi/Gaea/releases/download/v1.2.5/gaea-v1.2.5-linux-amd64-go1.13.3 -O /gaea/v1.2.5/gaea

3.2 配置Gaea服务

  1. (默认配置)创建配置文件vim /gaea/v1.2.5/etc/gaea.ini

    ; 配置类型,目前支持file/etcd两种方式,file方式不支持热加载,但是可以快速体验功能
    ; file 模式下读取file_config_path下的namespace配置文件
    ; etcd 模式下读取coordinator_addr/cluster_name下的namespace配置文件
    config_type=file
    ;file config path, 具体配置放到file_config_path的namespace目录下,该下级目录为固定目录
    file_config_path=./etc/file
    
    ;配置中心地址,目前只支持etcd
    coordinator_addr=http://127.0.0.1:2379
    ;配置中心用户名和密码
    username=test
    password=test
    
    ;环境划分、test、online
    environ=online 
    ;service name
    service_name=gaea_proxy
    ;gaea_proxy 当前proxy所属的集群名称
    cluster_name=gaea_default_cluster
    
    ;日志配置
    log_path=./logs
    log_level=Notice
    log_filename=gaea
    log_output=file
    
    ;管理地址
    admin_addr=0.0.0.0:13307
    ;basic auth
    admin_user=admin
    admin_password=admin
    
    ;代理服务监听地址
    proto_type=tcp4
    proxy_addr=0.0.0.0:13306
    
    ; 默认编码
    proxy_charset=utf8
    ;慢sql阈值,单位: 毫秒
    slow_sql_time=100
    ;空闲会话超时时间,单位: 秒
    session_timeout=3600
    
    ;打点统计配置
    stats_enabled=true
    stats_interval=10 
    
    ;encrypt key, 用于对etcd中存储的namespace配置加解密
    encrypt_key=1234abcd5678efg*
    
    ;server_version 服务器版本号配置
    server_version=5.7.29-gaea
    
    ;auth plugin mysql_native_password or caching_sha2_password or ''
    ;自定义认证插件,支持 5.x 和 8.x 版本认证,认证插件为 caching_sha2_password 时,不支持低版本客户端认证
    auth_plugin=mysql_native_password
  2. 调整配置

    1. 由于没有搭建etcd配置中心,本例通过文本配置实现,修改config_type=file

    2. 配置文件目录file_config_path=./etc/file,需要创建该目录mkdir -p /gaea/v1.2.5/etc/file/namespace

    3. 添加namespace配置文件,用于配置主从数据库信息,文件路径/gaea/v1.2.5/etc/file/namespace/test_mysql.json

      {
          "name": "test_mysql",
          "online": true,
          "read_only": false,
          "max_sql_result_size": -1,
          "allowed_dbs": {
              "test2": true
          },
          "slow_sql_time": "1000",
          "black_sql": [
              ""
          ],
          "allowed_ip": null,
          "slices": [
              {
                  "name": "slice-0",
                  "user_name": "root",
                  "password": "root",
                  "master": "192.168.2.170:3306",
                  "slaves": ["192.168.2.180:3306"],
                  "statistic_slaves": null,
                  "capacity": 20,
                  "max_capacity": 100,
                  "idle_timeout": 120
              }
          ],
          "shard_rules": null,
          "users": [
              {
                  "user_name": "test",
                  "password": "123456",
                  "namespace": "test_mysql",
                  "rw_flag": 2,
                  "rw_split": 1,
                  "other_property": 0
              }
          ],
          "default_slice": "slice-0",
          "global_sequences": null
      }
    4. 启动服务

      [gaea@localhost v1.2.5]$ chmod +x /gaea/v1.2.5/gaea
      [gaea@localhost v1.2.5]$ /gaea/v1.2.5/gaea
      Build Version Information:Version: bd4f77a454464ed450de828e0c72f8417b205eb5-dirty
      GitRevision: bd4f77a454464ed450de828e0c72f8417b205eb5-dirty
      User: work@tj1-dba-garm-test01.kscn
      GolangVersion: go1.13.3
      BuildStatus: Modified
      BuildTime: 2022-04-19--15:38:44
      BuildBranch: dev
      BuildGitDirty: 333
      
      [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
       - using env:   export GIN_MODE=release
       - using code:  gin.SetMode(gin.ReleaseMode)
      
      [GIN-debug] GET    /api/proxy/ping           --> github.com/XiaoMi/Gaea/proxy/server.(*AdminServer).ping-fm (2 handlers)
      [GIN-debug] PUT    /api/proxy/config/prepare/:name --> github.com/XiaoMi/Gaea/proxy/server.(*AdminServer).prepareConfig-fm (2 handlers)
      [GIN-debug] PUT    /api/proxy/config/commit/:name --> github.com/XiaoMi/Gaea/proxy/server.(*AdminServer).commitConfig-fm (2 handlers)
      [GIN-debug] PUT    /api/proxy/namespace/delete/:name --> github.com/XiaoMi/Gaea/proxy/server.(*AdminServer).deleteNamespace-fm (2 handlers)
      [GIN-debug] GET    /api/proxy/config/fingerprint --> github.com/XiaoMi/Gaea/proxy/server.(*AdminServer).configFingerprint-fm (2 handlers)
      [GIN-debug] GET    /api/proxy/stats/sessionsqlfingerprint/:namespace --> github.com/XiaoMi/Gaea/proxy/server.(*AdminServer).getNamespaceSessionSQLFingerprint-fm (2 handlers)
      [GIN-debug] GET    /api/proxy/stats/backendsqlfingerprint/:namespace --> github.com/XiaoMi/Gaea/proxy/server.(*AdminServer).getNamespaceBackendSQLFingerprint-fm (2 handlers)
      [GIN-debug] DELETE /api/proxy/stats/sessionsqlfingerprint/:namespace --> github.com/XiaoMi/Gaea/proxy/server.(*AdminServer).clearNamespaceSessionSQLFingerprint-fm (2 handlers)
      [GIN-debug] DELETE /api/proxy/stats/backendsqlfingerprint/:namespace --> github.com/XiaoMi/Gaea/proxy/server.(*AdminServer).clearNamespaceBackendSQLFingerprint-fm (2 handlers)
      [GIN-debug] GET    /api/metric/metrics       --> github.com/gin-gonic/gin.WrapH.func1 (2 handlers)
      [GIN-debug] GET    /debug/pprof/             --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
      [GIN-debug] GET    /debug/pprof/cmdline      --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
      [GIN-debug] GET    /debug/pprof/profile      --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
      [GIN-debug] POST   /debug/pprof/symbol       --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
      [GIN-debug] GET    /debug/pprof/symbol       --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
      [GIN-debug] GET    /debug/pprof/trace        --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
      [GIN-debug] GET    /debug/pprof/block        --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
      [GIN-debug] GET    /debug/pprof/goroutine    --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
      [GIN-debug] GET    /debug/pprof/heap         --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
      [GIN-debug] GET    /debug/pprof/mutex        --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
      [GIN-debug] GET    /debug/pprof/threadcreate --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
      [GIN-debug] GET    /debug/pprof/allocs       --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)

      3.3 读写分离测试

      思路:首先关闭从实例的主从复制,然后通过Gaea代理来操作数据库,插入一条数据,如果主实例中有这条数据而从实例中没有,说明写操作是走的主库。然后再通过Gaea代理查询该表数据,如果没有这条数据,表示读操作走的是从库,证明读写分离成功。

      • 步骤分解如下,不做详细展示。
        1. 暂停主从复制
        2. 通过gaea代理插入一条数据
        3. 通过gaea代理查询master实例是否存在数据
        4. 通过gaea代理查询slave实例是否存在数据
        5. 开启主从复制
        6. 通过gaea代理查询slave实例是否存在数据

3.3 注册为系统服务并设置开机自启动(root用户操作)

  • 详细配置参考我的另一篇文章:Linux进程管理工具 Systemd 入坑指南

  • 编辑配置文件vim /usr/lib/systemd/system/gaea.service

    [Unit]
    Description=gaea - MySQL Proxy
    Documentation=https://github.com/XiaoMi/Gaea
    After=network.target
    
    [Service]
    User=gaea
    Group=gaea
    WorkingDirectory=/gaea/v1.2.5
    Type=forking
    Restart=always
    ExecStart=/gaea/v1.2.5/gaea -config=/gaea/v1.2.5/etc/gaea.ini
    ExecReload=/bin/kill -s HUP $MAINPID
    ExecStop=/bin/kill -s QUIT $MAINPID
    PrivateTmp=true
    
    [Install]
    WantedBy=multi-user.target
  • 启动服务

    [root@localhost ~]# systemctl start gaea.service
  • 设置开启自启动

    [root@localhost ~]# systemctl enable gaea.service
  • 查看服务状态

    [root@localhost ~]# systemctl status gaea.service
    ● gaea.service - gaea - MySQL Proxy
       Loaded: loaded (/usr/lib/systemd/system/gaea.service; enabled; vendor preset: disabled)
       Active: activating (start) since Tue 2022-11-29 18:08:55 CST; 12s ago
         Docs: https://github.com/XiaoMi/Gaea
      Control: 14260 (gaea)
        Tasks: 9
       Memory: 14.6M
       CGroup: /system.slice/gaea.service
               └─14260 /gaea/v1.2.5/gaea -config=/gaea/v1.2.5/etc/gaea.ini
    
    Nov 29 18:08:55 gaea gaea[14260]: [GIN-debug] GET    /debug/pprof/profile      --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
    Nov 29 18:08:55 gaea gaea[14260]: [GIN-debug] POST   /debug/pprof/symbol       --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
    Nov 29 18:08:55 gaea gaea[14260]: [GIN-debug] GET    /debug/pprof/symbol       --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
    Nov 29 18:08:55 gaea gaea[14260]: [GIN-debug] GET    /debug/pprof/trace        --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
    Nov 29 18:08:55 gaea gaea[14260]: [GIN-debug] GET    /debug/pprof/block        --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
    Nov 29 18:08:55 gaea gaea[14260]: [GIN-debug] GET    /debug/pprof/goroutine    --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
    Nov 29 18:08:55 gaea gaea[14260]: [GIN-debug] GET    /debug/pprof/heap         --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
    Nov 29 18:08:55 gaea gaea[14260]: [GIN-debug] GET    /debug/pprof/mutex        --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
    Nov 29 18:08:55 gaea gaea[14260]: [GIN-debug] GET    /debug/pprof/threadcreate --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
    Nov 29 18:08:55 gaea gaea[14260]: [GIN-debug] GET    /debug/pprof/allocs       --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)

4.配置说明

gaea配置由两部分组成,本地配置为gaea_proxy直接使用的配置内容,一般不需要在运行时改变。gaea为多租户模式,每个租户称为一个namespace,namespace 的配置在运行时都可变,一般保存在etcd中。

本地配置说明

; 配置类型,目前支持file/etcd两种方式,file方式不支持热加载,但是可以快速体验功能
; file 模式下读取file_config_path下的namespace配置文件
; etcd 模式下读取coordinator_addr/cluster_name下的namespace配置文件
config_type=etcd
;file config path, 具体配置放到file_config_path的namespace目录下,该下级目录为固定目录
file_config_path=./etc/file

;配置中心地址,目前只支持etcd
coordinator_addr=http://127.0.0.1:2379
;配置中心用户名和密码
username=test
password=test

;环境划分、test、online
environ=test 
;service name
service_name=gaea_proxy
;gaea_proxy 当前proxy所属的集群名称
cluster_name=gaea_default_cluster

;日志配置
log_path=./logs
log_level=Notice
log_filename=gaea
log_output=file

;管理地址
admin_addr=0.0.0.0:13307
;basic auth
admin_user=admin
admin_password=admin

;代理服务监听地址
proto_type=tcp4
proxy_addr=0.0.0.0:13306

; 默认编码
proxy_charset=utf8
;慢sql阈值,单位: 毫秒
slow_sql_time=100
;空闲会话超时时间,单位: 秒
session_timeout=3600

;打点统计配置
stats_enabled=true
stats_interval=10 

;encrypt key, 用于对etcd中存储的namespace配置加解密
encrypt_key=1234abcd5678efg*

;server_version 服务器版本号配置
server_version=5.6.20-gaea

;auth plugin mysql_native_password or caching_sha2_password or ''
;自定义认证插件,支持 5.x 和 8.x 版本认证,认证插件为 caching_sha2_password 时,不支持低版本客户端认证
;auth_plugin=mysql_native_password

namespace配置说明

namespace的配置格式为json,包含分表、非分表、实例等配置信息,都可在运行时改变。namespace的配置可以直接通过web平台进行操作,使用方不需要关心json里的内容,如果有兴趣参与到gaea的开发中,可以关注下字段含义,具体解释如下,格式为字段名称、类型、内容含义。

字段名称 字段类型 字段含义
name string namespace名称
online bool 是否在线,逻辑上下线使用
read_only bool 是否只读,namespace级别
allowed_dbs map 数据库集合
default_phy_dbs map 默认数据库名, 与allowed_dbs一一对应
slow_sql_time string 慢sql时间,单位ms
black_sql string数组 黑名单sql
allowed_ip string数组 白名单IP
slices map数组 一主多从的物理实例,slice里map的具体字段可参照slice配置
shard_rules map数组 分库、分表、特殊表的配置内容,具体字段可参照shard配置
users map数组 应用端连接gaea所需要的用户配置,具体字段可参照users配置
global_sequences map 生成全局唯一序列号的配置, 具体字段可参考全局序列号配置
default_slice string show语句默认的执行分片
open_general_log bool 是否开启审计日志, 如何开启
max_sql_execute_time int 应用端查询最大执行时间, 超时后会被自动kill, 为0默认不开启此功能
max_sql_result_size int gaea从后端mysql接收结果集的最大值, 限制单分片查询行数, 默认值10000, -1表示不开启

slice配置

字段名称 字段类型 字段含义
name string 分片名称,自动、有序生成
user_name string 连接后端mysql所需要的用户名称
password string 连接后端mysql所需要的用户密码
master string 主实例地址
slaves string数组 从实例地址列表
statistic_slaves string数组 统计型从实例地址列表
capacity int gaea_proxy与每个实例的连接池大小
max_capacity int gaea_proxy与每个实例的连接池最大大小
idle_timeout int gaea_proxy与后端mysql空闲连接存活时间,单位:秒

shard配置

这里列出了一些基本配置参数, 详细配置请参考分片表配置

如需要了解每种规则详细库表对照示例,可以查看分片规则示例说明

字段名称 字段类型 字段含义
db string 分片表所在DB
table string 分片表名
type string 分片类型
key string 分片列名
locations list 每个slice上分布的分片个数
slices list slice列表
databases list mycat分片规则后端实际DB名

users配置

字段名称 字段类型 字段含义
user_name string 用户名
password string 用户密码
namespace string 对应的命名空间
rw_flag int 读写标识, 只读=1, 读写=2
rw_split int 是否读写分离, 非读写分离=0, 读写分离=1
other_property int 目前用来标识是否走统计从实例, 普通用户=0, 统计用户=1

全局序列号配置

字段名称 字段类型 字段含义
db string 使用全局序列号的表所在的db的逻辑db名
table string 使用全局序列号的表的逻辑表名
type string 目前只支持mycat方式
pk_name string 使用全局序列号的列名,单表只允许一个列使用全局序列号
slice_name string mycat_sequence表所在分片

配置示例

{
    "name": "gaea_namespace_1",
    "online": true,
    "read_only": true,
    "allowed_dbs": {
        "db_ks": true,
        "db_mycat": true
    },
    "default_phy_dbs": {
        "db_ks": "db_ks",
        "db_mycat": "db_mycat_0"
    }, 
    "slow_sql_time": "1000",
    "black_sql": [
        ""
    ],
    "allowed_ip": null, 
    "slices": [
        {
            "name": "slice-0",
            "user_name": "root",
            "password": "root",
            "master": "127.0.0.1:3306",
            "capacity": 64,
            "max_capacity": 128,
            "idle_timeout": 3600
        },
        {
            "name": "slice-1",
            "user_name": "root",
            "password": "root",
            "master": "127.0.0.1:3307",
            "capacity": 64,
            "max_capacity": 128,
            "idle_timeout": 3600
        }
    ],
    "shard_rules": [
        {
            "db": "db_ks",
            "table": "tbl_ks",
            "type": "hash",
            "key": "id",
            "locations": [
                2,
                2
            ],
            "slices": [
                "slice-0",
                "slice-1"
            ]
        },
        {
            "db": "db_ks",
            "table": "tbl_ks_child",
            "type": "linked",
            "key": "id",
            "parent_table": "tbl_ks"
        },
        {
            "db": "db_ks",
            "table": "tbl_ks_global",
            "type": "global",
            "locations": [
                2,
                2
            ],
            "slices": [
                "slice-0",
                "slice-1"
            ]
        },
        {
            "db": "db_ks",
            "table": "tbl_ks_range",
            "type": "range",
            "key": "id",
            "locations": [
                2,
                2
            ],
            "slices": [
                "slice-0",
                "slice-1"
            ],
            "table_row_limit": 100
        },
        {
            "db": "db_ks",
            "table": "tbl_ks_year",
            "type": "date_year",
            "key": "create_time",
            "slices": [
                "slice-0",
                "slice-1"
            ],
            "date_range": [
                "2014-2017",
                "2018-2019"
            ]
        },
        {
            "db": "db_ks",
            "table": "tbl_ks_month",
            "type": "date_month",
            "key": "create_time",
            "slices": [
                "slice-0",
                "slice-1"
            ],
            "date_range": [
                "201405-201406",
                "201408-201409"
            ]
        },
        {
            "db": "db_ks",
            "table": "tbl_ks_day",
            "type": "date_day",
            "key": "create_time",
            "slices": [
                "slice-0",
                "slice-1"
            ],
            "date_range": [
                "20140901-20140905",
                "20140907-20140908"
            ]
        },
        {
            "db": "db_mycat",
            "table": "tbl_mycat",
            "type": "mycat_mod",
            "key": "id",
            "locations": [
                2,
                2
            ],
            "slices": [
                "slice-0",
                "slice-1"
            ],
            "databases": [
                "db_mycat_[0-3]"
            ]
        },
        {
            "db": "db_mycat",
            "table": "tbl_mycat_child",
            "type": "linked",
            "parent_table": "tbl_mycat",
            "key": "id"
        },
        {
            "db": "db_mycat",
            "table": "tbl_mycat_murmur",
            "type": "mycat_murmur",
            "key": "id",
            "locations": [
                2,
                2
            ],
            "slices": [
                "slice-0",
                "slice-1"
            ],
            "databases": [
                "db_mycat_0",
                "db_mycat_1",
                "db_mycat_2",
                "db_mycat_3"
            ],
            "seed": "0",
            "virtual_bucket_times": "160"
        },
        {
            "db": "db_mycat",
            "table": "tbl_mycat_long",
            "type": "mycat_long",
            "key": "id",
            "locations": [
                2,
                2
            ],
            "slices": [
                "slice-0",
                "slice-1"
            ],
            "databases": [
                "db_mycat_[0-3]"
            ],
            "partition_count": "4",
            "partition_length": "256"
        },
        {
            "db": "db_mycat",
            "table": "tbl_mycat_global",
            "type": "global",
            "locations": [
                2,
                2
            ],
            "slices": [
                "slice-0",
                "slice-1"
            ],
            "databases": [
                "db_mycat_[0-3]"
            ]
        },
        {
            "db": "db_mycat",
            "table": "tbl_mycat_string",
            "type": "mycat_string",
            "key": "id",
            "locations": [
                2,
                2
            ],
            "slices": [
                "slice-0",
                "slice-1"
            ],
            "databases": [
                "db_mycat_[0-3]"
            ],
            "partition_count": "4",
            "partition_length": "256",
            "hash_slice": "20"
        }
    ],
    "global_sequences": [
        {
            "db": "db_mycat",
            "table": "tbl_mycat",
            "type": "test",
            "pk_name": "id"
        },
        {
            "db": "db_ks",
            "table": "tbl_ks",
            "type": "test",
            "pk_name": "user_id"
        }
    ],
    "users": [
        {
            "user_name": "test_shard",
            "password": "test_shard",
            "namespace": "gaea_namespace_1",
            "rw_flag": 2,
            "rw_split": 1
        }
    ], 
    "default_slice": "slice-0",
    "open_general_log": false,
    "max_sql_execute_time": 5000,
    "max_sql_result_size": 10
}

本配置截取自proxy/plan/plan_test.go, 如果对Gaea分表有困惑, 也可以参考这个包下的测试用例. 下面将结合该配置示例介绍Gaea的namespace配置细节.

namespace名称为gaea_namespace_1. 在该namespace的users字段中添加一个gaea用户test_shard. 特别注意Gaea中的用户名+密码是全局唯一的 (映射到唯一的namespace). 该用户是读写用户, 且使用读写分离.

在namespace中通过allowed_dbs字段配置了两个可用的数据库, 另一个相关的字段为default_phy_dbs, 该字段仅用于mycat分库路由的场景, 用于标记后端实际库名. 如果没有使用mycat路由, 则可以只配置allowed_dbs字段, 不配置default_phy_dbs字段.

通过slices字段配置后端的slice. 一个slice实际上对应着一组MySQL实例, 可以包含一主多从. slice的名称目前必须使用slice-0, slice-1这样的格式, 如果自定义slice名称会出现找不到默认slice的问题.

shard_rules字段中配置分片表信息. 按照Gaea处理方式, 可以将分片表分为3类: kingshard路由模式的分片表, mycat路由模式的分片表, 全局表.

kingshard路由

kingshard路由模式下, 分片表要求后端数据库的库名相同, 子表的表名为table_后缀的模式.

{
    "db": "db_ks",
    "table": "tbl_ks",
    "type": "hash",
    "key": "id",
    "locations": [
        2,
        2
    ],
    "slices": [
        "slice-0",
        "slice-1"
    ]
}

以这个kingshard hash分片表配置为例, 路由规则为hash, 逻辑表名为tbl_ks, locations 2,2表示有两个slice, 每个slice上面分配两张子表, slices配置了两个slice的名称. 那么后端数据库的子表需要按照以下规则创建:

slice db table
slice-0 db_ks tbl_ks_0000
slice-0 db_ks tbl_ks_0001
slice-1 db_ks tbl_ks_0002
slice-1 db_ks tbl_ks_0003

其他kingshard路由的表名映射关系均类似, 再以range路由举例:

{
    "db": "db_ks",
    "table": "tbl_ks_month",
    "type": "date_month",
    "key": "create_time",
    "slices": [
        "slice-0",
        "slice-1"
    ],
    "date_range": [
        "201405-201406",
        "201408-201409"
    ]
}
slice db table
slice-0 db_ks tbl_ks_201405
slice-0 db_ks tbl_ks_201406
slice-1 db_ks tbl_ks_201408
slice-1 db_ks tbl_ks_201409

kingshard路由不需要配置databases字段, 因为后端数据库名与逻辑库名相同.

mycat路由

mycat路由与kingshard不完全相同, Gaea主要兼容了mycat的分库路由模式.

{
    "db": "db_mycat",
    "table": "tbl_mycat_murmur",
    "type": "mycat_murmur",
    "key": "id",
    "locations": [
        2,
        2
    ],
    "slices": [
        "slice-0",
        "slice-1"
    ],
    "databases": [
        "db_mycat_0",
        "db_mycat_1",
        "db_mycat_2",
        "db_mycat_3"
    ],
    "seed": "0",
    "virtual_bucket_times": "160"
}
slice db table
slice-0 db_mycat_0 tbl_mycat_murmur
slice-0 db_mycat_1 tbl_mycat_murmur
slice-1 db_mycat_2 tbl_mycat_murmur
slice-1 db_mycat_3 tbl_mycat_murmur

其中databases字段需要按路由顺序指定后端数据库的实际库名, 且数量需要与locations的总和相等.

全局表路由

全局表路由与mycat路由配置类似, 但是可以不指定databases. 如果不指定, 则全局表在各个后端的数据库名和表名均相同.


Gaea数据库中间件实现MySQL读写分离
https://www.gmtgo.com/39131.html
作者
大帅
发布于
2022年11月29日
许可协议