↓跳过正文
  1. blog/

Mysql简单高可用搭建: 异步主从复制+Orchestrator+ProxySQL

·1804 字·
Blog Mysql
Aoidayo
作者
Aoidayo
懒人
目录

为什么需要高可用?
#

规模越大、业务越关键,单点故障带来的代价越难以承受。单台数据库实例,无论硬件多可靠,故障是必然会发生的:磁盘损坏、内存故障、机房断电、误操作,这些都可能让这台唯一的主库瞬间不可用。

如果不使用高可用架构,那么RPO和RTO都无法保证。必须要有自动化的、即时的高可用方案,来将「数据丢失」和「恢复时间」保证在可控范围。

搭建结构
#

这里使用一个简单的高可用方案:

角色 最少机器数量 高可用的说明
基于GTID异步复制的MySQL一主两从 至少 3台(每台一个MySQL实例) mysql1/2/3 分布在不同物理机/可用区,才能真正做到高可用
Orchestrator + 元数据库 建议独立 1台(或多台组集群) Orchestrator自身也建议3节点做Raft集群,避免它自己是单点
ProxySQL 建议独立 1-2台(多台做负载均衡) 作为流量入口,也要避免单点故障
总结 最低高可用配置:mysql3台,orch+orch元数据库 1台,
ProxySQL1台,至少需要5台。

其中:

  • 基于GTID异步复制的MySQL一主两从:用GTID简化基于传统位点的主从复制,但是复制本身仍然是异步复制(主库不等从库确认就返回成功),所以RPO较大,没有被GTID解决。可以使用半同步方案来减少这一数据丢失风险。
  • Orchestrator 负责拓扑发现、故障检测、候选主库选举和自动切换。
  • ProxySQL 提供固定的读写、只读入口,并根据 Orchestrator API 和 MySQL read_only 状态更新路由。

在单机上实现,或者在腾讯云/阿里云的弹性ECS上按小时租,这里我在单机上实现:

Compose 服务 管理地址 角色
mysql1 127.0.0.1:3306 master,可写
mysql2 127.0.0.1:3307 GTID slave 从库,只读
mysql3 127.0.0.1:3308 GTID slave 从库,只读
orchestrator-db 127.0.0.1:3309 Orchestrator 元数据库
orchestrator 127.0.0.1:3000 拓扑管理、自动故障切换主库 ,旧主库重启后不会回归
proxysql 127.0.0.1:6032(管理)/6033(读)/6034(写) 读写分离和连接路由

GTID异步复制的Mysql Replication拓扑
#

二进制安装几个mysql实例:单二进制脚本🔗link

sudo python3 mysql_binary_install.py \
  --archive ~/mysql/Notes-Mysql/Mysql-Installer/mysql-8.0.37-linux-glibc2.28-x86_64.tar.xz \
  --md5sum 4ef87d5f5160a6565e767ec10002ce74 \
  --root-password 'Your@password123' \
  --port 3306 \
  --bind-address 0.0.0.0 \
  --server-id 101 \
  --report-host 127.0.0.1 \
  --report-port 3306

sudo python3 mysql_binary_install.py \
  --archive ~/mysql/Notes-Mysql/Mysql-Installer/mysql-8.0.37-linux-glibc2.28-x86_64.tar.xz \
  --md5sum 4ef87d5f5160a6565e767ec10002ce74 \
  --root-password 'Your@password123' \
  --port 3307 \
  --bind-address 0.0.0.0 \
  --server-id 102 \
  --report-host 127.0.0.1 \
  --report-port 3307 \
  --datadir /var/lib/mysql-3307 \
  --config /etc/my-3307.cnf

sudo python3 mysql_binary_install.py \
  --archive ~/mysql/Notes-Mysql/Mysql-Installer/mysql-8.0.37-linux-glibc2.28-x86_64.tar.xz \
  --md5sum 4ef87d5f5160a6565e767ec10002ce74 \
  --root-password 'Your@password123' \
  --port 3308 \
  --bind-address 0.0.0.0 \
  --server-id 103 \
  --report-host 127.0.0.1 \
  --report-port 3308 \
  --datadir /var/lib/mysql-3308 \
  --config /etc/my-3308.cnf

修改3307和3308上的slave配置:

// etc/my-3307.cnf, etc/my-3308.cnf
[mysqld]
read_only = ON
super_read_only = ON

在主库上添加replication账号:

CREATE USER 'repl'@'%' IDENTIFIED BY 'Your@password123';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';

在从库上进行复制配置

# 开启tls
CHANGE REPLICATION SOURCE TO SOURCE_SSL = 1; 

# 设置主库
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST = '127.0.0.1',
  SOURCE_USER = 'repl',
  SOURCE_PASSWORD = 'Your@password123',
  SOURCE_PORT = 3306,
  SOURCE_AUTO_POSITION = 1;

# 作为主从的 从节点
START REPLICA;

# 
SHOW REPLICA STATUS\G

此时主从搭建完成,等待主从同步结束,两个slave 3307和3308上面也有了replication的账号。

Orchestrator
#

个人还是推荐docker安装,本地部署需要查不少手册,有点累。

安装

wget https://github.com/openark/orchestrator/releases/download/v3.2.6/orchestrator_3.2.6_amd64.deb
dpkg -i ...
dpkg -r orchestrator

