分散式資料庫中介軟體 MyCat | 分庫分表實踐
阿新 • • 發佈:2020-08-20
### MyCat 簡介
`MyCat` 是一個功能強大的分散式資料庫中介軟體,是一個實現了 `MySQL` 協議的 `Server`,前端人員可以把它看做是一個數據庫代理中介軟體,用 `MySQL` 客戶端工具和命令列訪問;而後端人員可以用 `MySQL` 原生協議與多個 `MySQL` 伺服器通訊,也可以用 `JDBC` 協議與大多數主流資料庫伺服器通訊。可以用作 **讀寫分離**、**分庫分表(分片)**、**容災備份**、**多租戶應用開發**、**大資料基礎設施**,使底層資料架構具備很強的適應性和靈活性。
`MyCat` 的智慧優化模組可以使系統的資料訪問瓶頸和熱點一目瞭然,並且可以將這些統計分析資料自動或手工調整後端儲存,將不同的表對映到不同儲存引擎上,而整個應用的程式碼可以一行也不用變。
#### 具體應用場景
1. **讀寫分離**:支援讀寫分離,主從切換,此配置最簡單;
2. **分庫分表**:對於超過 1000 萬的表進行分片,最大支援 1000 億的單表分片;
3. **多租戶應用**:每個應用一個庫,但應用程式只連線 MyCat,使程式不用改造本身,實現多租戶化;
4. **替代 `Hbase`**:用於分析大資料;
5. **報表系統**:藉助 MyCat 的分表能力,處理大規模報表的統計;
6. **海量資料查詢**:比如 10 億條頻繁查詢的記錄需要在 3 秒內查詢出來結果,除了基於主鍵的查詢,還可能存在範圍查詢或其他屬性查詢,此時 MyCat 可能是最簡單有效的選擇。
本文主要實踐核心功能 **分庫分表**。
### 分庫分表原理剖析
指通過某種特定的條件,將存放在同一個資料庫中的資料分散存放到多個數據庫上面,以達到分散單臺裝置負載的效果。
根據切分規則的型別可以分為以下兩種切分模式。
- 垂直切分:最大特點是規則簡單,適合各業務之間的的耦合度非常低、相互影響小、業務邏輯非常清晰的系統。在這種系統中,可以很容易 **將不同業務模組所使用的的表切到不同的資料庫中**。
- 水平切分:相對來說複雜一些,因為要 **將同一個表中的不同資料切分到不同的資料庫中**,後期的資料維護也更為複雜一些。
#### 垂直切分
一個數據庫由很多表構成,每個表對應著不同的業務,垂直切分就是按照業務將表進行分類,從而分佈到不同的資料庫上面,這樣也就將壓力分擔到不同的資料庫上,如圖。
![](https://qiniuyun.antoniopeng.com/1597863110.jpg)
一個架構設計好的系統其總體功能通常是由多個功能模組所組成的,而每一個功能模組的資料對應到資料庫中就是一個或多個表。而在架構設計中,各個功能模組相互之間的互動點越少和越統一,系統的耦合度就越低,系統各個模組的維護性以及擴充套件性也就越好,這樣的系統也就越容易實現垂直切分。
但是往往系統中有些表難以做到完全的獨立,存在跨庫 `join` 的情況,對於這類分庫,可以共用一個數據源,業務之間通過介面來呼叫。
**優點**:規則明確、業務清晰、更易於整合和擴充套件、維護簡單。
**缺點**:部分業務表無法 `join`,需要通過業務介面方式解決,提高系統複雜度;各業務存在單庫效能瓶頸,不易於資料擴充套件和效能提高;事務處理複雜問題。
由於垂直切分是將表按照業務分類切分到不同的單庫中,所有導致某些業務表過於龐大,存在單庫讀寫與儲存瓶頸,則需要水平切分來解決。
#### 水平切分
水平切分不是將表按照業務分類,而是按照某個欄位的某種規則分散到多個庫中,每個表中包含一部分資料,如圖。
![](https://qiniuyun.antoniopeng.com/1597866083.jpg)
拆分資料需要定義分片規則,拆分的第一原則是找到 **拆分維度**。比如:從會員的角度來分析,需要查詢會員某天某月某個訂單,那麼就需要按照日期來拆分,不同的資料按照會員 ID 做分組。
**優點**:拆分規則抽象好;不存在單庫資料瓶頸問題;提高系統穩定性和負載能力。
**缺點**:事務一致性難以解決;資料擴充套件和維護的難度極大;跨庫 join 效能差。
#### 附:多資料來源管理方案
- 第一種:客戶端模式,在每個應用程式中配置管理自己需要的一個或多個數據源,直接訪問各個資料庫。
- 第二種:通過中間代理層來統一管理所有的資料來源。
### 搭建環境
> 均採用 Docker Compose 搭建服務
#### 部署 3 臺 MySQL 容器
分別建立 3 份 `docker-compose.yml` 檔案
- mysql-01
```yaml
version: '3.1'
services:
mysql-1:
image: mysql
container_name: mysql-01
environment:
MYSQL_ROOT_PASSWORD: 123456
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
ports:
- 3306:3306
volumes:
- ./data:/var/lib/mysql
```
- mysql-02
```yaml
version: '3.1'
services:
mysql-2:
image: mysql
container_name: mysql-02
environment:
MYSQL_ROOT_PASSWORD: 123456
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
ports:
- 3307:3306
volumes:
- ./data:/var/lib/mysql
```
- mysql-03
```yaml
version: '3.1'
services:
mysql-3:
image: mysql
container_name: mysql-03
environment:
MYSQL_ROOT_PASSWORD: 123456
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
ports:
- 3308:3306
volumes:
- ./data:/var/lib/mysql
```
分別啟動 3 臺容器
```sh
$ docker-compose up -d
```
#### 部署 MyCat 容器
- 克隆專案
```sh
$ git clone https://github.com/antoniopeng/docker.mycat.git
```
- 構建映象
```sh
$ cd docker.mycat
$ docker-compose build
```
- 啟動容器
```sh
$ docker-compose up -d
```
### 配置資料庫分片
> 此處以 **水平切分** 為例
#### 配置使用者名稱和密碼
```sh
$ vi config/mycat/server.xml
```
找到第 90 行,參考配置如下:
```xml
```
#### 配置資料庫節點
```sh
$ vi config/mycat/schema.xml
```
參考配置如下:
`