跳到主要内容

第11章 MySQL高可用之Orchestrator

Orchestrator高可用方案

附件说明

本章涉及的软件包和配置文件:

1721789844223-29a666d4-4822-4547-838b-00e8b67a9865.png

1. Orchestrator介绍与特性

Orchestrator 是一个专门用于 MySQL 高可用性(High Availability, HA)管理和故障恢复的开源工具。它专注于 MySQL 复制拓扑的管理、监控和自动化,特别是在主从复制(Replication)和组复制(Group Replication)环境中。Orchestrator 能够自动检测故障、执行主从切换(Failover),并确保数据库集群的高可用性。

Orchestrator 的核心功能

  1. 拓扑发现与可视化
    • 自动发现 MySQL 复制拓扑(主从关系)。
    • 提供 Web 界面,直观展示复制拓扑结构,包括主库、从库、中间主库等。
  2. 故障检测与恢复
    • 实时监控 MySQL 实例的健康状态。
    • 在主库故障时,自动或手动执行故障转移(Failover),将合适的从库提升为新的主库。
    • 支持多种故障恢复策略,如基于 GTID(Global Transaction Identifier)的复制修复。
  3. 复制拓扑管理
    • 支持手动或自动调整复制拓扑,例如将从库切换到新的主库。
    • 支持复杂的复制结构,如链式复制(Chain Replication)和多层主从架构。
  4. 高可用性支持
    • 与 MySQL 主从复制和组复制(Group Replication)深度集成。
    • 支持半同步复制(Semi-Synchronous Replication)和 GTID。
  5. 自动化与手动控制
    • 提供自动化故障转移功能,同时也支持手动干预。
    • 可以通过命令行工具或 Web 界面进行操作。
  6. 历史记录与审计
    • 记录所有拓扑变更和故障转移操作,便于审计和故障排查。
  7. REST API
    • 提供 RESTful API,方便与其他工具或系统集成,实现自动化运维。

Orchestrator 的架构

  • 分布式架构:Orchestrator 本身支持多节点部署,具有高可用性。
  • 后端存储:使用 MySQL 或 SQLite 存储拓扑信息和元数据。
  • Web 界面:提供友好的用户界面,方便管理员查看和管理复制拓扑。

Orchestrator 的应用场景

  1. MySQL 主从复制环境
    • 在主库故障时,自动选择并提升从库为新的主库,确保服务不中断。
    • 管理复杂的复制拓扑,如链式复制或多主架构。
  2. MySQL 组复制(Group Replication)环境
    • 监控组复制的健康状态,自动处理节点故障。
  3. 混合环境
    • 支持传统异步复制和半同步复制的混合环境。
  4. 多数据中心部署
    • 支持跨数据中心的 MySQL 复制拓扑管理。

Orchestrator 的优势

  1. 高可用性
    • 自动故障转移,减少人工干预,确保数据库服务的连续性。
  2. 易用性
    • 提供直观的 Web 界面和丰富的 API,便于管理和集成。
  3. 灵活性
    • 支持多种 MySQL 复制模式,适应不同的业务需求。
  4. 开源
    • 完全开源,社区活跃,支持自定义扩展
注意事项

Orchestrator 虽然功能强大,但也有一定的学习曲线,需要充分理解其配置和操作原理。

Orchestrator 与其他工具的比较

工具特点
Orchestrator专注于 MySQL 复制拓扑管理,支持自动故障转移,开源且灵活。
MHAMySQL Master High Availability,专注于主从复制的故障转移,但功能相对简单。
ProxySQL主要用于负载均衡和查询路由,不直接提供故障转移功能。
Galera Cluster提供多主复制和高可用性,但与 Orchestrator 的定位不同。

总结

Orchestrator 是一个强大的 MySQL 高可用性管理工具,特别适合需要自动化故障转移和复杂复制拓扑管理的场景。它通过提供自动化的故障检测、恢复和拓扑管理功能,显著提高了 MySQL 集群的可靠性和运维效率。对于依赖 MySQL 作为核心数据库的企业来说,Orchestrator 是一个值得考虑的高可用性解决方案。

2. Orchestrator部署与管理

MySQL主从环境搭建部署

停掉MHA服务
重要操作

注意!db-53服务器都操作!

masterha_stop  --conf=/etc/mha/app1.cnf
清理旧数据
重要操作

注意!所有MySQL服务器都操作!

