暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL高可用复制管理工具 —— Orchestrator调研

学徒杨新建 2022-05-08
4123

Orchestrator简介

Orchestrator是一个MySQL高可用性和复制管理工具,作为服务运行并提供命令行访问、HTTP API和Web界面。 
Orchestrator可以主动发现当前的拓扑结构和主从复制状态,支持MySQL主从复制拓扑关系的调整、支持MySQL主库故障自动切换(failover)、手动主从切换(switchover)等功能。 
Orchestrator自身也可以部署多个节点,通过raft分布式一致性协议,保证自身的高可用。

Orchestrator支持

1.检测和审查复制集群,可以主动发现当前的拓扑结构和主从复制状态,读取基本的MySQL信息如复制状态和配置。 
2.安全拓扑重构:转移服务于另外一台计算机的系统拓扑,orchestrator了解复制规则,可以解析binlog文件中的position、GTID、Pseudo GTID、binlog服务器 
整洁的拓扑可视化 
复制问题可视化 
通过简单的拖拽修改拓扑 
3.故障修复,根据拓扑信息,可以识别各种故障,根据配置可以执行自动恢复。

Orchestrator原理

探测机制

Orchestrator默认每隔5秒(可以通过参数设置)去被监控的MySQL实例上拉取实例的状态,并将实例的状态信息存储至Orchestrator的后端元数据库,然后Orchestrator默认每隔5秒从元数据库中获取每个MySQL实例的状态,展示在Web界面。

故障检测

Orchestrator很好地利用了集群实例间的复制关系,不仅会探测主库,也会对从库进行探测,实际情况下,如果所有从库都联系不上主库,说明集群的复制关系已经被损坏,我们是有理由进行故障切换的。 
在同时满足以下两个条件的前提下,Orchestrator才会判定主库故障: 
1.联系主库失败。 
2.可以联系到主库对应的从库,并且这些从库联系主库也失败。

选主过程

Orchestrator判定主库故障后会进入选新主库的阶段,整个阶段大致会经历: 
故障发现-对所有主库副本进行排序-选择新主库-对其余主库副本进行划分-重新拓扑主从关系-新主选择完成-新集群恢复写入

副本排序

Orchestrator判定主库故障后,会停止故障主库的副本和故障主库的复制关系,然后对所有副本进行排序操作。排序规则包括很多,这里只介绍在我们实际应用场景中比较重要的几种规则,其余就不一一介绍了。其中副本排序规则的优先级从高到低依次为:副本对故障主库Binlog的实际执行位置、数据中心(地域)、提升规则。依据排序规则的优先级,Binlog执行位置最新的副本优先,如果副本Binlog执行位置相同,则数据中心和故障主库相同的副本优先,如果Binlog执行位置也相同,则提升规则对应数值小的副本优先。其中提升规则的制定对集群来说是比较灵活的,用户可以自定义每个实例的提升规则,提升规则的选项及其对应的数值如下: 
1.must:0 
2.prefer(比较喜欢):1 
3.neutral(中立):2 
4.prefer_not(比较不喜欢):3 
5.must_not(禁止提升):4

新主选择

根据排序规则对故障主库的所有副本排序完成后,Orchestrator不会直接选择排序结果优先级比较高的副本作为新主库,除了考虑排序结果外,Orchestrator还会考虑副本的版本、副本的Binlog格式、以及副本的提升规则是否设置为must_not(禁止提升),以此来判定某个副本是否合适作为新的主库,综合考虑以上条件后,最终会选择出一个副本作为集群的新主库。

副本划分

新主库初步选择完成后,Orchestrator会对故障主库的其余副本进行划分,划分的规则是副本对故障主库Binlog的实际执行位置,Binlog的执行位置代表同步数据的新旧程度。因此将其余副本划分为三类,分别是:比新主库数据还要新的副本(ahead)、和新主库一样新的副本(equal)、比新主库落后的副本(later)。

重新拓扑

