Gaea数据库中间件实现MySQL读写分离
1.Gaea简介
Gaea
是小米中国区电商研发部研发的基于mysql协议的数据库中间件,目前在小米商城大陆和海外得到广泛使用,包括订单、社区、活动等多个业务。Gaea支持分库分表、sql路由、读写分离等基本特性,更多详细功能可以参照下面的功能列表。其中分库分表方案兼容了mycat和kingshard两个项目的路由方式。Gaea在设计、实现阶段参照了mycat、kingshard和vitess,并使用tidb parser作为内置的sql parser,在此表达诚挚感谢。为了方便使用和学习Gaea,我们也提供了详细的使用和设计文档,也欢迎大家多多参与。
接下来将详细介绍如何使用Gaea实现MySQL的读写分离。
2.准备工作
- 使用Gaea需要依赖MySql的主从复制环境
- 主从复制环境搭建请参考本博客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下载安装包
创建gaea数据目录
创建gaea用户组、用户
授权数据目录并切换gaea用户
下载gaea安装包
3.2 配置Gaea服务
(默认配置)创建配置文件
vim /gaea/v1.2.5/etc/gaea.ini
调整配置
由于没有搭建etcd配置中心,本例通过文本配置实现,修改
config_type=file
配置文件目录
file_config_path=./etc/file
,需要创建该目录mkdir -p /gaea/v1.2.5/etc/file/namespace
添加namespace配置文件,用于配置主从数据库信息,文件路径
/gaea/v1.2.5/etc/file/namespace/test_mysql.json
启动服务
3.3 读写分离测试
思路:首先关闭从实例的主从复制,然后通过Gaea代理来操作数据库,插入一条数据,如果主实例中有这条数据而从实例中没有,说明写操作是走的主库。然后再通过Gaea代理查询该表数据,如果没有这条数据,表示读操作走的是从库,证明读写分离成功。
- 步骤分解如下,不做详细展示。
- 暂停主从复制
- 通过gaea代理插入一条数据
- 通过gaea代理查询master实例是否存在数据
- 通过gaea代理查询slave实例是否存在数据
- 开启主从复制
- 通过gaea代理查询slave实例是否存在数据
- 步骤分解如下,不做详细展示。
3.3 注册为系统服务并设置开机自启动(root用户操作)
详细配置参考我的另一篇文章:Linux进程管理工具 Systemd 入坑指南
编辑配置文件
vim /usr/lib/systemd/system/gaea.service
启动服务
设置开启自启动
查看服务状态
4.配置说明
gaea配置由两部分组成,本地配置为gaea_proxy直接使用的配置内容,一般不需要在运行时改变。gaea为多租户模式,每个租户称为一个namespace,namespace 的配置在运行时都可变,一般保存在etcd中。
本地配置说明
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表所在分片 |
配置示例
本配置截取自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_后缀
的模式.
以这个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路由举例:
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的分库路由模式.
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
. 如果不指定, 则全局表在各个后端的数据库名和表名均相同.