01 摘要
傳統的MySQL讀寫分離方案是通過在代碼中根據SQL語句的類型動態切換數據源來實現的,那么有沒有什么中間件可以自動實現讀寫分離呢?小米開源的數據庫中間件Gaea就可以實現,接下來我們將詳細講解如何使用Gaea來實現MySql的讀寫分離。
02 Gaea簡介
Gaea是小米中國區電商研發部研發的基于MySql協議的數據庫中間件,目前在小米商城大陸和海外得到廣泛使用,包括訂單、社區、活動等多個業務。Gaea支持分庫分表、SQL路由、讀寫分離等基本特性,其中分庫分表方案兼容了mycat和kingshard兩個項目的路由方式。
03 MySql主從復制
使用Gaea需要依賴MySql的主從復制環境,關于MySql的主從復制可以參考:MySql主從復制,從原理到實踐!
04 直接在linux下安裝
目前官方提供的是在Linux下直接安裝的方式,我們先按此方法來安裝Gaea。
4.1 安裝Go語言環境
由于Gaea是使用Go語言編寫的,所以我們需要先安裝Go語言的環境。
- 安裝Go語言環境,下載地址:golang.org/dl/

- 下載完成后解壓到/mydata目錄下;
tar -zxvf go1.13.5.linux-amd64.tar.gz -C /mydata/
- 添加/mydata/go/bin目錄到PATH變量中:
# 編輯環境變量配置文件
vim /etc/profile
# 在最后一行添加
export GOROOT=mydata/go
export PATH=$PATH:$GOROOT/bin
# 刷新配置文件
source /etc/profile
- 查看版本號,測試是否安裝成功:
go version
- 返回以下信息表示Go語言環境已經安裝成功了:
go version go1.13.5 linux/amd64
4.2 安裝Gaea
由于Gaea并沒有提供安裝包,所以我們需要自行編譯源碼獲取可執行文件。
- 下載Gaea的源碼,直接下載zip包即可,下載地址:github.com/XiaoMi/Gaea
- 將下載好的壓縮包進行解壓操作,這里我們解壓到/mydata/gaea/目錄下:
unzip Gaea-master.zip
- 進入/mydata/gaea/目錄下,使用make命令對源碼編譯:
make build
- 注意:由于網絡問題,某些Go的依賴會下載不下來導致編譯失敗,多嘗試幾次即可成功;
- 編譯完成后在/mydata/gaea/bin目錄下會生成Gaea的執行文件gaea:

- 由于我們沒有搭建etcd配置中心,所以需要修改本地配置文件/mydata/gaea/etc/gaea.ini,將配置類型改為file:
; 配置類型,目前支持file/etcd兩種方式,file方式不支持熱加載
config_type=file
- 添加namespace配置文件,用于配置我們的主從數據庫信息,配置文件地址:/mydata/gaea/etc/file/namespace/mall_namespace_1.json

- 配置文件內容如下:
{
"name": "mall_namespace_1",
"online": true,
"read_only": false,
"allowed_dbs": {
"mall": true
},
"slow_sql_time": "1000",
"black_sql": [
""
],
"allowed_ip": null,
"slices": [
{
"name": "slice-0",
"user_name": "root",
"password": "root",
"master": "192.168.6.132:3307",
"slaves": ["192.168.6.132:3308"],
"statistic_slaves": null,
"capacity": 12,
"max_capacity": 24,
"idle_timeout": 60
}
],
"shard_rules": null,
"users": [
{
"user_name": "macro",
"password": "123456",
"namespace": "mall_namespace_1",
"rw_flag": 2,
"rw_split": 1,
"other_property": 0
}
],
"default_slice": "slice-0",
"global_sequences": null
}
4.3 namespace配置文件
namespace的配置格式為json,包含分表、非分表、實例等配置信息,都可在運行時改變。
- 整體配置說明:

- slice配置:

- users配置:

05 在Docker容器中運行
由于官方只提供了Linux下直接安裝運行的方式,這里我們提供另一種運行方式,在Docker容器中作為服務運行。
5.1 打包成Docker鏡像
Docker Hub 中并沒有打包好的Gaea鏡像,我們需要自行構建一個,下面詳細介紹下如何構建Gaea的Docker鏡像。
- 這里我們使用Dockerfile構建Docker鏡像,Dockerfile中的內容如下:
# 該鏡像需要依賴的基礎鏡像
FROM golang:latest
# 將當前目錄下的gaea源碼包復制到docker容器的/go/Gaea-master目錄下,對于.tar.gz文件會自動解壓
ADD Gaea-master.tar.gz /go/Gaea-master
# 將解壓后的源碼移動到/go/gaea目錄中去
RUN bash -c 'mv /go/Gaea-master/Gaea-master /go/gaea'
# 進入/go/gaea目錄
WORKDIR /go/gaea
# 將gaea源碼進行打包編譯
RUN bash -c 'make build'
# 聲明服務運行在13306端口
EXPOSE 13306
# 指定docker容器啟動時執行的命令
ENTRYPOINT ["/go/gaea/bin/gaea"]
# 指定維護者的名字
MAINTAINER macrozheng
- 在此之前我們需要把Gaea的源碼壓縮包轉換為.tar.gz格式方便在Docker容器中的解壓,可以使用壓縮軟件來實現:

- 之后使用Docker命令構建Gaea的Docker鏡像:
docker build -t gaea:1.0.2 .
- 構建成功控制臺輸出:

- 將本地安裝的Gaea配置文件復制到/mydata/gaea-docker/etc/目錄下:
cp -r /mydata/gaea/etc/ /mydata/gaea-docker/etc/
- 使用Docker命令啟動Gaea容器:
docker run -p 13306:13306 --name gaea
-v /mydata/gaea-docker/etc:/go/gaea/etc
-d gaea:1.0.2
06 測試讀寫分離
測試思路:首先我們關閉從實例的主從復制,然后通過Gaea代理來操作數據庫,插入一條數據,如果主實例中有這條數據而從實例中沒有,說明寫操作是走的主庫。然后再通過Gaea代理查詢該表數據,如果沒有這條數據,表示讀操作走的是從庫,證明讀寫分離成功。
- 通過Navicat連接到Gaea代理,注意此處賬號密碼為Gaea的namespace中配置的內容,端口為Gaea的服務端口;

- 通過Navicat分別連接到主庫和從庫,用于查看數據,此時建立了以下三個數據庫連接;

- 通過stop slave命令關閉mysql-slave實例的主從復制功能:

- 通過Gaea代理在test表中插入一條數據:

- 在主庫中查看test表的數據,發現已有該數據:

- 在從庫中查看test表的數據,發現沒有該數據,證明寫操作走的是主庫:

- 直接在代理中查看test表中的數據,發現沒有該數據,證明讀操作走的是從庫。

07 結合SpringBoot使用
在我們的SpringBoot應用中,我們只需要把Gaea的代理服務直接當做數據庫服務來使用就可以實現讀寫分離了。這樣就不用在代碼中添加任何讀寫分離邏輯了,是不是很方便!