安装目录

安装目录:/usr/local/orchestrator

/usr/local/orchestrator/
├── orchestrator                        # 主程序二进制(19MB,2021-07-27)
├── orchestrator-sample.conf.json
├── orchestrator-sample-sqlite.conf.json
└── resources/
    ├── bin/orchestrator-client         # 客户端脚本
    ├── templates/                      # Web UI 模板
    ├── public/                         # 前端 js/css/图片
    ├── metrics/orchestrator-grafana.json
    └── pseudo-gtid/

配置/etc/orchestrator.conf.json

{
  "Debug": false,
  "ListenAddress": ":3000",

  "MySQLOrchestratorHost": "127.0.0.1",
  "MySQLOrchestratorPort": 3306,
  "MySQLOrchestratorDatabase": "orchestrator",
  "MySQLOrchestratorUser": "orch_backend",
  "MySQLOrchestratorPassword": "orch_backend_pass",


  "MySQLTopologyUser": "orch_topo",
  "MySQLTopologyPassword": "orch_topo_pass",

  "InstancePollSeconds": 5,
  "DiscoverByShowSlaveHosts": true,
  "UnseenInstanceForgetHours": 240,

  "RecoveryPeriodBlockSeconds": 3600,
  "RecoverMasterClusterFilters": ["*"],
  "PromotionIgnoreHostnameFilters": [],
}

创建orch元数据库

sudo python3 mysql_binary_install.py \
  --archive ~/mysql/Notes-Mysql/Mysql-Installer/mysql-8.0.37-linux-glibc2.28-x86_64.tar.xz \
  --md5sum 4ef87d5f5160a6565e767ec10002ce74 \
  --root-password 'Your@password123' \
  --port 3309 \
  --bind-address 0.0.0.0 \
  --server-id 104 \
  --report-host 127.0.0.1 \
  --report-port 3309 \
  --basedir /usr/local/mysql \
  --datadir /var/lib/mysql-3309 \
  --config /etc/my-3309.cnf

alias mysql3309='/usr/local/mysql/bin/mysql -uroot -h127.0.0.1 -P3309 -pYour@password123'

在主库上创建mysql用户,通过replication复制到从库上:

CREATE USER 'orch_topo'@'127.0.0.1' IDENTIFIED BY 'orch_topo_pass';
GRANT PROCESS, REPLICATION SLAVE, REPLICATION CLIENT, RELOAD ON *.* TO 'orch_topo'@'127.0.0.1';
GRANT REPLICATION_SLAVE_ADMIN, GROUP_REPLICATION_ADMIN ON *.* TO 'orch_topo'@'127.0.0.1';

在从库上select user, host, plugin from mysql.user;做验证。

在orch元数据库上创建用户

CREATE USER 'orch_backend'@'127.0.0.1' IDENTIFIED BY 'orch_backend_pass';
CREATE DATABASE IF NOT EXISTS orchestrator;
GRANT ALL ON orchestrator.* TO 'orch_backend'@'127.0.0.1';

进行orch发现

curl -s "http://127.0.0.1:3000/api/discover/127.0.0.1/3306"

有:

alt text

可以手动测试下故障切换

systemctl stop mysqld

停止3306后 3308自动提升为主库,自动切主的时候将新主库的两个read_only修改为false。

mysql> SELECT VARIABLE_NAME, VARIABLE_VALUE
    -> FROM performance_schema.global_variables
    -> WHERE VARIABLE_NAME IN ('read_only', 'super_read_only');
+-----------------+----------------+
| VARIABLE_NAME   | VARIABLE_VALUE |
+-----------------+----------------+
| read_only       | OFF            |
| super_read_only | OFF            |
+-----------------+----------------+
2 rows in set (0.00 sec)

mysql> SHOW global VARIABLES LIKE '%read_only';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_read_only      | OFF   |
| read_only             | OFF   |
| super_read_only       | OFF   |
| transaction_read_only | OFF   |
+-----------------------+-------+
4 rows in set (0.01 sec)

proxySQL
#

用于分流的工具,提供固定的读写、只读入口,并根据 Orchestrator API 和 MySQL read_only 状态更新路由。

在故障切换的时候,自动切换可写主库,在应用层我们只需要填写两个东西:读写url+用户名密码、只读url+用户名密码。

需要在orchestrator 配置的json中添加钩子:

{
  "PostMasterFailoverProcesses": [
    "curl -fsS -X POST http://proxy-sync:8080/sync >/dev/null 2>&1 || true",
    "echo 'Master failover complete: {failedHost}:{failedPort} -> {successorHost}:{successorPort}' >> /tmp/recovery.log"
  ],
  "PostIntermediateMasterFailoverProcesses": [
    "curl -fsS -X POST http://proxy-sync:8080/sync >/dev/null 2>&1 || true",
    "echo 'Intermediate master failover complete: {failedHost}:{failedPort} -> {successorHost}:{successorPort}' >> /tmp/recovery.log"
  ],
  "PostGracefulTakeoverProcesses": [
    "curl -fsS -X POST http://proxy-sync:8080/sync >/dev/null 2>&1 || true",
    "echo 'Graceful takeover complete: {failedHost}:{failedPort} -> {successorHost}:{successorPort}' >> /tmp/recovery.log"
  ],
}

这块要记录的内容比较多,有时间以后再写。


0