• Mysql orchestrator高可用


    一、什么是Orchestrator

    Orchestrator是一款开源,对MySQL复制提供高可用、拓扑的可视化管理工具,采用go语言编写,它能够主动发现当前拓扑结构和主从复制状态,支持MySQL主从复制拓扑关系的调整、支持MySQL主库故障自动切换(failover)、手动主从切换(switchover)等功能。

    Orchestrator后台依赖于MySQL或者SQLite存储元数据,能够提供Web界面展示MySQL集群的拓扑关系及实例状态,通过Web界面可更改MySQL实例的部分配置信息,同时也提供命令行和api接口,以便更加灵活的自动化运维管理。Orchestrator 对MySQL主库的故障切换分为自动切换和手动切换。手动切换又分为recover、force-master-failover、force-master-takeover以及graceful-master-takeover。

    相比于MHA,Orchestrator更加偏重于复制拓扑关系的管理,能够实现MySQL任一复制拓扑关系的调整,并在此基础上,实现MySQL高可用。另外,Orchestrator自身也可以部署多个节点,通过raft分布式一致性协议,保证自身的高可用。

    二、Orchestrator搭建

    1、材料准备

    主机hostname备注
    192.168.88.129mysql_orch安装Orchestrator环境
    192.168.88.130mysql00主库mysql8.0
    192.168.88.131mysql01从库库mysql8.0
    192.168.88.132mysql02从库库mysql8.0

    a.修改hostname

    vim /etc/sysconfig/network
    hostname=mysql00

    b.在每台机器上面配置

    echo '192.168.88.129 mysql_orch' >> /etc/hosts
    echo '192.168.88.130 mysql00' >> /etc/hosts
    echo '192.168.88.131 mysql01' >> /etc/hosts
    echo '192.168.88.132 mysql02' >> /etc/hosts

    c.每台主机做免登录

    ssh-keygen -t rsa ##enter键执行3次
    ssh-copy-id -i ~/.ssh/id_rsa.pub mysql_orch
    ssh-copy-id -i ~/.ssh/id_rsa.pub mysql00  ##含义是对192.168.88.130登录做免密
    ssh-copy-id -i ~/.ssh/id_rsa.pub mysql01  ##含义是对192.168.88.131登录做免密
    ssh-copy-id -i ~/.ssh/id_rsa.pub mysql02  ##含义是对192.168.88.132登录做免密

    d.关闭每台电脑的防火墙

    2、 搭建主从环境

    主从环境就略过了,需要开启gtid,半同步增强复制。

    在192.168.88.129的mysql上面创建Orchestrator账户,用于Orchestrator存储高可用架构的信息。还需要创建一个数据库

    1. CREATE DATABASE IF NOT EXISTS orchestrator;
    2. create user 'orchestrator'@'%' identified by '123456';
    3. GRANT ALL PRIVILEGES ON `orchestrator`.* TO 'orchestrator'@'%';

    在192.168.88.130、192.168.88.131、192.168.88.132的mysql创建Orchestrator账户,用于Orchestrator,抓取各个mysql的信息,主从结构、切换mysql主从等。

    1. create user 'orchestrator'@'%' identified by '123456';
    2. GRANT SUPER, PROCESS, REPLICATION SLAVE, RELOAD ON *.* TO 'orchestrator'@'%';
    3. GRANT SELECT ON mysql.slave_master_info TO 'orchestrator'@'%';

    这里需要在每台mysql中创建Orchestrator账户,

    3、  安装Orchestrator

    a. 下载Orchestrator 

    GitHub - openark/orchestrator: MySQL replication topology management and HA

     orchestrator-3.2.6-1.x86_64.rpm

    b. 安装orchestrator-3.2.6-1.x86_64.rpm

    yum localinstall orchestrator-3.2.6-1.x86_64.rpm 即可,有需要的依赖包,安装即可。

    c. orchestrator 配置文件配置

    yum安装orchestrator后,安装路径在/usr/local/orchestrator目录

    复制一份配置文件orchestrator.conf.json

     cp orchestrator-sample.conf.json orchestrator.conf.json

    orchestrator.conf.json文件是一个json文件,主要配置以下参数

    1. {
    2. "Debug": true,
    3. "EnableSyslog": false,
    4. "ListenAddress": ":3000",
    5. "MySQLTopologyUser": "orchestrator",
    6. "MySQLTopologyPassword": "123456",
    7. "MySQLTopologyCredentialsConfigFile": "",
    8. "MySQLTopologySSLPrivateKeyFile": "",
    9. "MySQLTopologySSLCertFile": "",
    10. "MySQLTopologySSLCAFile": "",
    11. "MySQLTopologySSLSkipVerify": true,
    12. "MySQLTopologyUseMutualTLS": false,
    13. "MySQLOrchestratorHost": "192.168.88.129",
    14. "MySQLOrchestratorPort": 3306,
    15. "MySQLOrchestratorDatabase": "orchestrator",
    16. "MySQLOrchestratorUser": "orche",
    17. "MySQLOrchestratorPassword": "123456",
    18. "MySQLOrchestratorCredentialsConfigFile": "",
    19. "MySQLOrchestratorSSLPrivateKeyFile": "",
    20. "MySQLOrchestratorSSLCertFile": "",
    21. "MySQLOrchestratorSSLCAFile": "",
    22. "MySQLOrchestratorSSLSkipVerify": true,
    23. "MySQLOrchestratorUseMutualTLS": false,
    24. "MySQLConnectTimeoutSeconds": 1,
    25. "DefaultInstancePort": 3306,
    26. "DiscoverByShowSlaveHosts": true,
    27. "InstancePollSeconds": 5,
    28. "DiscoveryIgnoreReplicaHostnameFilters": [
    29. "a_host_i_want_to_ignore[.]example[.]com",
    30. ".*[.]ignore_all_hosts_from_this_domain[.]example[.]com",
    31. "a_host_with_extra_port_i_want_to_ignore[.]example[.]com:3307"
    32. ],
    33. "UnseenInstanceForgetHours": 240,
    34. "SnapshotTopologiesIntervalHours": 0,
    35. "InstanceBulkOperationsWaitTimeoutSeconds": 10,
    36. "HostnameResolveMethod": "default",
    37. "MySQLHostnameResolveMethod": "@@hostname",
    38. "SkipBinlogServerUnresolveCheck": true,
    39. "ExpiryHostnameResolvesMinutes": 60,
    40. "RejectHostnameResolvePattern": "",
    41. "ReasonableReplicationLagSeconds": 10,
    42. "ProblemIgnoreHostnameFilters": [],
    43. "VerifyReplicationFilters": false,
    44. "ReasonableMaintenanceReplicationLagSeconds": 20,
    45. "CandidateInstanceExpireMinutes": 60,
    46. "AuditLogFile": "",
    47. "AuditToSyslog": false,
    48. "RemoveTextFromHostnameDisplay": ".mydomain.com:3306",
    49. "ReadOnly": false,
    50. "AuthenticationMethod": "",
    51. "HTTPAuthUser": "",
    52. "HTTPAuthPassword": "",
    53. "AuthUserHeader": "",
    54. "PowerAuthUsers": [
    55. "*"
    56. ],
    57. "ClusterNameToAlias": {
    58. "127.0.0.1": "test suite"
    59. },
    60. "ReplicationLagQuery": "",
    61. "DetectClusterAliasQuery": "SELECT SUBSTRING_INDEX(@@hostname, '.', 1)",
    62. "DetectClusterDomainQuery": "",
    63. "DetectInstanceAliasQuery": "",
    64. "DetectPromotionRuleQuery": "",
    65. "DataCenterPattern": "[.]([^.]+)[.][^.]+[.]mydomain[.]com",
    66. "PhysicalEnvironmentPattern": "[.]([^.]+[.][^.]+)[.]mydomain[.]com",
    67. "PromotionIgnoreHostnameFilters": [],
    68. "DetectSemiSyncEnforcedQuery": "",
    69. "ServeAgentsHttp": false,
    70. "AgentsServerPort": ":3001",
    71. "AgentsUseSSL": false,
    72. "AgentsUseMutualTLS": false,
    73. "AgentSSLSkipVerify": false,
    74. "AgentSSLPrivateKeyFile": "",
    75. "AgentSSLCertFile": "",
    76. "AgentSSLCAFile": "",
    77. "AgentSSLValidOUs": [],
    78. "UseSSL": false,
    79. "UseMutualTLS": false,
    80. "SSLSkipVerify": false,
    81. "SSLPrivateKeyFile": "",
    82. "SSLCertFile": "",
    83. "SSLCAFile": "",
    84. "SSLValidOUs": [],
    85. "URLPrefix": "",
    86. "StatusEndpoint": "/api/status",
    87. "StatusSimpleHealth": true,
    88. "StatusOUVerify": false,
    89. "AgentPollMinutes": 60,
    90. "UnseenAgentForgetHours": 6,
    91. "StaleSeedFailMinutes": 60,
    92. "SeedAcceptableBytesDiff": 8192,
    93. "PseudoGTIDPattern": "",
    94. "PseudoGTIDPatternIsFixedSubstring": false,
    95. "PseudoGTIDMonotonicHint": "asc:",
    96. "DetectPseudoGTIDQuery": "",
    97. "BinlogEventsChunkSize": 10000,
    98. "SkipBinlogEventsContaining": [],
    99. "ReduceReplicationAnalysisCount": true,
    100. "FailureDetectionPeriodBlockMinutes": 1,
    101. "FailMasterPromotionOnLagMinutes": 0,
    102. "RecoveryPeriodBlockSeconds": 30,
    103. "RecoveryIgnoreHostnameFilters": [],
    104. "RecoverMasterClusterFilters": [
    105. "*"
    106. ],
    107. "RecoverIntermediateMasterClusterFilters": [
    108. "*"
    109. ],
    110. "OnFailureDetectionProcesses": [
    111. "echo 'Detected {failureType} on {failureCluster}. Affected replicas: {countSlaves}' >> /tmp/recovery.log"
    112. ],
    113. "PreGracefulTakeoverProcesses": [
    114. "echo 'Planned takeover about to take place on {failureCluster}. Master will switch to read_only' >> /tmp/recovery.log"
    115. ],
    116. "PreFailoverProcesses": [
    117. "echo 'Will recover from {failureType} on {failureCluster}' >> /tmp/recovery.log"
    118. ],
    119. "PostFailoverProcesses": [
    120. "echo '(for all types) Recovered from {failureType} on {failureCluster}. Failed: {failedHost}:{failedPort}; Successor: {successorHost}:{successorPort}{failureClusterAlias}' >> /tmp/recovery.log", "/home/orch/orch_hook.sh {failureType} {failureClusterAlias} {failedHost} {successorHost} >> /tmp/orch.log"
    121. ],
    122. "PostUnsuccessfulFailoverProcesses": [],
    123. "PostMasterFailoverProcesses": [
    124. "echo 'Recovered from {failureType} on {failureCluster}. Failed: {failedHost}:{failedPort}; Promoted: {successorHost}:{successorPort}' >> /tmp/recovery.log"
    125. ],
    126. "PostIntermediateMasterFailoverProcesses": [
    127. "echo 'Recovered from {failureType} on {failureCluster}. Failed: {failedHost}:{failedPort}; Successor: {successorHost}:{successorPort}' >> /tmp/recovery.log"
    128. ],
    129. "PostGracefulTakeoverProcesses": [
    130. "echo 'Planned takeover complete' >> /tmp/recovery.log"
    131. ],
    132. "CoMasterRecoveryMustPromoteOtherCoMaster": true,
    133. "DetachLostSlavesAfterMasterFailover": true,
    134. "ApplyMySQLPromotionAfterMasterFailover": true,
    135. "PreventCrossDataCenterMasterFailover": false,
    136. "PreventCrossRegionMasterFailover": false,
    137. "MasterFailoverDetachReplicaMasterHost": false,
    138. "MasterFailoverLostInstancesDowntimeMinutes": 0,
    139. "PostponeReplicaRecoveryOnLagMinutes": 0,
    140. "OSCIgnoreHostnameFilters": [],
    141. "GraphiteAddr": "",
    142. "GraphitePath": "",
    143. "GraphiteConvertHostnameDotsToUnderscores": true,
    144. "ConsulAddress": "",
    145. "ConsulAclToken": "",
    146. "ConsulKVStoreProvider": "consul"
    147. }

    配置修改:

    MySQLTopologyUser 和 MySQLTopologyPassword

    表示的是192.168.88.130、192.168.88.131、192.168.88.132上面的mysql账户

    "MySQLOrchestratorHost": "192.168.88.129",
    "MySQLOrchestratorPort": 3306,
    "MySQLOrchestratorDatabase": "orchestrator",
    "MySQLOrchestratorUser": "orche",
    "MySQLOrchestratorPassword": "123456",

    上面的参数对应的是192.168.88.129对应的存储Orchestrator信息的数据库,这里一定要理解清楚,很容易搞混淆。

    RecoverMasterClusterFilters
    RecoverIntermediateMasterClusterFilters

    两个参数建议都配置 * ,不然后面多次切换主从的时候,第二次不会成功

    RecoveryPeriodBlockSeconds 3600 ##已经出故障后切换 3600s 后才能切换下一次
    FailureDetectionPeriodBlockMinutes 1 在该时间内再次出现故障,不会被多次发现

    如果在测试的环境把这两个值调小一点,不然多次切换主从会有问题

    d. 启动orchestrator

    在/usr/local/orchestrator 目录下执行

    nohup ./orchestrator --debug http > orc.log 2>&1 &

    f. 进入orchestrator web页面

    http://192.168.88.129:3000/

     可以在discover中添加我们的mysql主从集群,在hostname中输入主库192.168.88.130,点击submit按钮即可,

    如果能连接上就有下面的拓扑结构图

    三、其他相关问题

    1. 测试自动切换主从

    可以把192.168.88.130的mysql关闭后,刷新Orchestrator就可以看到,Orchestrator会自动选主。

    2.  orchestrator 是怎么检测主库挂掉的

    a.orch会先检测主库,如果联系不上主库
    b.判断能连接上的所有从库是否能联系上主库,如果a和b都不行,则判断主库已经挂掉了

    orch检测主库宕机依赖从库的IO线程(本身连不上主库后,还会通过从库再去检测主库是否异常),所以默认change搭建的主从感知主库宕机的等待时间过长,需要需要稍微改下

    change master to master_host='192.168.163.131',master_port=3307,master_user='rep',master_password='rep',master_auto_position=1,MASTER_HEARTBEAT_PERIOD=2,MASTER_CONNECT_RETRY=1, MASTER_RETRY_COUNT=86400;

    set global slave_net_timeout=8;##判断slave是否与主机断掉了,超时时间

    slave_net_timeout 表示slave在slave_net_timeout时间之内没有收到master的任何数据(包括binlog,heartbeat),slave认为连接断开,需要重连。默认值60s。


    MASTER_HEARTBEAT_PERIOD 表示心跳的周期。当MASTER_HEARTBEAT_PERIOD时间之内,master没有binlog event发送给slave的时候,就会发送心跳数据给slave

    MASTER_CONNECT_RETRY
    slave_net_timeout超时后,立刻重连,后续重连的时间间隔由 CHANGE MASTER TO 命令的MASTER_CONNECT_RETRY 参数指定。默认值60s。

    MASTER_RETRY_COUNT 限制重连次数

    3. orchestrator 是如何选主的

     考虑从库执行的位置点、数据中心、版本的兼容、binlog格式、是否满足相应的参数、promotion_rule规则的判定等等,来寻找一个符合设定条件的候选节点并尝试提升其为新的主库,从而完成自动故障恢复
    默认会选Executed_Gtid_Set最大的,数据最全的

    4.  是否会有丢失数据的风险

    有一些原因确实有丢失数据,造成主从不一致,因为orch不会主动的去补数据。所以一定要使用gtid和半同步增加复制。

    5. 从库升级主库后,old主库怎么处理

    检查old主库和new主库的数据有没有不同,然后change master to执行就好了

    change master to master_host='192.168.88.130', master_port=3306, master_user='repl', master_password='123456', master_auto_position=1, MASTER_HEARTBEAT_PERIOD=2,MASTER_CONNECT_RETRY=1, MASTER_RETRY_COUNT=86400;

    6. vip怎么漂移

    Orchestrator中配置钩子,在orchestrator.conf.json配置文件中,添加

     逻辑就是:在PostFailoverProcesses配置中添加一个shell脚本,orchestrator主从切换成功以后就会执行这个脚本。上面也可以配置不同的钩子,在orchestrator不同状态下执行对于的脚本。这里只讲vip相关的。

    "/home/orch/orch_hook.sh {failureType} {failureClusterAlias} {failedHost} {successorHost} >> /tmp/orch.log"

    有问题可以看上面的配置文件,里面直接复制

    a、所以我们的shell脚本就在 /home/orch/orch_hook.sh 中

    1. #!/bin/bash
    2. isitdead=$1
    3. cluster=$2
    4. oldmaster=$3
    5. newmaster=$4
    6. mysqluser="orchestrator"
    7. export MYSQL_PWD="123456"
    8. logfile="/var/log/orch_hook.log"
    9. # list of clusternames
    10. #clusternames=(rep blea lajos)
    11. # clustername=( interface IP user Inter_IP)
    12. #rep=( ens32 "192.168.56.121" root "192.168.56.125")
    13. if [[ $isitdead == "DeadMaster" ]]; then
    14. array=( ens33 "192.168.88.200" root "192.168.88.129")
    15. interface=${array[0]}
    16. IP=${array[1]}
    17. user=${array[2]}
    18. if [ ! -z ${IP} ] ; then
    19. echo $(date)
    20. echo "Revocering from: $isitdead"
    21. echo "New master is: $newmaster"
    22. echo "/usr/local/orchestrator/orch_vip.sh -d 1 -n $newmaster -i ${interface} -I ${IP} -u ${user} -o $oldmaster" | tee $logfile
    23. /usr/local/orchestrator/orch_vip.sh -d 1 -n $newmaster -i ${interface} -I ${IP} -u ${user} -o $oldmaster
    24. #mysql -h$newmaster -u$mysqluser < /usr/local/bin/orch_event.sql
    25. else
    26. echo "Cluster does not exist!" | tee $logfile
    27. fi
    28. elif [[ $isitdead == "DeadIntermediateMasterWithSingleSlaveFailingToConnect" ]]; then
    29. array=( ens33 "192.168.88.200" root "192.168.88.129")
    30. interface=${array[0]}
    31. IP=${array[1]}
    32. user=${array[2]}
    33. slavehost=`echo $5 | cut -d":" -f1`
    34. echo $(date)
    35. echo "Revocering from: $isitdead"
    36. echo "New intermediate master is: $slavehost"
    37. echo "/usr/local/orchestrator/orch_vip.sh -d 1 -n $slavehost -i ${interface} -I ${IP} -u ${user} -o $oldmaster" | tee $logfile
    38. /usr/local/orchestrator/orch_vip.sh -d 1 -n $slavehost -i ${interface} -I ${IP} -u ${user} -o $oldmaster
    39. elif [[ $isitdead == "DeadIntermediateMaster" ]]; then
    40. array=( ens33 "192.168.88.200" root "192.168.88.129")
    41. interface=${array[0]}
    42. IP=${array[3]}
    43. user=${array[2]}
    44. slavehost=`echo $5 | sed -E "s/:[0-9]+//g" | sed -E "s/,/ /g"`
    45. showslave=`mysql -h$newmaster -u$mysqluser -sN -e "SHOW SLAVE HOSTS;" | awk '{print $2}'`
    46. newintermediatemaster=`echo $slavehost $showslave | tr ' ' '\n' | sort | uniq -d`
    47. echo $(date)
    48. echo "Revocering from: $isitdead"
    49. echo "New intermediate master is: $newintermediatemaster"
    50. echo "/usr/local/orchestrator/orch_vip.sh -d 1 -n $newintermediatemaster -i ${interface} -I ${IP} -u ${user} -o $oldmaster" | tee $logfile
    51. /usr/local/orchestrator/orch_vip.sh -d 1 -n $newintermediatemaster -i ${interface} -I ${IP} -u ${user} -o $oldmaster
    52. fi

    上面的脚本需要修改的地方 array=( ens33 "192.168.88.200" root "192.168.88.129")

    ens33表示网卡,填自己的电脑上面的

    192.168.88.200 表示vip地址

    192.168.88.129 表示orchestrator安装的ip

    root 表示免登录的linux账户

    b、/usr/local/orchestrator/orch_vip.sh 漂移脚本

    1. #!/bin/bash
    2. isitdead=$1
    3. cluster=$2
    4. oldmaster=$3
    5. newmaster=$4
    6. mysqluser="orchestrator"
    7. export MYSQL_PWD="123456"
    8. logfile="/var/log/orch_hook.log"
    9. # list of clusternames
    10. #clusternames=(rep blea lajos)
    11. # clustername=( interface IP user Inter_IP)
    12. #rep=( ens32 "192.168.56.121" root "192.168.56.125")
    13. if [[ $isitdead == "DeadMaster" ]]; then
    14. array=( ens33 "192.168.88.200" root "192.168.88.129")
    15. interface=${array[0]}
    16. IP=${array[1]}
    17. user=${array[2]}
    18. if [ ! -z ${IP} ] ; then
    19. echo $(date)
    20. echo "Revocering from: $isitdead"
    21. echo "New master is: $newmaster"
    22. echo "/usr/local/orchestrator/orch_vip.sh -d 1 -n $newmaster -i ${interface} -I ${IP} -u ${user} -o $oldmaster" | tee $logfile
    23. /usr/local/orchestrator/orch_vip.sh -d 1 -n $newmaster -i ${interface} -I ${IP} -u ${user} -o $oldmaster
    24. #mysql -h$newmaster -u$mysqluser < /usr/local/bin/orch_event.sql
    25. else
    26. echo "Cluster does not exist!" | tee $logfile
    27. fi
    28. elif [[ $isitdead == "DeadIntermediateMasterWithSingleSlaveFailingToConnect" ]]; then
    29. array=( ens33 "192.168.88.200" root "192.168.88.129")
    30. interface=${array[0]}
    31. IP=${array[1]}
    32. user=${array[2]}
    33. slavehost=`echo $5 | cut -d":" -f1`
    34. echo $(date)
    35. echo "Revocering from: $isitdead"
    36. echo "New intermediate master is: $slavehost"
    37. echo "/usr/local/orchestrator/orch_vip.sh -d 1 -n $slavehost -i ${interface} -I ${IP} -u ${user} -o $oldmaster" | tee $logfile
    38. /usr/local/orchestrator/orch_vip.sh -d 1 -n $slavehost -i ${interface} -I ${IP} -u ${user} -o $oldmaster
    39. elif [[ $isitdead == "DeadIntermediateMaster" ]]; then
    40. array=( ens33 "192.168.88.200" root "192.168.88.129")
    41. interface=${array[0]}
    42. IP=${array[3]}
    43. user=${array[2]}
    44. slavehost=`echo $5 | sed -E "s/:[0-9]+//g" | sed -E "s/,/ /g"`
    45. showslave=`mysql -h$newmaster -u$mysqluser -sN -e "SHOW SLAVE HOSTS;" | awk '{print $2}'`
    46. newintermediatemaster=`echo $slavehost $showslave | tr ' ' '\n' | sort | uniq -d`
    47. echo $(date)
    48. echo "Revocering from: $isitdead"
    49. echo "New intermediate master is: $newintermediatemaster"
    50. echo "/usr/local/orchestrator/orch_vip.sh -d 1 -n $newintermediatemaster -i ${interface} -I ${IP} -u ${user} -o $oldmaster" | tee $logfile
    51. /usr/local/orchestrator/orch_vip.sh -d 1 -n $newintermediatemaster -i ${interface} -I ${IP} -u ${user} -o $oldmaster
    52. fi
    53. [root@localhost orchestrator]# cat /usr/local/orchestrator/orch_vip.sh
    54. #!/bin/bash
    55. emailaddress="email@example.com"
    56. sendmail=0
    57. function usage {
    58. cat << EOF
    59. usage: $0 [-h] [-d master is dead] [-o old master ] [-s ssh options] [-n new master] [-i interface] [-I] [-u SSH user]
    60. OPTIONS:
    61. -h Show this message
    62. -o string Old master hostname or IP address
    63. -d int If master is dead should be 1 otherweise it is 0
    64. -s string SSH options
    65. -n string New master hostname or IP address
    66. -i string Interface exmple eth0:1
    67. -I string Virtual IP
    68. -u string SSH user
    69. EOF
    70. }
    71. while getopts ho:d:s:n:i:I:u: flag; do
    72. case $flag in
    73. o)
    74. orig_master="$OPTARG";
    75. ;;
    76. d)
    77. isitdead="${OPTARG}";
    78. ;;
    79. s)
    80. ssh_options="${OPTARG}";
    81. ;;
    82. n)
    83. new_master="$OPTARG";
    84. ;;
    85. i)
    86. interface="$OPTARG";
    87. ;;
    88. I)
    89. vip="$OPTARG";
    90. ;;
    91. u)
    92. ssh_user="$OPTARG";
    93. ;;
    94. h)
    95. usage;
    96. exit 0;
    97. ;;
    98. *)
    99. usage;
    100. exit 1;
    101. ;;
    102. esac
    103. done
    104. if [ $OPTIND -eq 1 ]; then
    105. echo "No options were passed";
    106. usage;
    107. fi
    108. shift $(( OPTIND - 1 ));
    109. # discover commands from our path
    110. ssh=$(which ssh)
    111. arping=$(which arping)
    112. ip2util=$(which ip)
    113. # command for adding our vip
    114. cmd_vip_add="sudo -n $ip2util address add ${vip} dev ${interface}"
    115. # command for deleting our vip
    116. cmd_vip_del="sudo -n $ip2util address del ${vip}/32 dev ${interface}"
    117. # command for discovering if our vip is enabled
    118. cmd_vip_chk="sudo -n $ip2util address show dev ${interface} to ${vip%/*}/32"
    119. # command for sending gratuitous arp to announce ip move
    120. cmd_arp_fix="sudo -n $arping -c 1 -I ${interface} ${vip%/*} "
    121. # command for sending gratuitous arp to announce ip move on current server
    122. cmd_local_arp_fix="sudo -n $arping -c 1 -I ${interface} ${vip%/*} "
    123. vip_stop() {
    124. rc=0
    125. # ensure the vip is removed
    126. $ssh ${ssh_options} -tt ${ssh_user}@${orig_master} \
    127. "[ -n \"\$(${cmd_vip_chk})\" ] && ${cmd_vip_del} && sudo ${ip2util} route flush cache || [ -z \"\$(${cmd_vip_chk})\" ]"
    128. rc=$?
    129. return $rc
    130. }
    131. vip_start() {
    132. rc=0
    133. # ensure the vip is added
    134. # this command should exit with failure if we are unable to add the vip
    135. # if the vip already exists always exit 0 (whether or not we added it)
    136. $ssh ${ssh_options} -tt ${ssh_user}@${new_master} \
    137. "[ -z \"\$(${cmd_vip_chk})\" ] && ${cmd_vip_add} && ${cmd_arp_fix} || [ -n \"\$(${cmd_vip_chk})\" ]"
    138. rc=$?
    139. $cmd_local_arp_fix
    140. return $rc
    141. }
    142. vip_status() {
    143. $arping -c 1 -I ${interface} ${vip%/*}
    144. if ping -c 1 -W 1 "$vip"; then
    145. return 0
    146. else
    147. return 1
    148. fi
    149. }
    150. if [[ $isitdead == 0 ]]; then
    151. echo "Online failover"
    152. if vip_stop; then
    153. if vip_start; then
    154. echo "$vip is moved to $new_master."
    155. if [ $sendmail -eq 1 ]; then mail -s "$vip is moved to $new_master." "$emailaddress" < /dev/null &> /dev/null ; fi
    156. else
    157. echo "Can't add $vip on $new_master!"
    158. if [ $sendmail -eq 1 ]; then mail -s "Can't add $vip on $new_master!" "$emailaddress" < /dev/null &> /dev/null ; fi
    159. exit 1
    160. fi
    161. else
    162. echo $rc
    163. echo "Can't remove the $vip from orig_master!"
    164. if [ $sendmail -eq 1 ]; then mail -s "Can't remove the $vip from orig_master!" "$emailaddress" < /dev/null &> /dev/null ; fi
    165. exit 1
    166. fi
    167. elif [[ $isitdead == 1 ]]; then
    168. echo "Master is dead, failover"
    169. # make sure the vip is not available
    170. if vip_status; then
    171. if vip_stop; then
    172. if [ $sendmail -eq 1 ]; then mail -s "$vip is removed from orig_master." "$emailaddress" < /dev/null &> /dev/null ; fi
    173. else
    174. if [ $sendmail -eq 1 ]; then mail -s "Couldn't remove $vip from orig_master." "$emailaddress" < /dev/null &> /dev/null ; fi
    175. exit 1
    176. fi
    177. fi
    178. if vip_start; then
    179. echo "$vip is moved to $new_master."
    180. if [ $sendmail -eq 1 ]; then mail -s "$vip is moved to $new_master." "$emailaddress" < /dev/null &> /dev/null ; fi
    181. else
    182. echo "Can't add $vip on $new_master!"
    183. if [ $sendmail -eq 1 ]; then mail -s "Can't add $vip on $new_master!" "$emailaddress" < /dev/null &> /dev/null ; fi
    184. exit 1
    185. fi
    186. else
    187. echo "Wrong argument, the master is dead or live?"
    188. fi

    上面两个文件记得权限和可执行的问题。

    c.测试漂移

    在主库添加vip
    ip addr add 192.168.88.200 dev ens33

    然后关闭主库的mysql,看看主从切换后,vip地址是否也切换

    上面如果有问题的日志可以看

    /var/log/orch_hook.log

    /tmp/recovery.log

    细节:一定要配置免登录,否则不可能成功,orch_vip.sh这个脚本需要到新的主库linux上面去绑定vip的

    四、参考博文

    感谢下面的大佬的资料,感谢感谢!

    ##这个文章是真的不错
    https://www.cnblogs.com/chasetimeyang/p/15063858.html
    https://www.cnblogs.com/dh17/articles/14790321.html

    ##这个问题很不错啊
    https://blog.csdn.net/baijiu1/article/details/89395654

    https://blog.csdn.net/du18020126395/article/details/115289099
    https://www.cnblogs.com/zhoujinyi/p/10394389.html

    ##写的不错
    https://www.cnblogs.com/chasetimeyang/p/15063858.html

  • 相关阅读:
    volatile关键字详解
    SpringCloudStream+Rocket事务消息配置
    [python] 基于blind-watermark库添加图片盲水印
    tiup dm scale-in
    OFDM 十六讲 4 -What is a Cyclic Prefix in OFDM
    非常有用的JavaScript高阶面试技巧!
    FreeROTS 任务通知和实操 详解
    连续10年霸榜第一?程序员「最常用」的编程语言是它?
    Leetcode 1687. 从仓库到码头运输箱子 [四种解法] 动态规划 & 从朴素出发详细剖析优化步骤
    文字转语音朗读如何操作?手把手教你如何将文字转语音
  • 原文地址:https://blog.csdn.net/u010648194/article/details/126039337