MariaDBを3台構成で、
準同期レプリケーション&スレーブ自動昇格
のクラスターを組んだので、備忘録として記載しておく。
[ソフトウェア]
- MariaDB 10.1.18
- Maxscale 2.0.1
- MariaDB Replication Manager 0.6.4(以下MRM)
[インフラ]
- web × 3 → MariaDB client, Maxscale, MRMを配備
- db × 3 → MariaDB serverを配備
[処理概要]
webに配備されたMaxscaleはReadWriteSplitterで起動し、
127.0.0.1:4000のアクセスを、dbに振り分ける。
同時に、Maxscaleのmonitor機能により、
masterがフェイルオーバした際は、
MRMがコールされ、スレーブの自動昇格を実現する。
[注意したこと]
執筆時点でMRMの0.7rc3はリリースされていたが、どうも不具合があり、0.6.4で対応した。
ただし、issueでも上がっていたので、近日中には修正されると期待している。
MaxscaleからMRMを呼び出すのだが、
masterダウンイベントが走った際、3つのMRMが同時に検知してフェイルオーバ処理を実施した場合、
昇格の一貫性を保証するかわからなかったので、
masterダウンイベントを受け取った、webノード3台が相互に生き死にを確認し、もっとも優先順位が高いノードが、
フェイルオーバ処理を実行するようにした。
上記により、現状手動によるフェイルオーバ検知はすべて正常に行わるが、
MRMを呼び出す部分においてラップしているrubyスクリプトが、
ゾンビプロセスとなる不具合がある。
これについては、現状理由がよくわかっていないが、
Maxscaleを再起動すればなくなるので、一旦放置とした。
参考に、各設定を残しておく。
[maxscale.conf]
# Global parameters [maxscale] threads=2 # Server definitions [s-db01] type=server address=XXX.XXX.XXX.1 port=3306 protocol=MySQLBackend [s-db02] type=server address=XXX.XXX.XXX.2 port=3306 protocol=MySQLBackend [s-db03] type=server address=XXX.XXX.XXX.3 port=3306 protocol=MySQLBackend # Monitor for the servers [m-db] type=monitor module=mysqlmon servers=s-db01,s-db02,s-db03 user=XXX passwd=XXX monitor_interval=3000 script=/usr/local/bin/mrm.rb -u XXX:XXX -r XXX:XXX -h $INITIATOR,$NODELIST -e $EVENT -m m-db --live_nodes $NODELIST events=master_down,master_up,slave_down,slave_up,new_master,new_slave # Service definitions [rw-db] type=service router=readwritesplit servers=s-db01,s-db02,s-db03 user=XXX passwd=XXX max_slave_connections=100% localhost_match_wildcard_host=1 [maxadmin service] type=service router=cli # Listener definitions for the services [l-db] type=listener service=rw-db protocol=MySQLClient port=4000 [maxadmin listener] type=listener service=maxadmin service protocol=maxscaled port=6603
[mrm.rb]
#!/usr/bin/ruby # -*- encodinfg: utf-8 -*- # # maxscaleからfailoverを実行させるためのスクリプト # # 引数解析ライブラリ読み込み require 'optparse' ############################## # 初期化 admin_user = nil replication_user = nil target_hosts = nil event_name = nil monitor_name = nil live_nodes = nil # 引数解析 OptionParser.new do |opt| # 管理ユーザ opt.on('-u VALUE', 'admin user and password') do |v| admin_user = v logger.info('admin_user => %s' % v) end # レプリケーションユーザ opt.on('-r VALUE', 'replication user and password') do |v| replication_user = v logger.info('replication_user => %s' % v) end # 対象ホスト opt.on('-h VALUE', 'target hosts') do |v| target_hosts = v logger.info('target_hosts => %s' % v) end # 監視名 opt.on('-m VALUE', 'monitor name') do |v| monitor_name = v logger.info('monitor_name => %s' % v) end # イベント名称 opt.on('-e VALUE', 'event name') do |v| event_name = v logger.info('event_name => %s' % v) end # 稼働中ノード opt.on('--live_nodes [VALUE]', 'live nodes (optional)') do |v| live_nodes = v logger.info('live_nodes => %s' % v) end # 解析 opt.parse!(ARGV) end # チェック if !admin_user || !replication_user || !target_hosts || !event_name || !monitor_name # 終了 exit end # クラスターを取得 got_result_ip_list = [] cluster_ip_list = getClusterInternalIpList('web') cluster_ip_list.each do |cluster_ip| # maxadminの状況確認 command = '/usr/bin/timeout 3 /usr/bin/maxadmin -pmariadb -h %s list monitors | grep -F "%s" | grep -F "Running"' % [cluster_ip, monitor_name] result = exec(command) # 結果を取得できたIPを取得 if result.length > 0 got_result_ip_list.push(cluster_ip) end end # 結果を取得できたIPの先頭が自分のIPなら実行する self_internal_ip = getSelfInternalIp() if self_internal_ip != got_result_ip_list.shift # 終了 exit end # eventチェック command = nil result = nil if event_name == 'master_down' # replication-manager実行 raw_command = <<EOF /usr/local/bin/replication-manager\ --user=%s\ --rpluser=%s\ --hosts=%s\ --failover=force\ --interactive=false\ --gtidcheck=true\ 2>&1 | cat EOF command = raw_command % [admin_user, replication_user, target_hosts] result = exec(command) end # メール通知など
[my.cnf]
※3台とも同じ設定で、マシンスペックは4CORE/26GBの仮想マシンで、更新系に重点を置いている
########## # mysqld ########## [mysqld] # -------------------------------------------------- # base # -------------------------------------------------- user=mysql bind-address=0.0.0.0 port=3306 pid-file=/var/run/mysqld/mysqld.pid datadir=/var/lib/mysql socket =/var/lib/mysql/mysql.sock symbolic-links=0 sql_mode=TRADITIONAL default-storage-engine=InnoDB transaction-isolation=READ-COMMITTED character-set-server=utf8mb4 collation-server=utf8mb4_general_ci skip-character-set-client-handshake=0 innodb_buffer_pool_load_at_startup=1 innodb_buffer_pool_dump_at_shutdown=1 thread_handling=pool-of-threads # -------------------------------------------------- # replication # -------------------------------------------------- server-id=1 binlog_format=row log-bin=mysql-bin max_binlog_size=128M sync_binlog=1 expire_logs_days=3 innodb_flush_log_at_trx_commit=1 innodb_autoinc_lock_mode=2 plugin-load=rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so rpl_semi_sync_master_enabled=1 rpl_semi_sync_master_timeout=1000 rpl_semi_sync_slave_enabled=1 # -------------------------------------------------- # network # -------------------------------------------------- max_connections=1500 max_connect_errors=999999999 connect_timeout=10 max_allowed_packet=1G # -------------------------------------------------- # logging # -------------------------------------------------- log_output=FILE log_warnings=1 log_error=/var/log/mysql/error.log slow_query_log=1 long_query_time=0.5 slow_query_log_file=/var/log/mysql/slow.log innodb_file_per_table=1 innodb_log_buffer_size=16M # -------------------------------------------------- # cache, memory # -------------------------------------------------- query_cache_size=0 max_heap_table_size=32M tmp_table_size=32M thread_cache_size=500 innodb_buffer_pool_size=20G innodb_flush_neighbors=0 innodb_log_file_size=!G # -------------------------------------------------- # query # -------------------------------------------------- sort_buffer_size=512K read_rnd_buffer_size=512K read_buffer_size=512K join_buffer_size=512K ########## # mysqldump ########## [mysqldump] default-character-set=utf8mb4 max_allowed_packet=1G ########## # mysql ########## [mysql] default-character-set=utf8mb4 ########## # mysqld-safe ########## [mysqld_safe] log-error=/var/log/mysql/error.log
今後、高負荷状況において、テストを行うので、
修正があれば別途記載しようと思う。
以上
コメントがあればどうぞ