MySQL 高可用:InnoDB Cluster 部署詳解

最近公眾號(hào)有人留言:為啥使用 ProxySQL 而不使用 InnoDB Cluster ?
其實(shí)使用什么方案,根據(jù)實(shí)際情況進(jìn)行權(quán)衡利弊即可,如果先部署了 MGR ,想在此基礎(chǔ)之上完善高可用,添加 ProxySQL 比較方便。如果新部署一個(gè)高可用環(huán)境,直接使用 InnoDB Cluster 也可以,InnoDB Cluster 也是依賴(lài) MGR 。
下面從零開(kāi)始,來(lái)講解怎么通過(guò) Docker Compose 來(lái)部署 MySQL InnoDB Cluster,讓你能夠快速搭建一套完整的高可用數(shù)據(jù)庫(kù)系統(tǒng)。
什么是 MySQL InnoDB Cluster
核心概念
MySQL InnoDB Cluster是 MySQL 官方提供的高可用解決方案,它基于以下三個(gè)核心組件:
- MySQL Group Replication:提供數(shù)據(jù)復(fù)制和故障檢測(cè),這個(gè)就是前面文章中提到的 MGR
- MySQL Router:提供透明的路由和負(fù)載均衡
- MySQL Shell:提供集群管理和監(jiān)控功能
架構(gòu)優(yōu)勢(shì)
- 自動(dòng)故障檢測(cè)和轉(zhuǎn)移
- 強(qiáng)一致性數(shù)據(jù)復(fù)制
- 透明的讀寫(xiě)分離
- 簡(jiǎn)化的管理操作
架構(gòu)圖開(kāi)始部署
為了測(cè)試方便,在一臺(tái)服務(wù)器上使用 docker compose 部署多個(gè)服務(wù)節(jié)點(diǎn)。
啟動(dòng) MySQL 節(jié)點(diǎn)
在服務(wù)器上創(chuàng)建一個(gè)目錄 mysql-innodb-cluster ,目錄中按照下圖進(jìn)行目錄和文件的創(chuàng)建。
docker-compose.yml 文件內(nèi)容如下:
version: '3.8'
services:
mysql1:
image: mysql:8.0.39
container_name: mysql1
hostname: mysql1
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: rootpass123
TZ: Asia/Shanghai
networks:
- mysql-cluster-net
volumes:
- ./node1/conf:/etc/mysql/conf.d:ro
- ./node1/data:/var/lib/mysql
- ./node1/log:/var/log/mysql
ports:
- "3310:3306"
mysql2:
image: mysql:8.0.39
container_name: mysql2
hostname: mysql2
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: rootpass123
TZ: Asia/Shanghai
networks:
- mysql-cluster-net
volumes:
- ./node2/conf:/etc/mysql/conf.d:ro
- ./node2/data:/var/lib/mysql
- ./node2/log:/var/log/mysql
ports:
- "3311:3306"
mysql3:
image: mysql:8.0.39
container_name: mysql3
hostname: mysql3
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: rootpass123
TZ: Asia/Shanghai
networks:
- mysql-cluster-net
volumes:
- ./node3/conf:/etc/mysql/conf.d:ro
- ./node3/data:/var/lib/mysql
- ./node3/log:/var/log/mysql
ports:
- "3312:3306"
mysql-router:
image: mysql/mysql-router:8.0
container_name: mysql-router
restart: unless-stopped
depends_on:
- mysql1
- mysql2
- mysql3
networks:
- mysql-cluster-net
volumes:
- ./router/data:/tmp/mysqlrouter
ports:
- "6446:6446" # 讀寫(xiě)端口 (RW)
- "6447:6447" # 只讀端口 (RO)
- "6448:6448" # 管理端口 (X Protocol RW)
- "6449:6449" # 管理端口 (X Protocol RO)
environment:
MYSQL_HOST: mysql1
MYSQL_PORT: 3306
MYSQL_USER: clusteradmin
MYSQL_PASSWORD: clusterpass123
MYSQL_CREATE_ROUTER_USER: 0
MYSQL_ROUTER_BOOTSTRAP_EXTRA_OPTIONS: >
--conf-use-sockets
--conf-bind-address 0.0.0.0
--conf-base-port 6446
networks:
mysql-cluster-net:
driver: bridge
name: mysql-cluster-netrouter 節(jié)點(diǎn)說(shuō)明:
- 檢測(cè)
/tmp/mysqlrouter/mysqlrouter.conf是否存在,如果不存在則執(zhí)行mysqlrouter --bootstrap clusteradmin@mysql1:3306 ... --directory /tmp/mysqlrouter,密碼從MYSQL_PASSWORD變量讀入,非交互(不用手動(dòng)輸入)。 - bootstrap 成功后,以后每次容器重啟直接
mysqlrouter -c /tmp/mysqlrouter/mysqlrouter.conf不再重新掃描集群,配置持久化。 - Router 根據(jù)集群實(shí)時(shí)角色,把 6446 流量轉(zhuǎn)發(fā)到 PRIMARY,6447 轉(zhuǎn)發(fā)到 SECONDARY,應(yīng)用只需連固定端口即可。
mysql 節(jié)點(diǎn) 1 的配置文件 mysql1.cnf 內(nèi)容如下:
[mysqld]
# 網(wǎng)絡(luò)和連接
bind-address = 0.0.0.0
# 復(fù)制基礎(chǔ)
server_id = 1
log_bin = mysql-bin
binlog_format = ROW
enforce_gtid_consistency = ON
gtid_mode = ON
# Group Replication 特定配置
transaction_write_set_extraction = XXHASH64
loose-group_replication_group_name = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" # 請(qǐng)?zhí)鎿Q為一個(gè)有效的UUID,可使用 `uuidgen` 命令生成
loose-group_replication_start_on_boot = OFF
loose-group_replication_local_address = "mysql1:33061" # 內(nèi)部組通信地址和端口,通常為 33061
loose-group_replication_group_seeds = "mysql1:33061, mysql2:33061, mysql3:33061"
loose-group_replication_single_primary_mode = ON # 單主模式
loose-group_replication_bootstrap_group = OFF # 切勿隨意開(kāi)啟引導(dǎo)
# Innodb Cluster 元數(shù)據(jù)存儲(chǔ)
disabled_storage_engines = MyISAM,BLACKHOLE,FEDERATED,ARCHIVE
# 性能與可靠性
binlog_transaction_dependency_tracking = WRITESETmysql 節(jié)點(diǎn) 2 的配置文件 mysql2.cnf 內(nèi)容如下:
[mysqld]
bind-address = 0.0.0.0
server_id = 2
log_bin = mysql-bin
binlog_format = ROW
enforce_gtid_consistency = ON
gtid_mode = ON
transaction_write_set_extraction = XXHASH64
loose-group_replication_group_name = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" # 必須與node1相同
loose-group_replication_start_on_boot = OFF
loose-group_replication_local_address = "mysql2:33061"
loose-group_replication_group_seeds = "mysql1:33061, mysql2:33061, mysql3:33061"
loose-group_replication_single_primary_mode = ON
loose-group_replication_bootstrap_group = OFF
disabled_storage_engines = MyISAM,BLACKHOLE,FEDERATED,ARCHIVE
binlog_transaction_dependency_tracking = WRITESETmysql 節(jié)點(diǎn) 3 的配置文件 mysql3.cnf 內(nèi)容如下:
[mysqld]
bind-address = 0.0.0.0
server_id = 3
log_bin = mysql-bin
binlog_format = ROW
enforce_gtid_consistency = ON
gtid_mode = ON
transaction_write_set_extraction = XXHASH64
loose-group_replication_group_name = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" # 必須與node1相同
loose-group_replication_start_on_boot = OFF
loose-group_replication_local_address = "mysql3:33061"
loose-group_replication_group_seeds = "mysql1:33061, mysql2:33061, mysql3:33061"
loose-group_replication_single_primary_mode = ON
loose-group_replication_bootstrap_group = OFF
disabled_storage_engines = MyISAM,BLACKHOLE,FEDERATED,ARCHIVE
binlog_transaction_dependency_tracking = WRITESET節(jié)點(diǎn) 3 內(nèi)容與節(jié)點(diǎn) 2 類(lèi)似,但 server_id 必須改為 3,loose-group_replication_local_address 改為 mysql3:33061。loose-group_replication_group_name 必須與其它節(jié)點(diǎn)相同。
關(guān)于配置文件中 mgr 相關(guān)的部分可以參考之前的文章《MySQL高可用-使用Docker部署MGR》。
執(zhí)行下面的命令,先啟動(dòng)三個(gè) mysql 節(jié)點(diǎn)。
docker-compose up -d mysql1 mysql2 mysql3等三個(gè) mysql 節(jié)點(diǎn)都啟動(dòng)成功后,再執(zhí)行下面的操作。
添加集群管理賬戶
在三個(gè) MySQL 節(jié)點(diǎn)上,都需要?jiǎng)?chuàng)建一個(gè)用于集群管理和 Router 引導(dǎo)的管理員用戶(需要 SYSTEM_VARIABLES_ADMIN, REPLICATION_SLAVE_ADMIN, GROUP_REPLICATION_ADMIN 權(quán)限)。
先使用下面命令連接到節(jié)點(diǎn) 1 的 shell:
# 連接到 mysql1 容器并登錄 MySQL
docker-compose exec mysql1 mysql -uroot -prootpass123然后執(zhí)行下面的語(yǔ)句進(jìn)行 clusteradmin 賬戶的創(chuàng)建和權(quán)限設(shè)置:
CREATE USER IF NOT EXISTS 'clusteradmin'@'%' IDENTIFIED WITH mysql_native_password BY 'clusterpass123';
GRANT ALL PRIVILEGES ON *.* TO 'clusteradmin'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;在節(jié)點(diǎn) 2 和節(jié)點(diǎn) 3 上執(zhí)行相同的操作。
使用 mysql shell 構(gòu)建集群
配置和啟動(dòng) InnoDB Cluster,可以使用 MySQL Shell (mysqlsh) 來(lái)創(chuàng)建集群。臨時(shí)啟動(dòng)一個(gè) MySQL Shell 容器。
docker run --rm -it --network=mysql-cluster-net mysql/mysql-server:8.0 mysqlsh執(zhí)行成后會(huì)進(jìn)入到 MySQL JS 的 shell 界面,如下圖:
在 shell 模式下逐步執(zhí)行下面的代碼:
// 連接到第一個(gè)節(jié)點(diǎn)(將成為初始主節(jié)點(diǎn))
\connect clusteradmin@mysql1:3306
// 提供密碼:clusterpass123
// 檢查實(shí)例配置是否符合集群要求
dba.checkInstanceConfiguration('clusteradmin@mysql1:3306');
dba.checkInstanceConfiguration('clusteradmin@mysql2:3306');
dba.checkInstanceConfiguration('clusteradmin@mysql3:3306');
// 創(chuàng)建集群,命名為 'myCluster'
var cluster = dba.createCluster('myCluster');
// 添加其他實(shí)例到集群中
cluster.addInstance('clusteradmin@mysql2:3306', {password: 'your_strong_clusteradmin_password', recoveryMethod: 'clone'}); // 使用 clone 方式進(jìn)行恢復(fù)
cluster.addInstance('clusteradmin@mysql3:3306', {password: 'your_strong_clusteradmin_password', recoveryMethod: 'clone'});
// 檢查集群狀態(tài)
cluster.status();節(jié)點(diǎn)成功添加到集群中如下圖:
最后查看集群狀態(tài):
輸出應(yīng)顯示三個(gè)實(shí)例都是 ONLINE,其中一個(gè)角色是 PRIMARY,另外兩個(gè)是 SECONDARY。
啟動(dòng)并配置 MySQL Router
執(zhí)行下面命令啟動(dòng) router 容器
docker-compose up -d mysql-routerrouter 啟動(dòng)成功的日志如下:
到這 MySQL InnoDB Cluster 已經(jīng)部署完成,可以使用 Navicat 之類(lèi)的工具進(jìn)行連接進(jìn)行測(cè)試:
使用 Navicat 時(shí)需要注意,SSL 中的使用 SSL 必須勾選。
最后
一開(kāi)始想使用 AI 來(lái)生成所有的配置,嘗試了很多次,沒(méi)有能一次性成功的,根據(jù)日志中的錯(cuò)誤信息讓 AI 修改,越改越混亂。因?yàn)檎麄€(gè)過(guò)程中我沒(méi)有參與,給不出更多有價(jià)值的信息,最后放棄了讓 AI 直接來(lái)操作。
從這個(gè)過(guò)程我體會(huì)到更好使用 AI 的方式應(yīng)該是:
- 先讓 AI 總結(jié)出部署 MySQL InnoDB Cluster 的關(guān)鍵步驟。
- 從這個(gè)步驟中了解到一些基本的原理,然后分步驟讓 AI 搞定配置,實(shí)操的過(guò)程中也是分步驟進(jìn)行,這樣即便出現(xiàn)問(wèn)題也比較容易排查。
- 手動(dòng)一步一步去操作,有助于更好的理解和理清邏輯關(guān)系。
- 學(xué)習(xí)任何技術(shù),我們自己懂的越多,就越能讓 AI 發(fā)揮更大的能力。





