systemctl stop mysqld
rm -rf /data/mysql_3306/*
rm -rf /data/binlogs/*
mysqld --initialize-insecure --user=mysql --basedir=/opt/mysql --datadir=/data/mysql_3306/
systemctl start mysqld
mysqladmin password 123
主库配置远程复制账号
重要操作

注意!db-51服务器都操作!

mysql -uroot -p123
grant all privileges on *.* to root@'10.0.0.%' identified by '123';
grant replication slave on *.* to repl@'10.0.0.%' identified by '123';
flush privileges;
从库配置复制信息
重要操作

注意!db-52和db-53服务器都操作!

mysql -uroot -p123
change master to
master_host='10.0.0.51',
master_user='repl',
master_password='123' ,
MASTER_AUTO_POSITION=1;
start slave;
show slave status\G
set global read_only=1;
set global super_read_only=on;
详细配置脚本
参考脚本

以下为完整的MySQL主从环境搭建脚本,供参考使用

# MySQL主从环境搭建详细步骤

# 1.db-51主库清理
systemctl stop mysqld
rm -rf /data/mysql_3306/*
rm -rf /data/binlogs/*

cat> /etc/my.cnf <<EOF
[mysqld]
port=3306
user=mysql
basedir=/opt/mysql
datadir=/data/mysql_3306
server_id=51
log_bin=/data/binlogs/mysql-bin
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
socket=/tmp/mysql.sock

[mysql]
socket=/tmp/mysql.sock

[client]
socket=/tmp/mysql.sock
EOF

mysqld --initialize-insecure --user=mysql --basedir=/opt/mysql --datadir=/data/mysql_3306/
systemctl start mysqld
mysqladmin password 123
mysql -uroot -p123 -e "reset master;"

# 2.搭建从库
# db52-操作
systemctl stop mysqld
rm -rf /data/mysql_3306/*
rm -rf /data/binlogs/*

cat> /etc/my.cnf <<EOF
[mysqld]
port=3306
user=mysql
basedir=/opt/mysql
datadir=/data/mysql_3306
server_id=52
log_bin=/data/binlogs/mysql-bin
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
socket=/tmp/mysql.sock

[mysql]
socket=/tmp/mysql.sock

[client]
socket=/tmp/mysql.sock
EOF

mysqld --initialize-insecure --user=mysql --basedir=/opt/mysql --datadir=/data/mysql_3306/
systemctl start mysqld
mysqladmin password 123
mysql -uroot -p123 -e "reset master;"

# db-53操作
cd /opt/
tar zxf mysql-5.7.28-linux-glibc2.12-x86_64.tar.gz -C /opt/
mv mysql-5.7.28-linux-glibc2.12-x86_64 mysql-5.7.28
ln -s mysql-5.7.28 mysql
echo 'PATH=$PATH:/opt/mysql/bin' >> /etc/profile
source /etc/profile
mysql -V
rpm -qa|grep mariadb
yum remove mariadb-libs -y
rm -rf /etc/my.cnf
yum install -y libaio-devel
mkdir /data/{mysql_3306,binlogs} -p
useradd -s /sbin/nologin -M mysql
chown -R mysql:mysql /data/
chown -R mysql:mysql /opt/mysql*
cat> /etc/my.cnf <<EOF
[mysqld]
port=3306
user=mysql
basedir=/opt/mysql
datadir=/data/mysql_3306
server_id=53
log_bin=/data/binlogs/mysql-bin
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
socket=/tmp/mysql.sock

[mysql]
socket=/tmp/mysql.sock

[client]
socket=/tmp/mysql.sock
EOF
mysqld --initialize-insecure --user=mysql --basedir=/opt/mysql --datadir=/data/mysql_3306/
cp /opt/mysql/support-files/mysql.server /etc/init.d/mysqld
chkconfig --add mysqld
systemctl start mysqld
netstat -lntup|grep 3306
mysqladmin password 123
mysql -uroot -p123 -e "reset master;"

ORCH搭建部署

建立ssh互信

1)每个节点上执行以下命令生成ssh密钥

ssh-keygen -f /root/.ssh/id_rsa -N ''

2)免交互分发公钥

yum install sshpass -y
sshpass -p "123" ssh-copy-id 10.0.0.51 -o StrictHostKeyChecking=no
sshpass -p "123" ssh-copy-id 10.0.0.52 -o StrictHostKeyChecking=no
sshpass -p "123" ssh-copy-id 10.0.0.53 -o StrictHostKeyChecking=no

3)验证

ssh 10.0.0.51 'hostname'
ssh 10.0.0.52 'hostname'
ssh 10.0.0.53 'hostname'
部署ORCH后端MySQL多实例环境
重要操作

注意!所有ORCH机器都操作!

#1.创建配置文件
cat > /etc/my_3307.cnf << 'EOF'
[mysqld]
port=3307
user=mysql
basedir=/opt/mysql
datadir=/data/mysql_3307
socket=/tmp/mysql_3307.sock

[mysql]
socket=/tmp/mysql_3307.sock

[client]
socket=/tmp/mysql_3307.sock
EOF

#2.创建数据目录
mkdir /data/mysql_3307 -p
chown -R mysql:mysql /data/mysql_3307/

#3.MySQL数据初始化
mysqld --initialize-insecure --user=mysql --basedir=/opt/mysql --datadir=/data/mysql_3307/

#4.写入启动脚本
cat >/etc/systemd/system/mysqld_3307.service <<EOF
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/opt/mysql/bin/mysqld_safe --defaults-file=/etc/my_3307.cnf
LimitNOFILE = 5000
EOF

#5.启动MySQL
systemctl daemon-reload
systemctl start mysqld_3307.service
systemctl status mysqld_3307.service
mysqladmin -S /tmp/mysql_3307.sock password 123
mysql -uroot -p123 -S /tmp/mysql_3307.sock
部署Orchestrator

1)被管理的业务数据库的主库上创建账号

重要操作

注意!只在51操作!业务数据库3306

mysql -uroot -p123
CREATE USER 'orchestrator'@'%' IDENTIFIED BY 'orchestrator';
GRANT SUPER, PROCESS, REPLICATION SLAVE, RELOAD ON *.* TO 'orchestrator'@'%';
GRANT SELECT ON mysql.slave_master_info TO 'orchestrator'@'%';
GRANT SELECT ON meta.* TO 'orchestrator'@'%';
flush privileges;

2)创建ORCH数据库和用户

重要操作

注意!所有ORCH机器都操作!ORCH数据库3307

mysql -uroot -p123 -S /tmp/mysql_3307.sock
CREATE DATABASE orchestrator;
GRANT all privileges ON orchestrator.* TO 'orchestrator'@'127.0.0.1' IDENTIFIED BY 'orchestrator';
flush privileges;

3)安装部署ORCH软件

重要操作

注意!所有ORCH机器都操作!

第一步:解压并创建日志目录

tar -zxf /opt/orchestrator-3.2.6-linux-amd64.tar.gz -C /mnt/
cp -r /mnt/usr/local/orchestrator /usr/local/
mkdir /usr/local/orchestrator/log

第二步:创建用户并授权目录

groupadd -g 10008 orchestrator
useradd orchestrator -u 10008 -g 10008 -m -s /bin/bash
chown -R orchestrator:orchestrator /usr/local/orchestrator

第三步:写入环境变量并生效

echo 'PATH=$PATH:/usr/local/orchestrator:/usr/local/orchestrator/resources/bin' >> /etc/profile
source /etc/profile

第四步:编辑ORCH配置文件

重要提示

注意!有坑!每个机器配置都不一样!

脚本来自国外网友:

注意:"RaftBind":"10.0.0.51" 每个机器改成自己的IP

cat > /usr/local/orchestrator/orchestrator.conf.json << 'EOF'
{
"Debug": true,
"EnableSyslog": false,
"ListenAddress": ":3000",
"MySQLTopologyUser": "orchestrator",
"MySQLTopologyPassword": "orchestrator",
"MySQLTopologyCredentialsConfigFile": "",
"MySQLTopologySSLPrivateKeyFile": "",
"MySQLTopologySSLCertFile": "",
"MySQLTopologySSLCAFile": "",
"MySQLTopologySSLSkipVerify": true,
"MySQLTopologyUseMutualTLS": false,
"MySQLOrchestratorHost": "127.0.0.1",
"MySQLOrchestratorPort": 3307,
"MySQLOrchestratorDatabase": "orchestrator",
"MySQLOrchestratorUser": "orchestrator",
"MySQLOrchestratorPassword": "orchestrator",
"MySQLOrchestratorCredentialsConfigFile": "",
"MySQLOrchestratorSSLPrivateKeyFile": "",
"MySQLOrchestratorSSLCertFile": "",
"MySQLOrchestratorSSLCAFile": "",
"MySQLOrchestratorSSLSkipVerify": true,
"MySQLOrchestratorUseMutualTLS": false,
"MySQLConnectTimeoutSeconds": 1,
"DefaultInstancePort": 3307,
"DiscoverByShowSlaveHosts": true,
"InstancePollSeconds": 5,
"DiscoveryIgnoreReplicaHostnameFilters": [
"a_host_i_want_to_ignore[.]example[.]com",
".*[.]ignore_all_hosts_from_this_domain[.]example[.]com",
"a_host_with_extra_port_i_want_to_ignore[.]example[.]com:3307"
],
"UnseenInstanceForgetHours": 240,
"SnapshotTopologiesIntervalHours": 0,
"InstanceBulkOperationsWaitTimeoutSeconds": 10,
"HostnameResolveMethod": "none",
"MySQLHostnameResolveMethod": "@@report_host",
"SkipBinlogServerUnresolveCheck": true,
"ExpiryHostnameResolvesMinutes": 60,
"RejectHostnameResolvePattern": "",
"ReasonableReplicationLagSeconds": 10,
"ProblemIgnoreHostnameFilters": [],
"VerifyReplicationFilters": false,
"ReasonableMaintenanceReplicationLagSeconds": 20,
"CandidateInstanceExpireMinutes": 60,
"AuditLogFile": "",
"AuditToSyslog": false,
"RemoveTextFromHostnameDisplay": ".mydomain.com:3307",
"ReadOnly": false,
"AuthenticationMethod": "",
"HTTPAuthUser": "admin",
"HTTPAuthPassword": "Admin#123456",
"AuthUserHeader": "",
"PowerAuthUsers": [
"*"
],
"ClusterNameToAlias": {
"127.0.0.1": "test suite"
},
"ReplicationLagQuery": "",
"DetectClusterAliasQuery": "select replace(substr(@@hostname, 1, instr(@@hostname, 'mysql')-2), '-', '_')",
"DetectClusterDomainQuery": "",
"DetectInstanceAliasQuery": "",
"DetectPromotionRuleQuery": "",
"DataCenterPattern": "[.]([^.]+)[.][^.]+[.]mydomain[.]com",
"PhysicalEnvironmentPattern": "[.]([^.]+[.][^.]+)[.]mydomain[.]com",
"PromotionIgnoreHostnameFilters": [],
"DetectSemiSyncEnforcedQuery": "",
"ServeAgentsHttp": false,
"AgentsServerPort": ":3001",
"AgentsUseSSL": false,
"AgentsUseMutualTLS": false,
"AgentSSLSkipVerify": false,
"AgentSSLPrivateKeyFile": "",
"AgentSSLCertFile": "",
"AgentSSLCAFile": "",
"AgentSSLValidOUs": [],
"UseSSL": false,
"UseMutualTLS": false,
"SSLSkipVerify": false,
"SSLPrivateKeyFile": "",
"SSLCertFile": "",
"SSLCAFile": "",
"SSLValidOUs": [],
"URLPrefix": "",
"StatusEndpoint": "/api/status",
"StatusSimpleHealth": true,
"StatusOUVerify": false,
"AgentPollMinutes": 60,
"UnseenAgentForgetHours": 6,
"StaleSeedFailMinutes": 60,
"SeedAcceptableBytesDiff": 8192,
"PseudoGTIDPattern": "",
"PseudoGTIDPatternIsFixedSubstring": false,
"PseudoGTIDMonotonicHint": "asc:",
"DetectPseudoGTIDQuery": "",
"BinlogEventsChunkSize": 10000,
"SkipBinlogEventsContaining": [],
"ReduceReplicationAnalysisCount": true,
"FailureDetectionPeriodBlockMinutes": 1,
"FailMasterPromotionOnLagMinutes": 0,
"RecoveryPeriodBlockSeconds": 60,
"RecoveryIgnoreHostnameFilters": [],
"RecoverMasterClusterFilters": [
"*"
],
"RecoverIntermediateMasterClusterFilters": [
"*"
],
"OnFailureDetectionProcesses": [
"echo 'Detected {failureType} on {failureCluster}. Affected replicas:{countSlaves}' >> /usr/local/orchestrator/log/recovery.log"
],
"PreGracefulTakeoverProcesses": [
"echo 'Planned takeover about to take place on {failureCluster}. Master will switch to read_only' >> /usr/local/orchestrator/log/recovery.log"
],
"PreFailoverProcesses": [
"echo 'Will recover from {failureType} on {failureCluster}' >> /usr/local/orchestrator/log/recovery.log"
],
"PostFailoverProcesses": [
"echo 'Recovered from {failureType} on {failureCluster}. Failed: {failedHost}:{failedPort}; Successor: {successorHost}: {successorPort}; failureClusterAlias:{failureClusterAlias}' >> /usr/local/orchestrator/log/recovery.log",
"/usr/local/orchestrator/orch_hook.sh {failureType} {failureClusterAlias} {failedHost} {successorHost} >> /usr/local/orchestrator/log/recovery_orch_hook.log"
],
"PostUnsuccessfulFailoverProcesses": [],
"PostMasterFailoverProcesses": [
"echo 'Recovered from {failureType} on {failureCluster}. Failed: {failedHost}:{failedPort}; Promoted: {successorHost}:{successorPort}' >> /usr/local/orchestrator/log/recovery.log"
],
"PostIntermediateMasterFailoverProcesses": [
"echo 'Recovered from {failureType} on {failureCluster}. Failed: {failedHost}:{failedPort}; Successor: {successorHost}:{successorPort}' >> /usr/local/orchestrator/log/recovery.log"
],
"PostGracefulTakeoverProcesses": [
"echo 'Planned takeover complete' >> /usr/local/orchestrator/log/recovery.log"
],
"CoMasterRecoveryMustPromoteOtherCoMaster": true,
"DetachLostSlavesAfterMasterFailover": true,
"ApplyMySQLPromotionAfterMasterFailover": true,
"PreventCrossDataCenterMasterFailover": false,
"PreventCrossRegionMasterFailover": false,
"FailMasterPromotionIfSQLThreadNotUpToDate": false,
"DelayMasterPromotionIfSQLThreadNotUpToDate": true,
"DetachLostReplicasAfterMasterFailover": true,
"MasterFailoverDetachReplicaMasterHost": false,
"MasterFailoverLostInstancesDowntimeMinutes": 0,
"PostponeReplicaRecoveryOnLagMinutes": 0,
"OSCIgnoreHostnameFilters": [],
"GraphiteAddr": "",
"GraphitePath": "",
"GraphiteConvertHostnameDotsToUnderscores": true,
"ConsulAddress": "",
"ConsulAclToken": "",
"ConsulKVStoreProvider": "consul",
"RaftEnabled": true,
"BackendDB": "mysql",
"RaftDataDir": "/usr/local/orchestrator",
"RaftBind": "10.0.0.51",
"DefaultRaftPort": 10008,
"RaftNodes": [
"10.0.0.51",
"10.0.0.52",
"10.0.0.53"
]
}
EOF

第五步:编辑ORCH切换VIP脚本

重要提示

注意!有坑!每个机器配置都不一样!

orch_hook.sh是一个事件监听脚本,如果Master挂了,他会去调用另一个脚本来切换VIP。

须修改配置:

  • local_ip="10.0.0.51" - 当前主机IP
  • mysql_vip="10.0.0.100" - mysql集群VIP
  • eth_dev="eth0" - 当前主机网卡名

写入配置文件:

#1.创建脚本
cat > /usr/local/orchestrator/orch_hook.sh << 'EOFF'
#!/bin/bash

isitdead=$1
cluster=$2
oldmaster=$3
newmaster=$4
mysqluser="orchestrator"
export MYSQL_PWD="orchestrator"
sshoptions="-p 22 -o StrictHostKeyChecking=no"
logfile="/usr/local/orchestrator/log/orch_hook.log"
local_ip="10.0.0.51"
mysql_vip="10.0.0.100"
eth_dev="eth0"

if [[ $isitdead == "DeadMaster" ]]; then
array=( ${eth_dev} "${mysql_vip}" root "${local_ip}")
interface=${array[0]}
IP=${array[1]}
user=${array[2]}
echo "array: $array"
echo "interface: $interface"
echo "IP: $IP"
echo "user: $user"
if [ ! -z ${IP} ] ; then
echo $(date)
echo "Recovering from: $isitdead"
echo "New master is: $newmaster"
echo "/usr/local/orchestrator/orch_vip.sh -d 1 -n $newmaster -s ${sshoptions} -i ${interface} -I ${IP} -u ${user} -o $oldmaster" | tee $logfile
/usr/local/orchestrator/orch_vip.sh -d 1 -n $newmaster -s "${sshoptions}" -i ${interface} -I ${IP} -u ${user} -o $oldmaster
else
echo "Cluster does not exist!" | tee $logfile
fi
elif [[ $isitdead == "DeadIntermediateMasterWithSingleSlaveFailingToConnect" ]]; then
array=( ${eth_dev} "${mysql_vip}" root "${local_ip}")
interface=${array[0]}
IP=${array[3]}
user=${array[2]}
slavehost=`echo $5 | cut -d":" -f1`
echo $(date)
echo "Recovering from: $isitdead"
echo "New intermediate master is: $slavehost"
echo "/usr/local/orchestrator/orch_vip.sh -d 1 -n $slavehost -s ${sshoptions} -i ${interface} -I ${IP} -u ${user} -o $oldmaster" | tee $logfile
/usr/local/orchestrator/orch_vip.sh -d 1 -n $slavehost -s "${sshoptions}" -i ${interface} -I ${IP} -u ${user} -o $oldmaster
elif [[ $isitdead == "DeadIntermediateMaster" ]]; then
array=( ${eth_dev} "${mysql_vip}" root "${local_ip}")
interface=${array[0]}
IP=${array[3]}
user=${array[2]}
slavehost=`echo $5 | sed -E "s/:[0-9]+//g" | sed -E "s/,/ /g"`
showslave=`mysql -h$newmaster -u$mysqluser -sN -e "SHOW SLAVE HOSTS;" | awk '{print $2}'`
newintermediatemaster=`echo $slavehost $showslave | tr ' ' '\n' | sort | uniq -d`
echo $(date)
echo "Recovering from: $isitdead"
echo "New intermediate master is: $newintermediatemaster"
echo "/usr/local/orchestrator/orch_vip.sh -d 1 -n $newintermediatemaster -s ${sshoptions} -i ${interface} -I ${IP} -u ${user} -o $oldmaster" | tee $logfile
/usr/local/orchestrator/orch_vip.sh -d 1 -n $newintermediatemaster -s "${sshoptions}" -i ${interface} -I ${IP} -u ${user} -o $oldmaster
fi
EOFF

#2.添加可执行权限
chmod +x /usr/local/orchestrator/orch_hook.sh

#3.更改所属用户
chown -R orchestrator:orchestrator /usr/local/orchestrator/

第六步:编辑ORCH切换VIP脚本

重要操作

注意!所有ORCH机器都操作!

注意:orch_hook.sh 会调用 orch_vip.sh

#1.创建脚本
cat > /usr/local/orchestrator/orch_vip.sh << 'EOHFF'
#!/bin/bash

function usage {
cat << EOF
usage: $0 [-h] [-d master is dead] [-o old master] [-s ssh options] [-n new master] [-i interface] [-I] [-u SSH user]
OPTIONS:
-h Show this message
-o string Old master hostname or IP address
-d int If master is dead should be 1 otherwise it is 0
-s string SSH options
-n string New master hostname or IP address
-i string Interface example eth0:1
-I string Virtual IP
-u string SSH user
EOF
}

while getopts ho:d:s:n:i:I:u: flag; do
case $flag in
o)
orig_master="$OPTARG"
;;
d)
isitdead="$OPTARG"
;;
s)
ssh_options="$OPTARG"
;;
n)
new_master="$OPTARG"
;;
i)
interface="$OPTARG"
;;
I)
vip="$OPTARG"
;;
u)
ssh_user="$OPTARG"
;;
h)
usage
exit 0
;;
*)
usage
exit 1
;;
esac
done

echo "orig_master: $orig_master"
echo "isitdead: $isitdead"
echo "ssh_options: $ssh_options"
echo "new_master: $new_master"
echo "interface: $interface"
echo "vip: $vip"

if [ $OPTIND -eq 1 ]; then
echo "No options were passed"
usage
fi

shift $((OPTIND - 1))


# Discover commands from our path

ssh=$(which ssh)
arping=$(which arping)
ip2util=$(which ip)


# Command for adding our VIP

cmd_vip_add="sudo -n $ip2util address add ${vip} dev ${interface}"


# Command for deleting our VIP

cmd_vip_del="sudo -n $ip2util address del ${vip}/32 dev ${interface}"


# Command for discovering if our VIP is enabled

cmd_vip_chk="sudo -n $ip2util address show dev ${interface} to ${vip%/*}/32"


# Command for sending gratuitous ARP to announce IP move

cmd_arp_fix="sudo -n $arping -c 1 -I ${interface} ${vip%/*}"


# Command for sending gratuitous ARP to announce IP move on current server

cmd_local_arp_fix="sudo -n $arping -c 1 -I ${interface} ${vip%/*}"

function vip_stop() {
rc=0
# Ensure the VIP is removed
$ssh ${ssh_options} -tt ${ssh_user}@${orig_master} \
"[ -n \"\$(${cmd_vip_chk})\" ] && ${cmd_vip_del} && sudo ${ip2util} route flush cache || [ -z \"\$(${cmd_vip_chk})\" ]"
rc=$?
return $rc
}

function vip_start() {
rc=0
# Ensure the VIP is added
$ssh ${ssh_options} -tt ${ssh_user}@${new_master} \
"[ -z \"\$(${cmd_vip_chk})\" ] && ${cmd_vip_add} && ${cmd_arp_fix} || [ -n \"\$(${cmd_vip_chk})\" ]"
rc=$?
$cmd_local_arp_fix
return $rc
}

function vip_status() {
$arping -c 1 -I ${interface} ${vip%/*}
if ping -c 1 -W 1 "$vip"; then
return 0
else
return 1
fi
}

if [[ $isitdead == 0 ]]; then
echo "Online failover"
if vip_stop; then
if vip_start; then
echo "$vip is moved to $new_master."
else
echo "Can't add $vip on $new_master!"
exit 1
fi
else
echo "Can't remove the $vip from orig_master!"
exit 1
fi
elif [[ $isitdead == 1 ]]; then
echo "Master is dead, failover"
if vip_status; then
if vip_stop; then
echo "$vip is removed from orig_master."
else
echo "Couldn't remove $vip from orig_master."
exit 1
fi
fi
if vip_start; then
echo "$vip is moved to $new_master."
else
echo "Can't add $vip on $new_master!"
exit 1
fi
else
echo "Wrong argument, the master is dead or live?"
fi
EOHFF

#2.添加可执行权限
chmod +x /usr/local/orchestrator/orch_vip.sh

#3.更改所属用户
chown -R orchestrator:orchestrator /usr/local/orchestrator/

第七步:systemd配置Orchestrator启动文件

重要操作

注意!所有ORCH机器都操作!

cat > /etc/systemd/system/orchestrator.service << 'EOFF'
[Unit]
Description=orchestrator: MySQL replication management and visualization
Documentation=https://github.com/openark/orchestrator
After=syslog.target network.target mysqld.service mysql.service

[Service]
Type=simple
WorkingDirectory=/usr/local/orchestrator
ExecStart=/usr/local/orchestrator/orchestrator http
EnvironmentFile=-/etc/sysconfig/orchestrator
ExecReload=/bin/kill -HUP $MAINPID
LimitNOFILE=16384

[Install]
WantedBy=multi-user.target
EOFF

第八步:启动orchestrator

重要操作

注意!所有ORCH机器都操作!

systemctl daemon-reload
systemctl start orchestrator
systemctl enable orchestrator
netstat -lntup|grep 3000

3. 自动故障转移实战

ORCH管理命令

管理MySQL实例
前置条件

使用orchestrator-client命令行请先安装jq

[root@db-51 ~]# yum install jq -y
[root@db-51 ~]# orchestrator-client -c discover -i 10.0.0.51:3306
10.0.0.51:3306
打印指定集群的拓扑
# orchestrator-client -c topology -i 10.0.0.51:3306
[root@db-51 ~]# orchestrator-client -c topology -i 10.0.0.51:3306
10.0.0.51:3306 [0s,ok,5.7.28-log,rw,ROW,>>,GTID]
+ 10.0.0.52:3306 [0s,ok,5.7.28-log,ro,ROW,>>,GTID]
+ 10.0.0.53:3306 [0s,ok,5.7.28-log,ro,ROW,>>,GTID]

# orchestrator-client -c topology-tabulated -i 10.0.0.51:3306
[root@db-51 ~]# orchestrator-client -c topology-tabulated -i 10.0.0.51:3306
10.0.0.51:3306 |0s|ok|5.7.28-log|rw|ROW|>>,GTID
+ 10.0.0.52:3306|0s|ok|5.7.28-log|ro|ROW|>>,GTID
+ 10.0.0.53:3306|0s|ok|5.7.28-log,ro|ROW|>>,GTID
主库设置VIP
初始化操作

第一次运行的时候VIP需要手动创建

添加VIP:

ip address add 10.0.0.100 dev eth0

删除VIP:

ip address del 10.0.0.100 dev eth0
GTID错误事务处理

将错误的GTID事务当做空事务应用副本的主上:

orchestrator-client -c gtid-errant-inject-empty  -i 10.0.0.52:3306
orchestrator-client -c gtid-errant-inject-empty -i 10.0.0.53:3306
强制切换
orchestrator-client -c graceful-master-takeover -a 10.0.0.52:3306 -d 10.0.0.51:3306
orchestrator-client -c start-replica -i 10.0.0.52:3306
常见问题解决

报错信息:

[root@db-51 ~]# orchestrator-client -c discover -i 10.0.0.51:3306
MySQLHostnameResolveMethod configured to use @@report_host but 10.0.0.51:3306 has NULL/empty @@report_host

解决方案:

配置修改

在每个业务数据库的配置文件里添加以下参数,每台机器都不一样

report_host = 10.0.0.51
report_port = 3306

拓展知识:Raft选举算法

Raft 是一种用于管理和实现分布式系统中的一致性的算法。它是为了容易理解和实现而设计的,同时提供与 Paxos 等其他一致性算法相同的功能和保证。Raft 通过一系列的子协议来处理领导选举、日志复制、安全性和变更集群成员。

核心概念

Raft 将系统中的所有服务器划分为以下三种角色:

  1. Leader:负责接收客户端请求,将请求作为日志条目添加到本地日志,然后复制到其他服务器。当日志条目被安全复制后,leader 会将操作应用到其状态机并返回结果给客户端。
  2. Follower:被动地响应来自 leader 或候选者的请求。它们自身不发起任何请求。
  3. Candidate:用于领导选举的临时角色。
Raft 算法的关键步骤

1. 领导选举

  • 当服务器启动时,它们首先是 follower 状态。如果一个 follower 在一段时间内没有收到 leader 的消息,它会认为系统当前没有有效的 leader。
  • 这时,follower 转变为 candidate 并开始一次领导选举:增加当前的任期号(term),对自己投票,并向其他服务器发送请求投票的消息。
  • 收到大多数服务器的投票后,候选者变成 leader。
  • 如果候选者在选举过程中从当前 leader 接收到有效的日志条目,则重新变回 follower。

2. 日志复制

  • Leader 接收到客户端的请求后,会将该请求作为一个新的日志条目存储在本地日志中,然后尝试通过发送 AppendEntries 消息将这个日志条目复制到集群中的所有 follower。
  • 一旦日志条目被安全地复制(即被大多数服务器存储),leader 会将该条目应用到自己的状态机,并向客户端返回操作成功的响应。
  • 如果 follower 没有及时复制日志,leader 会不断重试,直到所有的 follower 都成功存储所有的日志条目。

3. 安全性

  • Raft 通过 “领导者完整性原则” 保证安全性,即领导者必须拥有所有已提交的日志条目。
  • 在选举过程中,candidate 必须向其他服务器展示其拥有的最新日志信息。如果其他服务器发现自己的日志比 candidate 的更新,它们将拒绝投票。

4. 成员变更

  • Raft 处理成员变更(即添加或删除服务器)的过程中,使用了一种被称为 “joint consensus”(联合一致性)的方法。在这种机制下,系统可以在变更过程中继续运行,同时保持一致性和可用性。
实现和应用

Raft 因其算法的清晰性和易于理解的特性而广泛应用于各种分布式系统中,如 etcd、Consul 和 Apache Ratis 等。这些系统利用 Raft 来管理配置信息、提供服务发现的一致性保证或作为分布式存储系统的一致性层。

ORCH配置解释

cat > /usr/local/orchestrator/orchestrator.conf.json << 'EOF'
{
"Debug": true, // 开启调试模式
"EnableSyslog": false, // 禁用Syslog记录
"ListenAddress": ":3000", // 监听地址和端口
"MySQLTopologyUser": "orchestrator", // MySQL拓扑用户
"MySQLTopologyPassword": "orchestrator", // MySQL拓扑密码
"MySQLTopologyCredentialsConfigFile": "", // MySQL拓扑凭证文件路径
"MySQLTopologySSLPrivateKeyFile": "", // MySQL拓扑SSL私钥文件
"MySQLTopologySSLCertFile": "", // MySQL拓扑SSL证书文件
"MySQLTopologySSLCAFile": "", // MySQL拓扑SSL CA证书文件
"MySQLTopologySSLSkipVerify": true, // 跳过MySQL拓扑SSL验证
"MySQLTopologyUseMutualTLS": false, // MySQL拓扑不使用双向TLS
"MySQLOrchestratorHost": "127.0.0.1", // Orchestator MySQL服务地址
"MySQLOrchestratorPort": 3307, // Orchestator MySQL服务端口
"MySQLOrchestratorDatabase": "orchestrator", // Orchestator数据库名称
"MySQLOrchestratorUser": "orchestrator", // Orchestator数据库用户
"MySQLOrchestratorPassword": "orchestrator", // Orchestator数据库密码
"MySQLOrchestratorCredentialsConfigFile": "", // Orchestator数据库凭证文件路径
"MySQLOrchestratorSSLPrivateKeyFile": "", // Orchestator SSL私钥文件
"MySQLOrchestratorSSLCertFile": "", // Orchestator SSL证书文件
"MySQLOrchestratorSSLCAFile": "", // Orchestator SSL CA证书文件
"MySQLOrchestratorSSLSkipVerify": true, // 跳过Orchestator SSL验证
"MySQLOrchestratorUseMutualTLS": false, // Orchestator不使用双向TLS
"MySQLConnectTimeoutSeconds": 1, // MySQL连接超时时间(秒)
"DefaultInstancePort": 3307, // 默认实例端口
"DiscoverByShowSlaveHosts": true, // 通过SHOW SLAVE HOSTS发现从服务器
"InstancePollSeconds": 5, // 实例轮询时间(秒)
"DiscoveryIgnoreReplicaHostnameFilters": [ // 忽略的复制主机名过滤器
"a_host_i_want_to_ignore[.]example[.]com",
".*[.]ignore_all_hosts_from_this_domain[.]example[.]com",
"a_host_with_extra_port_i_want_to_ignore[.]example[.]com:3307"
],
"UnseenInstanceForgetHours": 240, // 长时间未见实例的遗忘时间(小时)
"SnapshotTopologiesIntervalHours": 0, // 拓扑快照间隔时间(小时)
"InstanceBulkOperationsWaitTimeoutSeconds": 10, // 实例批量操作等待超时时间(秒)
"HostnameResolveMethod": "none", // 主机名解析方法
"MySQLHostnameResolveMethod": "@@report_host", // MySQL主机名解析方法
"SkipBinlogServerUnresolveCheck": true, // 跳过Binlog服务器解析检查
"ExpiryHostnameResolvesMinutes": 60, // 主机名解析过期时间(分钟)
"RejectHostnameResolvePattern": "", // 拒绝的主机名解析模式
"ReasonableReplicationLagSeconds": 10, // 合理的复制延迟时间(秒)
"ProblemIgnoreHostnameFilters": [], // 忽略的问题主机名过滤器
"VerifyReplicationFilters": false, // 验证复制过滤器
"ReasonableMaintenanceReplicationLagSeconds": 20, // 维护期间合理的复制延迟时间(秒)
"CandidateInstanceExpireMinutes": 60, // 候选实例过期时间(分钟)
"AuditLogFile": "", // 审计日志文件路径
"AuditToSyslog": false, // 审计记录到Syslog
"RemoveTextFromHostnameDisplay": ".mydomain.com:3307", // 从主机名显示中移除的文本
"ReadOnly": false, // 只读模式
"AuthenticationMethod": "", // 认证方法
"HTTPAuthUser": "admin", // HTTP认证用户
"HTTPAuthPassword": "Admin#123456", // HTTP认证密码
"AuthUserHeader": "", // 认证用户头
"PowerAuthUsers": [ // 权限认证用户
"*"
],
"ClusterNameToAlias": { // 集群名称到别名的映射
"127.0.0.1": "test suite"
},
"ReplicationLagQuery": "", // 复制延迟查询
"DetectClusterAliasQuery": "select replace(substr(@@hostname, 1, instr(@@hostname, 'mysql')-2), '-', '_')", // 检测集群别名查询
"DetectClusterDomainQuery": "", // 检测集群域名查询
"DetectInstanceAliasQuery": "", // 检测实例别名查询
"DetectPromotionRuleQuery": "", // 检测提升规则查询
"DataCenterPattern": "[.]([^.]+)[.][^.]+[.]mydomain[.]com", // 数据中心模式
"PhysicalEnvironmentPattern": "[.]([^.]+[.][^.]+)[.]mydomain[.]com", // 物理环境模式
"PromotionIgnoreHostnameFilters": [], // 提升忽略主机名过滤器
"DetectSemiSyncEnforcedQuery": "", // 检测半同步强制查询
"ServeAgentsHttp": false, // 服务代理HTTP
"AgentsServerPort": ":3001", // 代理服务器端口
"AgentsUseSSL": false, // 代理使用SSL
"AgentsUseMutualTLS": false, // 代理使用双向TLS
"AgentSSLSkipVerify": false, // 代理跳过SSL验证
"AgentSSLPrivateKeyFile": "", // 代理SSL私钥文件
"AgentSSLCertFile": "", // 代理SSL证书文件
"AgentSSLCAFile": "", // 代理SSL CA证书文件
"AgentSSLValidOUs": [], // 代理SSL有效的组织单位
"UseSSL": false, // 使用SSL
"UseMutualTLS": false, // 使用双向TLS
"SSLSkipVerify": false, // 跳过SSL验证
"SSLPrivateKeyFile": "", // SSL私钥文件
"SSLCertFile": "", // SSL证书文件
"SSLCAFile": "", // SSL CA证书文件
"SSLValidOUs": [], // SSL有效的组织单位
"URLPrefix": "", // URL前缀
"StatusEndpoint": "/api/status", // 状态端点
"StatusSimpleHealth": true, // 简单健康状态
"StatusOUVerify": false, // 状态OU验证
"AgentPollMinutes": 60, // 代理轮询时间(分钟)
"UnseenAgentForgetHours": 6, // 长时间未见代理的遗忘时间(小时)
"StaleSeedFailMinutes": 60, // 陈旧种子失败时间(分钟)
"SeedAcceptableBytesDiff": 8192, // 种子可接受的字节差异
"PseudoGTIDPattern": "", // 伪GTID模式
"PseudoGTIDPatternIsFixedSubstring": false, // 伪GTID模式是固定子字符串
"PseudoGTIDMonotonicHint": "asc:", // 伪GTID单调提示
"DetectPseudoGTIDQuery": "", // 检测伪GTID查询
"BinlogEventsChunkSize": 10000, // Binlog事件块大小
"SkipBinlogEventsContaining": [], // 跳过包含的Binlog事件
"ReduceReplicationAnalysisCount": true, // 减少复制分析次数
"FailureDetectionPeriodBlockMinutes": 1, // 失败检测阻塞时间(分钟)
"FailMasterPromotionOnLagMinutes": 0, // 延迟分钟数导致主升级失败
"RecoveryPeriodBlockSeconds": 60, // 恢复期阻塞时间(秒)
"RecoveryIgnoreHostnameFilters": [], // 恢复忽略主机名过滤器
"RecoverMasterClusterFilters": [ // 恢复主集群过滤器
"*"
],
"RecoverIntermediateMasterClusterFilters": [ // 恢复中间主集群过滤器
"*"
],
"OnFailureDetectionProcesses": [ // 失败检测过程
"echo 'Detected {failureType} on {failureCluster}. Affected replicas:{countSlaves}' >> /usr/local/orchestrator/log/recovery.log"
],
"PreGracefulTakeoverProcesses": [ // 优雅接管前过程
"echo 'Planned takeover about to take place on {failureCluster}. Master will switch to read_only' >> /usr/local/orchestrator/log/recovery.log"
],
"PreFailoverProcesses": [ // 故障转移前过程
"echo 'Will recover from {failureType} on {failureCluster}' >> /usr/local/orchestrator/log/recovery.log"
],
"PostFailoverProcesses": [ // 故障转移后过程
"echo 'Recovered from {failureType} on {failureCluster}. Failed: {failedHost}:{failedPort}; Successor: {successorHost}: {successorPort}; failureClusterAlias:{failureClusterAlias}' >> /usr/local/orchestrator/log/recovery.log",
"/usr/local/orchestrator/orch_hook.sh {failureType} {failureClusterAlias} {failedHost} {successorHost} >> /usr/local/orchestrator/log/recovery_orch_hook.log"
],
"PostUnsuccessfulFailoverProcesses": [], // 故障转移不成功后过程
"PostMasterFailoverProcesses": [ // 主故障转移后过程
"echo 'Recovered from {failureType} on {failureCluster}. Failed: {failedHost}:{failedPort}; Promoted: {successorHost}:{successorPort}' >> /usr/local/orchestrator/log/recovery.log"
],
"PostIntermediateMasterFailoverProcesses": [ // 中间主故障转移后过程
"echo 'Recovered from {failureType} on {failureCluster}. Failed: {failedHost}:{failedPort}; Successor: {successorHost}:{successorPort}' >> /usr/local/orchestrator/log/recovery.log"
],
"PostGracefulTakeoverProcesses": [ // 优雅接管后过程
"echo 'Planned takeover complete' >> /usr/local/orchestrator/log/recovery.log"
],
"CoMasterRecoveryMustPromoteOtherCoMaster": true, // 协同主恢复必须提升另一个协同主
"DetachLostSlavesAfterMasterFailover": true, // 主故障转移后分离丢失的从属
"ApplyMySQLPromotionAfterMasterFailover": true, // 主故障转移后应用MySQL提升
"PreventCrossDataCenterMasterFailover": false, // 防止跨数据中心主故障转移
"PreventCrossRegionMasterFailover": false, // 防止跨区域主故障转移
"FailMasterPromotionIfSQLThreadNotUpToDate": false, // 如果SQL线程不是最新的,则主提升失败
"DelayMasterPromotionIfSQLThreadNotUpToDate": true, // 如果SQL线程不是最新的,延迟主提升
"DetachLostReplicasAfterMasterFailover": true, // 主故障转移后分离丢失的复制品
"MasterFailoverDetachReplicaMasterHost": false, // 主故障转移分离复制主机
"MasterFailoverLostInstancesDowntimeMinutes": 0, // 主故障转移丢失实例的停机时间(分钟)
"PostponeReplicaRecoveryOnLagMinutes": 0, // 延迟复制恢复的分钟数
"OSCIgnoreHostnameFilters": [], // 忽略主机名过滤器的在线模式切换
"GraphiteAddr": "", // Graphite地址
"GraphitePath": "", // Graphite路径
"GraphiteConvertHostnameDotsToUnderscores": true, // Graphite将主机名中的点转换为下划线
"ConsulAddress": "", // Consul地址
"ConsulAclToken": "", // Consul访问控制列表令牌
"ConsulKVStoreProvider": "consul", // Consul键值存储提供者
"RaftEnabled": true, // 启用Raft协议
"BackendDB": "mysql", // 后端数据库
"RaftDataDir":"/usr/local/orchestrator", // Raft数据目录
"RaftBind":"10.0.0.51", // Raft绑定地址
"DefaultRaftPort":10008, // 默认Raft端口
"RaftNodes":[ // Raft节点
"10.0.0.51",
"10.0.0.52",
"10.0.0.53"
]
}
EOF

ORCH故障转移及修复

模拟故障流程

第一步:主库MySQL停掉

systemctl stop mysqld

第二步:观察ORCH状态和集群状态

[root@db-51 ~]# orchestrator-client -c topology -i 10.0.0.53:3306
10.0.0.53:3306 [0s,ok,5.7.28-log,rw,ROW,>>,GTID]
+ 10.0.0.52:3306 [0s,ok,5.7.28-log,ro,ROW,>>,GTID]
故障修复

第一步:查看当前最新的主库信息

[root@db-51 ~]# orchestrator-client -c topology -i 10.0.0.53:3306
10.0.0.53:3306 [0s,ok,5.7.28-log,rw,ROW,>>,GTID]
+ 10.0.0.52:3306 [0s,ok,5.7.28-log,ro,ROW,>>,GTID]

第二步:重新启动故障MySQL

systemctl restart mysqld

第三步:手动调整复制关系

mysql -uroot -p123
change master to
master_host='10.0.0.53',
master_user='repl',
master_password='123' ,
MASTER_AUTO_POSITION=1;
start slave;
show slave status\G
set global read_only=1;
set global super_read_only=on;

第四步:再次查看ORCH状态

[root@db-51 ~]# orchestrator-client -c topology -i 10.0.0.53:3306
10.0.0.53:3306 [0s,ok,5.7.28-log,rw,ROW,>>,GTID]
+ 10.0.0.51:3306 [0s,ok,5.7.28-log,ro,ROW,>>,GTID,downtimed]
+ 10.0.0.52:3306 [0s,ok,5.7.28-log,ro,ROW,>>,GTID]

[root@db-51 ~]# orchestrator-client -c topology -i 10.0.0.53:3306
10.0.0.53:3306 [0s,ok,5.7.28-log,rw,ROW,>>,GTID]
+ 10.0.0.51:3306 [0s,ok,5.7.28-log,ro,ROW,>>,GTID]
+ 10.0.0.52:3306 [0s,ok,5.7.28-log,ro,ROW,>>,GTID]
ORCH选举流程
选举机制详解

Orchestrator的故障转移和选举机制遵循以下流程:

1. 故障检测

Orchestrator 首先需要确定主服务器是否真的已经宕机。这通常是通过连续的健康检查失败来确认的。

2. 选举策略

一旦确定主服务器已经宕机,Orchestrator 将根据预先定义的策略和权重系统来选择新的主服务器。选举过程通常遵循以下准则:

  • 复制延迟:倾向选择复制延迟最小的服务器
  • 数据一致性:选择数据最新、与原主服务器同步最接近的服务器
  • 服务器状态:健康状态良好,没有硬件或网络问题的服务器更有可能被选为新主
  • 地理位置:在某些配置中,可能会考虑服务器的地理位置,以优化延迟或符合数据驻留要求
  • 配置和容量:选择具有足够资源(CPU、内存、存储空间)来处理主服务器负载的服务器

3. 自动故障转移

Orchestrator 将自动执行故障转移操作,这包括:

  • 晋升新主服务器:将选举出的候选服务器晋升为新的主服务器
  • 重新配置复制:更新其他从服务器的复制设置,使它们开始从新的主服务器复制数据
  • 虚拟IP和路由更改(如果适用):自动调整网络设置,确保流量被正确地重定向到新的主服务器

4. 钩子和自定义脚本

在故障转移过程中,Orchestrator 允许执行自定义脚本(如 orch_hook.shorch_vip.sh),这些脚本可以处理额外的自定义逻辑,例如通知、日志记录或进一步的网络配置调整。

5. 监控和日志

整个故障检测和转移过程都会被详细记录并可通过 Orchestrator 的界面进行监控。这确保了操作的透明性和可追溯性。

总结

通过这些机制,Orchestrator 能够确保 MySQL 集群在面对主服务器故障时能够迅速、有效地恢复,最大程度地减少服务中断时间并保持数据的完整性和一致性。

ORCH数据存储与raft选举

Orchestrator 使用的 MySQL 数据库配置项如下:

"MySQLOrchestratorHost": "127.0.0.1",
"MySQLOrchestratorPort": 3307,
"MySQLOrchestratorDatabase": "orchestrator",
"MySQLOrchestratorUser": "orchestrator",
"MySQLOrchestratorPassword": "orchestrator",

根据这些配置,Orchestrator 会连接到运行在本地(127.0.0.1)的 MySQL 实例,该实例监听在端口 3307 上,并访问名为 orchestrator 的数据库。用户是 orchestrator,密码也是 orchestrator

数据存储概述

  • 单节点配置:如果 Orchestrator 运行在单个节点上,它会将所有数据(包括集群的拓扑信息、历史记录和其他元数据)存储在指定的这个 MySQL 实例中。
  • 多节点配置:如果你的环境中配置了多个 Orchestrator 节点,例如为了高可用性和故障恢复,每个 Orchestrator 节点通常会配置自己的数据库实例。这是为了保证每个节点都能独立地访问和存储必要的数据,特别是在处理故障转移和数据库拓扑变化时。

Raft协议

你的配置中还提到了 Raft 协议,这是一种用于实现分布式系统的一致性的协议。在你的配置中,相关的设置如下:

"RaftEnabled": true,
"RaftDataDir": "/usr/local/orchestrator",
"RaftBind": "10.0.0.51",
"DefaultRaftPort": 10008,
"RaftNodes": [
"10.0.0.51",
"10.0.0.52",
"10.0.0.53"
]

启用 Raft 后,Orchestrator 的多个节点将通过 Raft 协议协同工作,以确保集群状态的一致性。这意味着,虽然每个节点可能都连接到自己的本地 MySQL 实例,但关键的集群状态和决策(如主服务器的选举和故障转移的记录)将通过所有节点共享的 Raft 协议来同步。

结论

是的,每个 Orchestrator 节点都将数据存储在各自配置的 MySQL 实例中,数据库名称为 orchestrator,端口为 3307。通过 Raft 协议,这些节点可以在保持各自数据库的同时,确保关键操作的一致性和集群状态的同步。这种架构提高了 Orchestrator 集群的鲁棒性和可靠性。

文档更新

最后更新时间:2025-01-27
对应章节:第21章 Orchestrator高可用方案