副本划分完成后,进入重构拓扑的步骤,其中重构拓扑包括两个步骤,分别是重置副本的复制关系、分离不可用副本。首先对equal、later副本进行重置,将它们的主库从之前的故障主库变为目前的新主库,并启动它们和新主库之间的复制关系,和新主库建立复制关系后,later副本缺失的数据也会自动得到补偿。除此之外,很关键的一点是在这个阶段新主库还没有进行重置,还保留着和故障主库的复制信息,并且在这一阶段新主库重新开启了了这段复制关系,也就是说,如果这个阶段故障主库被重新拉起来,恢复正常,业务继续向旧主库写入的数据也会同步到新的拓扑中。 
在变更复制关系的过程中,可能有一些副本和新主库产生复制错误,这些副本会被Orchestrator从新集群中分离出去,除此之外,需要分离的副本还包括ahead副本,也就是比新主库数据还要新的副本,根据以上的选主策略,在我们实际的应用场景下,我们初次选出的新主库一般是所有副本中拥有最新数据的,除非最新副本被加入到了提升黑名单中被禁止提升。分离副本的方式是可逆的,通过修改副本的MasterHost实现(change master to “//master”)。

二次选主-理想主库替换新主

新集群拓扑产生后,选主过程并没有结束,Orchestrator会判断当前选出的新主库是否是一个理想的主库,如果不是,Orchestrator会继续尝试从当前新主库的所有副本中选择一个理想的主库来替换当前的新主库,替换的过程相当于两个实例互换角色,不会造成数据丢失。 
对于理想主库的判定,不得不说Orchestrator是非常人性化的,它会从用户的角度出发,尊重用户对于新主库的选择意愿,理想主库的判定和选择包括以下几个规则,这些规则都是用户自定义的选项: 
1.提升规则是否为must或者prefer 
2.DataCenter是否和故障主库相同 
3.PhysicalEnvironment是否和故障主库相同 
Orchestrator两次选主的过程,不仅保证了新集群能够最大程度地拥有最新的数据,并且还保障了用户的实际提升意愿。假设故障主库是广州机房,用户希望提升的新主库也是在广州机房,如果在第一次选主的过程中不幸选中的最新主库是上海机房的,该新主库一定会判定为非理想新主库,在第二次选主的过程中新主库会被理想的广州机房的副本所替换。

新集群恢复写入

新主选择完成后,新集群拓扑还处于只读状态,所以需要恢复新集群的写入,使数据能够正常写入新主库,并且要避免继续写入旧主库。 
这其中首先,在新主库上执行Reset操作来清除新旧主库间的复制关系,然后将新主库设置为可写状态,同时Orchestrator会尝试将故障主库设置为只读状态,防止故障主库重新被拉起造成脏数据的写入。该过程还定义了多个Hook,方便用户进行自定义开发。至此,关于Orchestrator的故障切换过程就完成了。

Orchestrator测试环境规划

IP地址操作系统MySQL版本测试MySQL端口(被管理的MySQL)后端MySQL端口(OC自己的MySQL)备注
10.30.8.108CentOS 7.35.7.1933063307
10.30.8.109CentOS 7.35.7.1933063307
10.30.8.111CentOS 7.35.7.1933063307

测试MySQL和后端MySQL部署过程

1.三台服务器安装MySQL软件(步骤略)

2.测试MySQL主从搭建(一主两从,搭建过程略)

my.cnf 配置文件如下:

  1. [root@kvm_db_1_8_108 ~]# more /etc/my.cnf

  2. [client]

  3. port = 3306

  4. socket = /tmp/mysql.sock

  5. user = root

  6. password = hhueP/Oku6xf


  7. [mysql]

  8. prompt = "\\u@\\h[\\d] \\R:\\m:\\s>"


  9. [mysqld]

  10. server-id = 10308108

  11. user = mysql

  12. port = 3306

  13. socket = /tmp/mysql.sock

  14. bind-address = 0.0.0.0

  15. report-host = 10.30.8.108

  16. report-port = 3306

  17. net_read_timeout = 120

  18. net_write_timeout = 900

  19. #character#

  20. character-set-server = utf8mb4

  21. explicit_defaults_for_timestamp = OFF

  22. skip-external-locking = ON

  23. key_buffer_size = 384M

  24. max_allowed_packet = 64M

  25. table_open_cache = 4096

  26. myisam_sort_buffer_size = 6M

  27. query_cache_type = 0

  28. query_cache_size = 0

  29. #slaveDB

  30. #####thread buffer

  31. tmp_table_size = 100M #不动

  32. max_heap_table_size = 100M #不动

  33. sql_mode =

  34. thread_cache_size = 32

  35. innodb_open_files = 65536

  36. open_files_limit = 65535

  37. table_definition_cache = 4096

  38. table_open_cache_instances = 64

  39. back_log = 500

  40. max_connections = 4500

  41. max_connect_errors = 100000

  42. skip-name-resolve = ON

  43. sysdate_is_now = 1

  44. lower_case_table_names = 1

  45. #thread-pool

  46. thread_handling = one-thread-per-connection

  47. thread_pool_high_prio_mode = statements

  48. extra_port = 3307

  49. #DATA STORAGE

  50. datadir = /mysqldata/mysql3306/data

  51. tmpdir = /mysqldata/mysql3306/tmp

  52. #BINARY LOGGING

  53. log_bin = /mysqldata/mysql3306/log/binlog

  54. expire_logs_days = 14

  55. sync_binlog = 1

  56. binlog_format = row

  57. binlog_row_image = full

  58. binlog_direct_non_transactional_updates = 1

  59. log_slave_updates = 1

  60. max_binlog_cache_size = 8G

  61. max_binlog_size = 1024M

  62. binlog-rows-query-log-events = 1

  63. log_bin_trust_function_creators = 1

  64. # INNODB #

  65. innodb_buffer_pool_size = 10G

  66. innodb_buffer_pool_instances = 16

  67. innodb_buffer_pool_dump_pct = 25

  68. #BACKUP

  69. #buffer recover

  70. innodb_buffer_pool_load_at_startup = 1

  71. innodb_buffer_pool_dump_at_shutdown = 1

  72. innodb_flush_method = O_DIRECT

  73. innodb_log_files_in_group = 3

  74. innodb_log_buffer_size = 32M

  75. innodb_log_file_size = 1G

  76. innodb_log_group_home_dir = /mysqldata/mysql3306/data

  77. innodb_page_cleaners = 8

  78. innodb_flush_log_at_trx_commit = 1

  79. innodb_file_per_table = 1

  80. innodb_max_dirty_pages_pct = 75

  81. innodb_io_capacity = 8000

  82. innodb_io_capacity_max = 15000

  83. innodb_use_native_aio = 1

  84. innodb_read_io_threads = 8

  85. innodb_write_io_threads = 8

  86. innodb_purge_threads = 2

  87. innodb_data_file_path = ibdata1:12M:autoextend

  88. innodb_temp_data_file_path = ibtmp1:12M:autoextend:max:50G

  89. innodb_undo_directory = /mysqldata/mysql3306/data

  90. innodb_rollback_segments = 128

  91. innodb_undo_tablespaces = 0

  92. innodb_undo_log_truncate = 1

  93. innodb_max_undo_log_size = 2G

  94. innodb_purge_rseg_truncate_frequency = 128

  95. innodb_sort_buffer_size = 64M

  96. innodb_print_all_deadlocks = 1

  97. innodb_strict_mode = 1

  98. innodb_online_alter_log_max_size = 10G

  99. innodb_autoinc_lock_mode = 2

  100. # LOGGING #

  101. log_error = /mysqldata/mysql3306/log/mysql-error.log

  102. log_queries_not_using_indexes = 1

  103. slow_query_log = 1

  104. slow_query_log_file = /mysqldata/mysql3306/log/mysql-slow.log

  105. long_query_time = 1

  106. log_slow_sp_statements = 1

  107. log_slow_verbosity = 'microtime,query_plan,innodb,profiling'

  108. #log-queries-not-using-indexes

  109. wait_timeout = 1814400

  110. #stat

  111. innodb_stats_persistent = 1

  112. innodb_stats_auto_recalc = 1

  113. #gtid and semi

  114. #rpl_semi_sync_master_enabled = 1

  115. #rpl_semi_sync_slave_enabled = 1

  116. gtid_mode = on

  117. enforce_gtid_consistency = on

  118. master_info_repository = table

  119. relay_log_recovery = 1

  120. relay_log_info_repository = table

  121. relay_log_purge = 1

  122. relay_log = /mysqldata/mysql3306/log/relaylog

  123. slave-rows-search-algorithms = 'INDEX_SCAN,HASH_SCAN'

  124. #checksum

  125. #innodb_checksum_algorithm = crc32

  126. binlog_checksum = crc32

  127. #innodb_log_checksum_algorithm = crc32

  128. #slave

  129. skip_slave_start = 0

  130. log_timestamps = SYSTEM

  131. slave_parallel_workers = 32

  132. slave-parallel-type = LOGICAL_CLOCK

  133. slave_preserve_commit_order = 1

  134. sort_buffer_size = 16M

  135. read_buffer_size = 8M

  136. join_buffer_size = 64M

  137. read_rnd_buffer_size = 16M

  138. bulk_insert_buffer_size = 32M

  139. binlog_cache_size = 4M

初始化MySQL

  1. mysqld --defaults-file=/etc/my.cnf --initialize

主从库启动mysql

  1. systemctl start mysqld

重置root用户密码和创建复制用户

  1. alter user root@'localhost' identified by 'hhueP/Oku6xf';

  2. create user 'repl'@'%' identified by 'hhueP/Oku6xf';

  3. grant replication slave on *.* to 'repl'@'%';

3.后端MySQL搭建(三台没有主从关系)

my3316.cnf 配置文件如下:

  1. [root@kvm_db_1_8_108 ~]# more /etc/my3316.cnf

  2. [client]

  3. port = 3316

  4. socket = /tmp/mysql3316.sock

  5. user = root

  6. password = hhueP/Oku6xf


  7. [mysql]

  8. prompt = "\\u@\\h[\\d] \\R:\\m:\\s>"


  9. [mysqld]

  10. server-id = 103081082

  11. user = mysql

  12. port = 3316

  13. socket = /tmp/mysql3316.sock

  14. bind-address = 0.0.0.0

  15. report-host = 10.30.8.108

  16. report-port = 3316

  17. net_read_timeout = 120

  18. net_write_timeout = 900

  19. #character#

  20. character-set-server = utf8mb4

  21. explicit_defaults_for_timestamp = OFF

  22. skip-external-locking = ON

  23. key_buffer_size = 384M

  24. max_allowed_packet = 64M

  25. table_open_cache = 4096

  26. myisam_sort_buffer_size = 6M

  27. query_cache_type = 0

  28. query_cache_size = 0

  29. #slaveDB

  30. #####thread buffer

  31. tmp_table_size = 100M #不动

  32. max_heap_table_size = 100M #不动

  33. sql_mode =

  34. thread_cache_size = 32

  35. innodb_open_files = 65536

  36. open_files_limit = 65535

  37. table_definition_cache = 4096

  38. table_open_cache_instances = 64

  39. back_log = 500

  40. max_connections = 4500

  41. max_connect_errors = 100000

  42. skip-name-resolve = ON

  43. sysdate_is_now = 1

  44. lower_case_table_names = 1

  45. #thread-pool

  46. thread_handling = one-thread-per-connection

  47. thread_pool_high_prio_mode = statements

  48. extra_port = 3317

  49. #DATA STORAGE #

  50. datadir = /mysqldata/mysql3316/data

  51. tmpdir = /mysqldata/mysql3316/tmp

  52. #BINARY LOGGING #

  53. log_bin = /mysqldata/mysql3316/log/binlog

  54. expire_logs_days = 14

  55. sync_binlog = 1

  56. binlog_format = row

  57. binlog_row_image = full

  58. binlog_direct_non_transactional_updates = 1

  59. log_slave_updates = 1

  60. max_binlog_cache_size = 8G

  61. max_binlog_size = 1024M

  62. binlog-rows-query-log-events = 1

  63. log_bin_trust_function_creators = 1

  64. # INNODB #

  65. innodb_buffer_pool_size = 1G

  66. innodb_buffer_pool_instances = 16

  67. innodb_buffer_pool_dump_pct = 25

  68. #BACKUP

  69. #buffer recover

  70. innodb_buffer_pool_load_at_startup = 1

  71. innodb_buffer_pool_dump_at_shutdown = 1

  72. innodb_flush_method = O_DIRECT

  73. innodb_log_files_in_group = 3

  74. innodb_log_buffer_size = 32M

  75. innodb_log_file_size = 1G

  76. innodb_log_group_home_dir = /mysqldata/mysql3316/data

  77. innodb_page_cleaners = 8

  78. innodb_flush_log_at_trx_commit = 1

  79. innodb_file_per_table = 1

  80. innodb_max_dirty_pages_pct = 75

  81. innodb_io_capacity = 8000

  82. innodb_io_capacity_max = 15000

  83. innodb_use_native_aio = 1

  84. innodb_read_io_threads = 8

  85. innodb_write_io_threads = 8

  86. innodb_purge_threads = 2

  87. innodb_data_file_path = ibdata1:12M:autoextend

  88. innodb_temp_data_file_path = ibtmp1:12M:autoextend:max:50G

  89. innodb_undo_directory = /mysqldata/mysql3316/data

  90. innodb_rollback_segments = 128

  91. innodb_undo_tablespaces = 0

  92. innodb_undo_log_truncate = 1

  93. innodb_max_undo_log_size = 2G

  94. innodb_purge_rseg_truncate_frequency = 128

  95. innodb_sort_buffer_size = 64M

  96. innodb_print_all_deadlocks = 1

  97. innodb_strict_mode = 1

  98. innodb_online_alter_log_max_size = 10G

  99. innodb_autoinc_lock_mode = 2

  100. # LOGGING #

  101. log_error = /mysqldata/mysql3316/log/mysql-error.log

  102. log_queries_not_using_indexes = 1

  103. slow_query_log = 1

  104. slow_query_log_file = /mysqldata/mysql3316/log/mysql-slow.log

  105. long_query_time = 1

  106. log_slow_sp_statements = 1

  107. log_slow_verbosity = 'microtime,query_plan,innodb,profiling'

  108. #log-queries-not-using-indexes

  109. wait_timeout = 1814400

  110. #stat

  111. innodb_stats_persistent = 1

  112. innodb_stats_auto_recalc = 1

  113. #gtid and semi

  114. #rpl_semi_sync_master_enabled = 1

  115. #rpl_semi_sync_slave_enabled = 1

  116. gtid_mode = on

  117. enforce_gtid_consistency = on

  118. master_info_repository = table

  119. relay_log_recovery = 1

  120. relay_log_info_repository = table

  121. relay_log_purge = 1

  122. relay_log = /mysqldata/mysql3316/log/relaylog

  123. slave-rows-search-algorithms = 'INDEX_SCAN,HASH_SCAN'

  124. #checksum

  125. #innodb_checksum_algorithm = crc32

  126. binlog_checksum = crc32

  127. #innodb_log_checksum_algorithm = crc32

  128. #slave

  129. skip_slave_start = 0

  130. log_timestamps = SYSTEM

  131. slave_parallel_workers = 32

  132. slave-parallel-type = LOGICAL_CLOCK

  133. slave_preserve_commit_order = 1

  134. sort_buffer_size = 16M

  135. read_buffer_size = 8M

  136. join_buffer_size = 64M

  137. read_rnd_buffer_size = 16M

  138. bulk_insert_buffer_size = 32M

  139. binlog_cache_size = 4M

初始化MySQL

  1. mysqld --defaults-file=/etc/my3316.cnf --initialize

启动MySQL

  1. mysqld --defaults-file=/etc/my3316.cnf &

Orchestrator的搭建

Orchestrator 截止当前最新的版本是 V3.2.6,下载地址:

  1. https://github.com/openark/orchestrator/releases

下载完成后解压

  1. cd /bak/data/

  2. tar -xvzf orchestrator-3.2.6-linux-amd64.tar.gz -C /

将/usr/local/orchestrator/orchestrator-sample.conf.json移动到/etc下,并命名为orchestrator.conf.json

  1. cp /usr/local/orchestrator/orchestrator-sample.conf.json /etc/orchestrator.conf.json

配置文件 orchestrator.conf.json 的配置如下:

  1. [root@kvm_db_1_8_108 etc]# more orchestrator.conf.json

  2. {

  3. "Debug": true,

  4. "EnableSyslog": false,

  5. "ListenAddress": ":3000",

  6. "MySQLTopologyUser": "orc_client_user",

  7. "MySQLTopologyPassword": "orc_client_password",

  8. "MySQLTopologyCredentialsConfigFile": "",

  9. "MySQLTopologySSLPrivateKeyFile": "",

  10. "MySQLTopologySSLCertFile": "",

  11. "MySQLTopologySSLCAFile": "",

  12. "MySQLTopologySSLSkipVerify": true,

  13. "MySQLTopologyUseMutualTLS": false,

  14. "MySQLOrchestratorHost": "127.0.0.1",

  15. "MySQLOrchestratorPort": 3316,

  16. "MySQLOrchestratorDatabase": "orchestrator",

  17. "MySQLOrchestratorUser": "orc_server_user",

  18. "MySQLOrchestratorPassword": "orc_server_password",

  19. "MySQLOrchestratorCredentialsConfigFile": "",

  20. "MySQLOrchestratorSSLPrivateKeyFile": "",

  21. "MySQLOrchestratorSSLCertFile": "",

  22. "MySQLOrchestratorSSLCAFile": "",

  23. "MySQLOrchestratorSSLSkipVerify": true,

  24. "MySQLOrchestratorUseMutualTLS": false,

  25. "MySQLConnectTimeoutSeconds": 1,

  26. "DefaultInstancePort": 3306,

  27. "DiscoverByShowSlaveHosts": true,

  28. "InstancePollSeconds": 5,

  29. "BackendDB": "mysql",

  30. "DiscoveryIgnoreReplicaHostnameFilters": [

  31. "a_host_i_want_to_ignore[.]example[.]com",

  32. ".*[.]ignore_all_hosts_from_this_domain[.]example[.]com",

  33. "a_host_with_extra_port_i_want_to_ignore[.]example[.]com:3307"

  34. ],

  35. "UnseenInstanceForgetHours": 240,

  36. "SnapshotTopologiesIntervalHours": 0,

  37. "InstanceBulkOperationsWaitTimeoutSeconds": 10,

  38. "HostnameResolveMethod": "default",

  39. "MySQLHostnameResolveMethod": "",

  40. "SkipBinlogServerUnresolveCheck": true,

  41. "ExpiryHostnameResolvesMinutes": 60,

  42. "RejectHostnameResolvePattern": "",

  43. "ReasonableReplicationLagSeconds": 10,

  44. "ProblemIgnoreHostnameFilters": [],

  45. "VerifyReplicationFilters": false,

  46. "ReasonableMaintenanceReplicationLagSeconds": 20,

  47. "CandidateInstanceExpireMinutes": 60,

  48. "AuditLogFile": "",

  49. "AuditToSyslog": false,

  50. "RemoveTextFromHostnameDisplay": ".mydomain.com:3306",

  51. "ReadOnly": false,

  52. "AuthenticationMethod": "",

  53. "HTTPAuthUser": "",

  54. "HTTPAuthPassword": "",

  55. "AuthUserHeader": "",

  56. "PowerAuthUsers": [

  57. "*"

  58. ],

  59. "ClusterNameToAlias": {

  60. "127.0.0.1": "test suite"

  61. },

  62. "ReplicationLagQuery": "",

  63. "DetectClusterAliasQuery": "select ifnull(max(cluster_name), '') as cluster_alias from orch_meta.cluster where anchor=1",

  64. "DetectClusterDomainQuery": "",

  65. "DetectInstanceAliasQuery": "select @@hostname",

  66. "DetectPromotionRuleQuery": "",

  67. "DataCenterPattern": "[.]([^.]+)[.][^.]+[.]mydomain[.]com",

  68. "DetachLostReplicasAfterMasterFailover": true,

  69. "PhysicalEnvironmentPattern": "",

  70. "PromotionIgnoreHostnameFilters": [],

  71. "DetectSemiSyncEnforcedQuery": "",

  72. "ServeAgentsHttp": false,

  73. "AgentsServerPort": ":3001",

  74. "AgentsUseSSL": false,

  75. "AgentsUseMutualTLS": false,

  76. "AgentSSLSkipVerify": false,

  77. "AgentSSLPrivateKeyFile": "",

  78. "AgentSSLCertFile": "",

  79. "AgentSSLCAFile": "",

  80. "AgentSSLValidOUs": [],

  81. "UseSSL": false,

  82. "UseMutualTLS": false,

  83. "SSLSkipVerify": false,

  84. "SSLPrivateKeyFile": "",

  85. "SSLCertFile": "",

  86. "SSLCAFile": "",

  87. "SSLValidOUs": [],

  88. "URLPrefix": "",

  89. "StatusEndpoint": "/api/status",

  90. "StatusSimpleHealth": true,

  91. "StatusOUVerify": false,

  92. "AgentPollMinutes": 60,

  93. "UnseenAgentForgetHours": 6,

  94. "StaleSeedFailMinutes": 60,

  95. "SeedAcceptableBytesDiff": 8192,

  96. "PseudoGTIDPattern": "",

  97. "PseudoGTIDPatternIsFixedSubstring": false,

  98. "PseudoGTIDMonotonicHint": "asc:",

  99. "DetectPseudoGTIDQuery": "",

  100. "BinlogEventsChunkSize": 10000,

  101. "SkipBinlogEventsContaining": [],

  102. "ReduceReplicationAnalysisCount": true,

  103. "FailureDetectionPeriodBlockMinutes": 60,

  104. "FailMasterPromotionOnLagMinutes": 0,

  105. "RecoveryPeriodBlockSeconds": 30,

  106. "RecoveryIgnoreHostnameFilters": [],

  107. "RecoverMasterClusterFilters": ["*"],

  108. "RecoverIntermediateMasterClusterFilters": ["*"],

  109. "OnFailureDetectionProcesses": [

  110. "echo 'Detected {failureType} on {failureCluster}. Affected replicas: {countSlaves}' >> tmp/recovery.log"

  111. ],

  112. "PreGracefulTakeoverProcesses": [

  113. "echo 'Planned takeover about to take place on {failureCluster}. Master will switch to read_only' >> tmp/recovery.log"

  114. ],

  115. "PreFailoverProcesses": [

  116. "echo 'Will recover from {failureType} on {failureCluster}' >> tmp/recovery.log"

  117. ],

  118. "PostFailoverProcesses": [

  119. "echo '(for all types) Recovered from {failureType} on {failureCluster}. Failed: {failedHost}:{failedPort}; Successor: {successorHost}:{successorPort}' >> tmp/recovery.log"

  120. ],

  121. "PostUnsuccessfulFailoverProcesses": [],

  122. "PostMasterFailoverProcesses": [

  123. "echo 'Recovered from {failureType} on {failureCluster}. Failed: {failedHost}:{failedPort}; Promoted: {successorHost}:{successorPort}' >> tmp/recovery.log"

  124. ],

  125. "PostIntermediateMasterFailoverProcesses": [

  126. "echo 'Recovered from {failureType} on {failureCluster}. Failed: {failedHost}:{failedPort}; Successor: {successorHost}:{successorPort}' >> tmp/recovery.log"

  127. ],

  128. "PostGracefulTakeoverProcesses": [

  129. "echo 'Planned takeover complete' >> tmp/recovery.log"

  130. ],

  131. "CoMasterRecoveryMustPromoteOtherCoMaster": true,

  132. "DetachLostSlavesAfterMasterFailover": true,

  133. "ApplyMySQLPromotionAfterMasterFailover": true,

  134. "PreventCrossDataCenterMasterFailover": false,

  135. "PreventCrossRegionMasterFailover": false,

  136. "MasterFailoverDetachReplicaMasterHost": false,

  137. "MasterFailoverLostInstancesDowntimeMinutes": 0,

  138. "PostponeReplicaRecoveryOnLagMinutes": 0,

  139. "OSCIgnoreHostnameFilters": [],

  140. "GraphiteAddr": "",

  141. "GraphitePath": "",

  142. "GraphiteConvertHostnameDotsToUnderscores": true,

  143. "ConsulAddress": "",

  144. "ConsulAclToken": "",

  145. "ConsulKVStoreProvider": "consul",

  146. "RaftEnabled": true,

  147. "RaftBind": "10.30.8.108",

  148. "RaftDataDir": "/var/lib/orchestrator",

  149. "DefaultRaftPort": 10008,

  150. "RaftNodes": [

  151. "10.30.8.108",

  152. "10.30.8.109",

  153. "10.30.8.111"

  154. ]

  155. }

主要参数的解释如下:

  1. MySQLOrchestratorHost:orch后端数据库地址

  2. MySQLOrchestratorPort:orch后端数据库端口

  3. MySQLOrchestratorDatabase:orch后端数据库名

  4. MySQLOrchestratorUser:orch后端数据库用户名(明文)

  5. MySQLOrchestratorPassword:orch后端数据库密码(明文)

  6. MySQLTopologyUser:被管理的MySQL的用户(明文)

  7. MySQLTopologyPassword:被管理的MySQL的密码(密文)

  8. InstancePollSeconds:orch探测MySQL的间隔秒数

  9. MySQLConnectTimeoutSeconds:orch连接MySQL的超时时间

  10. DefaultInstancePort:被管理MySQL的默认端口

  11. DiscoverByShowSlaveHosts:通过show slave hosts 来发现拓扑结构

  12. DetachLostReplicasAfterMasterFailover:是否强制分离在主恢复中不会丢失的从库

  13. RecoveryPeriodBlockSeconds:在该时间内再次出现故障,不会进行迁移,避免出现并发恢复和不稳定

  14. RecoverMasterClusterFilters:只对匹配这些正则表达式模式的集群进行主恢复(“*”模式匹配所有)。

  15. RecoverIntermediateMasterClusterFilter:只对匹配这些正则表达式模式的集群进行主恢复(“*”模式匹配所有)

  16. HostnameResolveMethod:解析主机名,使用主机名:default;不解析用none,直接用IP --

  17. MySQLHostnameResolveMethod:解析主机名,发出select @@hostname;发出select @@report_host(需要配置report_host)。不解析用"",直接用IP

  18. InstanceBulkOperationsWaitTimeoutSeconds:进行批量操作时等待单个实例的时间

  19. ReasonableReplicationLagSeconds:复制延迟高于该值表示异常

  20. VerifyReplicationFilters:在拓扑重构之前检查复制筛选器

  21. ReasonableMaintenanceReplicationLagSeconds:复制延迟高于该值会上下移动调整MySQL拓扑

  22. CandidateInstanceExpireMinutes:该时间之后,使用实例作为候选从库(在主故障转移时提升)的建议到期

  23. ReplicationLagQuery (SlaveLagQuery):使用SHOW SLAVE STATUS进行延迟判断,力度为秒。

  24. DetectClusterAliasQuery:查询集群别名的query,信息放到每个被管理实例的meta库的cluster表中。--参考参数 DetectClusterAliasQuery

  25. DetectClusterDomainQuery:查询集群Domainquery,信息放到每个被管理实例的meta库的cluster表中。

  26. DetectInstanceAliasQuery:查询实例的别名。--

  27. BackendDB:后端数据库类型。

  28. RaftEnabled:是否开启Raft,保证orch的高可用。

  29. RaftDataDir:Raft的数据目录。

  30. RaftBind:Raft bind地址。

  31. DefaultRaftPort:Raft的端口。

  32. RaftNodes:Raft的节点。

  33. ConsulAddress:Consul的地址。

  34. ConsulAclToken:Consultoken

Orchestrator的调试

1.安装完成后创建 orchestrator 所需的库和用户(三个节点 3316)

  1. mysql -S /tmp/mysql3316.sock -uroot -p123456


  2. CREATE DATABASE IF NOT EXISTS orchestrator;

  3. CREATE USER 'orc_server_user'@'127.0.0.1' IDENTIFIED BY 'orc_server_password';

  4. GRANT ALL PRIVILEGES ON `orchestrator`.* TO 'orc_server_user'@'127.0.0.1';

2.被管理的数据库的授权(3306)

  1. CREATE USER 'orc_client_user'@'10.30.8.%' IDENTIFIED BY 'orc_client_password';

  2. GRANT SUPER, PROCESS, REPLICATION SLAVE, RELOAD ON *.* TO 'orc_client_user'@'10.30.8.%';

  3. GRANT SELECT ON mysql.slave_master_info TO 'orc_client_user'@'10.30.8.%';

  4. GRANT SELECT ON orch_meta.* TO 'orc_client_user'@'10.30.8.%'; --这个权限参考参数 DetectClusterAliasQuery,如果设置了参数,需要创建对应的库和表

  5. GRANT SELECT ON ndbinfo.processes TO 'orc_client_user'@'10.30.8.%'; -- Only for NDB Cluster

如果启用 DetectClusterAliasQuery,需要建库和表

  1. 参考 https://github.com/Fanduzi/orchestrator-chn-doc/blob/master/Setup/%E9%85%8D%E7%BD%AE/Configuration%20%20Discovery%2C%20classifying%20servers.md#cluster-alias


  2. create database orch_meta;

  3. use orch_meta;

  4. CREATE TABLE IF NOT EXISTS cluster (

  5. anchor TINYINT NOT NULL,

  6. cluster_name VARCHAR(128) CHARSET ascii NOT NULL DEFAULT '',

  7. cluster_domain VARCHAR(128) CHARSET ascii NOT NULL DEFAULT '',

  8. PRIMARY KEY (anchor)

  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3.启动Orchestrator(OC这里测试的raft enable,所以三个节点都起,注意修改配置文件)
[root@kvm_db_1_8_108 ~]# scp etc/orchestrator.conf.json 10.30.8.109:/etc/ 
[root@kvm_db_1_8_108 ~]# scp etc/orchestrator.conf.json 10.30.8.111:/etc/

  1. cd /usr/local/orchestrator && ./orchestrator --config=/etc/orchestrator.conf.json http &

web端访问地址 10.30.8.108:3000,下图是我做完测试后的截图,大家凑合看下效果

kill 掉 10.30.8.108 上的mysql主库后,10.30.8.111变成了新的主库,10.30.8.109自动变更成10.30.8.111的从库 

重新拉起 10.30.8.108上的测试mysql后,重置下主从关系,Orchestrator 会自动发现拓扑关系


也可以在Home-Status下看到当前的 Orchestrator Raft 集群的节点情况




4.补充点: Orchestrator 的raft高可用 
如果需要启动 RaftEnabled ,需要在 orchestrator 的各个几点上部署 orchestrator 进程,编辑 /etc/orchestrator.conf.json 下的参数 RaftBind 和 RaftEnabled 
改完 RaftBind 和 RaftEnabled 之后,启动orchestrator进程,之后就可以看到日志中显示:

  1. 2022-04-18 20:35:44 DEBUG orchestrator/raft: applying command 74: request-health-report

  2. 2022-04-18 20:35:48 INFO auditType:forget-clustr-aliases instance::0 cluster: message:Forgotten aliases: 0

  3. 2022-04-18 20:35:48 INFO auditType:forget-unseen-differently-resolved instance::0 cluster: message:Forgotten instances: 0

  4. 2022-04-18 20:35:48 INFO auditType:forget-unseen instance::0 cluster: message:Forgotten instances: 0

  5. 2022-04-18 20:35:48 INFO auditType:review-unseen-instances instance::0 cluster: message:Operations: 0

  6. 2022-04-18 20:35:48 INFO auditType:inject-unseen-masters instance::0 cluster: message:Operations: 0

  7. 2022-04-18 20:35:48 INFO auditType:resolve-unknown-masters instance::0 cluster: message:Num resolved hostnames: 0

  8. 2022-04-18 20:35:48 DEBUG raft leader is 10.30.8.108:10008; state: Follower

  9. 2022-04-18 20:35:53 DEBUG raft leader is 10.30.8.108:10008; state: Follower

5.故障测试 
(1).Orchestrator 一个节点挂掉 
kill掉 orchestrator leader节点的进程,raft集群进行切换,有新的节点成为了leader 
(2).mysql主库挂掉,从节点能不能变主库接管服务 
kill 掉mysql主库后,其中一个从库变成主库

Orchestrator 的优缺点

需要明白的是 Orchestrator 的作用是仅仅是保证 MySQL数据库的高可用,在MySQL主库故障时能自动进行故障切换,选举出新的主库,恢复集群写入,保证业务正常访问。 
MHA和Orchestrator的对比:

MHA和Orchestrator的对比

功能MHAOrchestrator
自身高可用单点基于Raft协议实现高可用
宕机判断悲观检测可靠的故障检测
数据补偿支持不支持
选主模式选择最新从库选择最合适的从库
GTID模式支持支持
自动&手动切换支持支持
自定义Hook支持支持支持

在实际使用过程中,MySQL集群的上层需要部署一层代理如DBPorxy为业务和数据库之间的中间层,为业务访问数据库提供了独立、透明的高性能代理服务。 
MHA架构单点自身不是高可用,有vip跨机房漂移的问题(这个问题比较严重),出现故障时如果vip漂移的有问题需要DBA进行干预,不需要业务进行整改,如果要改成 Orchestrator 的高可用架构,需要加代理解决的主要问题是到域名到主库ip的指向的问题,可以考虑Consul。

参考文档:

https://github.com/openark/orchestrator/tree/master/docs

https://mp.weixin.qq.com/s/HS3Cit5r2K-B4adW9DIl1g

文章转载自学徒杨新建,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论