你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?




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目錄下;
<code>tar -zxvf go1.13.5.linux-amd64.tar.gz -C /mydata//<code>
  • 添加/mydata/go/bin目錄到PATH變量中:
<code># 編輯環境變量配置文件
vim /etc/profile
# 在最後一行添加
export GOROOT=mydata/go
export PATH=$PATH:$GOROOT/bin
# 刷新配置文件
source /etc/profile/<code>
  • 查看版本號,測試是否安裝成功:
<code>go version/<code>
  • 返回以下信息表示Go語言環境已經安裝成功了:
<code>go version go1.13.5 linux/amd64/<code>

4.2 安裝Gaea

由於Gaea並沒有提供安裝包,所以我們需要自行編譯源碼獲取可執行文件。

  • 下載Gaea的源碼,直接下載zip包即可,下載地址:github.com/XiaoMi/Gaea
  • 將下載好的壓縮包進行解壓操作,這裡我們解壓到/mydata/gaea/目錄下:
<code>unzip Gaea-master.zip/<code>
  • 進入/mydata/gaea/目錄下,使用make命令對源碼編譯:
<code>make build/<code>
  • 注意:由於網絡問題,某些Go的依賴會下載不下來導致編譯失敗,多嘗試幾次即可成功;
  • 編譯完成後在/mydata/gaea/bin目錄下會生成Gaea的執行文件gaea:
你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?

  • 由於我們沒有搭建etcd配置中心,所以需要修改本地配置文件/mydata/gaea/etc/gaea.ini,將配置類型改為file:
<code>; 配置類型,目前支持file/etcd兩種方式,file方式不支持熱加載
config_type=file/<code>
  • 添加namespace配置文件,用於配置我們的主從數據庫信息,配置文件地址:/mydata/gaea/etc/file/namespace/mall_namespace_1.json
你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?

  • 配置文件內容如下:
<code>{
"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
}/<code>

4.3 namespace配置文件

namespace的配置格式為json,包含分表、非分表、實例等配置信息,都可在運行時改變。

  • 整體配置說明:
你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?

  • slice配置:


你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?


  • users配置:
你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?

05 在Docker容器中運行

由於官方只提供了Linux下直接安裝運行的方式,這裡我們提供另一種運行方式,在Docker容器中作為服務運行。

5.1 打包成Docker鏡像

Docker Hub 中並沒有打包好的Gaea鏡像,我們需要自行構建一個,下面詳細介紹下如何構建Gaea的Docker鏡像。

  • 這裡我們使用Dockerfile構建Docker鏡像,Dockerfile中的內容如下:
<code># 該鏡像需要依賴的基礎鏡像
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/<code>
  • 在此之前我們需要把Gaea的源碼壓縮包轉換為.tar.gz格式方便在Docker容器中的解壓,可以使用壓縮軟件來實現:
你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?

  • 之後使用Docker命令構建Gaea的Docker鏡像:
<code>docker build -t gaea:1.0.2 ./<code>
  • 構建成功控制檯輸出:
你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?

  • 將本地安裝的Gaea配置文件複製到/mydata/gaea-docker/etc/目錄下:
<code>cp -r /mydata/gaea/etc/ /mydata/gaea-docker/etc//<code>
  • 使用Docker命令啟動Gaea容器:
<code>docker run -p 13306:13306 --name gaea \\
-v /mydata/gaea-docker/etc:/go/gaea/etc \\
-d gaea:1.0.2/<code>

06 測試讀寫分離

測試思路:首先我們關閉從實例的主從複製,然後通過Gaea代理來操作數據庫,插入一條數據,如果主實例中有這條數據而從實例中沒有,說明寫操作是走的主庫。然後再通過Gaea代理查詢該表數據,如果沒有這條數據,表示讀操作走的是從庫,證明讀寫分離成功。

  • 通過Navicat連接到Gaea代理,注意此處賬號密碼為Gaea的namespace中配置的內容,端口為Gaea的服務端口;
你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?

  • 通過Navicat分別連接到主庫和從庫,用於查看數據,此時建立了以下三個數據庫連接;
你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?

  • 通過stop slave命令關閉mysql-slave實例的主從複製功能:
你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?

  • 通過Gaea代理在test表中插入一條數據:
你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?

  • 在主庫中查看test表的數據,發現已有該數據:
你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?

  • 在從庫中查看test表的數據,發現沒有該數據,證明寫操作走的是主庫:
你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?

  • 直接在代理中查看test表中的數據,發現沒有該數據,證明讀操作走的是從庫。
你還在代碼裡做讀寫分離麼?要不試試這個中間件吧?

07 結合SpringBoot使用

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

原文鏈接:https://juejin.im/post/5e22b37ee51d454d523be24d


分享到:


相關文章: