MySQL是云计算领域非常重要的RDS(Relational Database Service),应用非常广泛,但是MySQL的运维非常复杂。为了提供更好的服务,我们开发了Xenon。它帮助 MySQL Cluster 更高的可用性,使强一致性达到一个新的高度。由于高度自动化且无需人工干预,O&M(运维)现在更容易且成本更低。
Xenon 是一个去中心化的代理,不会对 MySQL 源进行侵入式访问。Xenon管理 MySQL 实例。只要网络可达,它就不会关心部署站点。
它使用 LVS + Raft + GTID 并行复制进行主数据同步。更重要的是,Xenon拯救了一批运维人员。现在他们最大的乐趣就是在制作休闲高手。
Xenon
是一个 MySQL 复制拓扑 HA、管理和可视化工具,允许:
Xenon
主动获取集群拓扑并映射它们。它读取基本的 MySQL 信息,例如复制状态和配置。
Xenon
了解复制规则。它知道 binlog 文件:位置、GTID、Binlog 服务器。
重构复制拓扑可以是将副本拖放到另一个主服务器下。移动副本是安全的:xenon
将拒绝非法的重构尝试。
Xenon
使用整体方法来检测主控和中间主控故障。根据从拓扑本身获得的信息,它可以识别各种故障场景。
可选地,它具有恢复节点的选项(这也允许用户指定恢复节点)。
Raft+介绍
在Raft+
中,使用 MySQL GTID (Global Transaction Identifier) 作为日志索引,用于Raft protocol
结合 MySQL 的 Multi-Threaded Slave (MTS)。它可以完成日志条目的并行复制、并行回放,日志回放消耗的时间极短,并且在故障转移后立即对外服务。
同时,Raft+
使用Semi-Sync-Replication保证至少有一个slave与master完全同步。master失败后,数据完全同步的slave将被选为新的Master。
这确保了零数据丢失和高可用性。
Raft+ 只读状态
除了Leader
// raft+之外的三个状态还提供Candidate
状态:Follower Idle
Idle
状态适合部署为远程机房的容灾实例。通过Idle
设置,可以重新组装不同的Xenon节点来提供服务,我们称之为Semi-Raft Group
.
例如,机房 A 有 3 个节点,形成一个Semi-Raft Group
. 这些机器是:
[A1:Leader, A2:Follower, A3: Follower]
Room B有3个容灾节点(Semi-Raft Group):
[B1:Idle, B2:Idle, B3:Idle]
如果房间A断电并恢复很长时间,我们可以设置房间B的三个实例从Idle到Follower。
这样B房间的Semi-Raft Group就向主机发起外部服务的选择。结合BinlogServer
,A 的数据一模一样。
rebuildme
重建必须安装xtrabackup。补充:
此软件需要在每台MySQL服务器安装配置。
所有机器执行
yum install -y wget git unzip sshpass
所有机器执行
# 生成密钥
ssh-keygen # 一路回车
# 传输密钥
ssh-copy-id root@'10.10.8.203'
ssh-copy-id root@'10.10.8.204'
ssh-copy-id root@'10.10.8.206'
# 验证
ssh 10.10.8.203 date
ssh 10.10.8.204 date
ssh 10.10.8.206 date
内网可指定内网时间同步服务器,此处使用阿里云时间同步服务器。
# 时间同步
ntpdate -u ntp.aliyun.com
# 定时同步时间
cat >>/var/spool/cron/root<<'EOF'
# ntp 时间同步
00 00 * * * /usr/sbin/ntpdate -u ntp.aliyun.com
EOF
# 验证
crontab -l
所有机器执行
# 下载二进制包
wget https://golang.google.cn/dl/go1.18.8.linux-amd64.tar.gz
# 解压包
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.18.8.linux-amd64.tar.gz
# 配置环境变量
cat >/etc/profile.d/go.sh<<'EOF'
export PATH=$PATH:/usr/local/go/bin
EOF
# 生效环境变量
source /etc/profile.d/go.sh
# 关闭GO111MODULE
go env -w GO111MODULE=off
# 查看版本信息
go version
所有机器执行
# 下载
wget https://downloads.percona.com/downloads/Percona-XtraBackup-2.4/Percona-XtraBackup-2.4.26/binary/redhat/7/x86_64/percona-xtrabackup-24-2.4.26-1.el7.x86_64.rpm
# 安装
yum install -y percona-xtrabackup-24-2.4.26-1.el7.x86_64.rpm && rm -f percona-xtrabackup-24-2.4.26-1.el7.x86_64.rpm
# 验证
xtrabackup --version
所有机器执行
# 安装常用命令及依赖
yum install -y net-tools lrzsz vim libaio-devel ntpdate epel-release \
tree libaio-devel lsof sysstat bash-completion bash-completion-extras jemalloc
# 卸载mariadb
yum remove mariadb* -y
# 创建MySQL软件及数据目录
mkdir /mysql/{tools,tar} -p
mkdir /mydata/3306/{binlog,data,etc,lock,log,pid,socket,tmp,script} -p
# 下载安装包
# md5验证包的完整性
md5sum mysql-5.7.36-linux-glibc2.12-x86_64.tar.gz
# 1748ec2c8b5ca1bcf8ba3b1f5e956139 mysql-5.7.36-linux-glibc2.12-x86_64.tar.gz
# 解压MySQL包
cd /mysql/tar
tar xf /mysql/tar/mysql-5.7.36-linux-glibc2.12-x86_64.tar.gz
# 移动tar包到mysql目录
mv /mysql/tar/mysql-5.7.36-linux-glibc2.12-x86_64 /mysql/mysql57
# 配置环境变量
cat >/etc/profile.d/mysql.sh<<'EOF'
export PATH=/mysql/mysql57/bin:$PATH
EOF
#修改权限
chmod 700 /etc/profile.d/mysql.sh
#生效环境变量
source /etc/profile.d/mysql.sh
# 创建所需用户
groupadd mysql
useradd mysql -g mysql
# 添加配置文件
vim /mydata/3306/etc/my.cnf
[client]
socket=/mydata/3306/socket/mysql.sock
[mysql]
socket=/mydata/3306/socket/mysql.sock
prompt='\u@\d>\_'
default-character-set=utf8mb4
no-auto-rehash
#show-warnings #查看告警信息
[mysqld]
# GENERAL #
lower_case_table_names = 1
character_set_server = utf8mb4
collation_server = utf8mb4_general_ci
user = mysql
default_storage_engine = InnoDB
port = 3306
socket = /mydata/3306/socket/mysql.sock
pid-file = /mydata/3306/pid/mysql.pid
log_timestamps = SYSTEM
default_time_zone = +08:00
secure_file_priv = ''
local_infile = ON
thread_stack = 512K
# MyISAM #
key_buffer_size = 128M
myisam_sort_buffer_size = 8M
read_rnd_buffer_size = 262144
# SAFETY #
back_log = 1024
bind-address = 0.0.0.0
innodb_strict_mode = 1
max_allowed_packet = 32M
max_connect_errors = 1000000
interactive_timeout = 900
wait_timeout = 900
skip_grant_tables = 0
skip_name_resolve = 1
host_cache_size = 0
sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
sysdate_is_now = 1
transaction_isolation = REPEATABLE-READ
explicit_defaults_for_timestamp = 1
# DATA STORAGE #
basedir = /mysql/mysql57
datadir = /mydata/3306/data
tmpdir = /mydata/3306/tmp
# BINARY LOGGING #
#max_binlog_files = 100
binlog_cache_size = 1M
binlog_format = ROW
expire_logs_days = 7
max_binlog_size = 512M
max_binlog_cache_size = 4G
log_bin = /mydata/3306/binlog/mysql-bin
log_bin_index = /mydata/3306/binlog/mysql-bin.index
sync_binlog = 1
innodb_support_xa = 1
master-info-repository = TABLE
# REPLICATION #
log_slave_updates = 1
read_only = 1
relay_log = /mydata/3306/binlog/relay-bin
relay_log_index = /mydata/3306/binlog/relay-bin.index
server_id = 330651
slave_skip_errors = OFF
skip_slave_start
slave_net_timeout = 60
relay-log-info-repository = TABLE
slave_compressed_protocol = OFF #5.6版本、5.7.21+、8.0.4+可以设置为ON
# CACHES AND LIMITS #
max_connections = 2000
max_heap_table_size = 128M
tmp_table_size = 128M
open_files_limit = 65535
query_cache_limit = 1M
query_cache_min_res_unit = 4096
query_cache_size = 0
query_cache_type = 0
join_buffer_size = 1M
read_buffer_size = 1M
sort_buffer_size = 1M
table_definition_cache = 4096
table_open_cache = 4000
thread_cache_size = 1000
# INNODB #
innodb_autoextend_increment = 64
innodb_buffer_pool_instances = 45
innodb_buffer_pool_size = 95G
innodb_buffer_pool_load_at_startup = ON
innodb_buffer_pool_dump_at_shutdown = ON
innodb_data_file_path = ibdata1:1024M:autoextend
innodb_fast_shutdown = 1
innodb_file_format = Barracuda
innodb_file_format_max = Barracuda
innodb_file_per_table = 1
innodb_force_recovery = 0
innodb_flush_log_at_trx_commit = 1
innodb_flush_method = O_DIRECT
innodb_lock_wait_timeout = 50
innodb_log_buffer_size = 8M
innodb_log_file_size = 1024M
innodb_log_files_in_group = 4
innodb_open_files = 10000
innodb_purge_threads = 4
innodb_read_io_threads = 8
innodb_write_io_threads = 8
innodb_sync_spin_loops = 30
innodb_thread_concurrency = 24
innodb_print_all_deadlocks = 1
innodb_io_capacity = 2000
# LOGGING #
general_log = 0
general_log_file = /mydata/3306/log/mysql-general.log
log_error = /mydata/3306/log/mysql-error.log
log_queries_not_using_indexes = 0
long_query_time = 1
slow_query_log = 1
slow_query_log_file = /mydata/3306/log/mysql-slow.log
# GTID
enforce_gtid_consistency = ON
gtid_mode = ON
binlog_gtid_simple_recovery = TRUE
# SEMI-SYNC
plugin-load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so"
rpl_semi_sync_master_enabled = ON
rpl_semi_sync_slave_enabled = ON
rpl_semi_sync_master_timeout = 10000
rpl_semi_sync_master_trace_level = 32
rpl_semi_sync_slave_trace_level = 32
rpl_semi_sync_master_wait_no_slave = ON
##parallel 配置文件参数 ##
slave_rows_search_algorithms = 'INDEX_SCAN,HASH_SCAN'
binlog_group_commit_sync_delay = 500
binlog_group_commit_sync_no_delay_count = 13
slave_parallel_type = LOGICAL_CLOCK
slave_parallel_workers = 40
slave_preserve_commit_order = 1
binlog_transaction_dependency_tracking = writeset
transaction_write_set_extraction = XXHASH64
slave_checkpoint_period = 2
binlog_checksum = CRC32
log_slave_updates = ON
master_info_repository = TABLE
relay_log_info_repository = TABLE
relay_log_recovery = 1
# 将配置文件链接到 etc 下
ln -s /mydata/3306/etc/my.cnf /etc/my3306.cnf
# 创建error文件
touch /mydata/3306/log/mysql-error.log
# 授权mysql数据目录
chown -R mysql:mysql /mydata/
chmod 700 /mydata/
# 初始化MySQL
mysqld --initialize-insecure --user=mysql --basedir=/mysql/mysql57 --datadir=/mydata/3306/data --innodb_data_file_path=ibdata1:1024M:autoextend
# 配置system管理
cat >/usr/lib/systemd/system/mysqld3306.service<<'EOF'
[Unit]
Description=MySQL 3306 Server
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/mysql/mysql57/bin/mysqld_safe --defaults-file=/mydata/3306/etc/my.cnf
LimitNOFILE = 65536
LimitNPROC = 65535
Restart=on-failure
RestartPreventExitStatus=1
ReStartSec=10
StartLimitInterval=300
StartLimitBurst=2
TimeoutStartSec=30
TimeoutStopSec=30
EOF
# 生效
systemctl daemon-reload
# 启动实例
systemctl start mysqld3306
# 重置启动次数
#systemctl reset-failed mysqld3306.service
# 查看状态
systemctl status mysqld3306
# 设置便捷登录
cat >/usr/local/bin/3306_mysql_login.sh<<'EOF'
mysql -A -S /mydata/3306/socket/mysql.sock -p
EOF
# 授权
chmod 700 /usr/local/bin/3306_mysql_login.sh
# 修改密码
alter user root@localhost identified by '123456';
flush privileges;
主库创建用户后,在从库服务器执行指定主库和开启主从的操作。
# 主库创建复制用户
grant replication slave on *.* to repl@'10.10.8.%' identified by '123456';
flush privileges;
# 从库指定主库信息
change master to
master_host='10.10.8.203',
master_user='repl',
master_port=3306,
master_password='123456',
MASTER_AUTO_POSITION=1;
#开启主从
start slave;
#查看主从信息
show slave status\G
所有机器执行
# 下载
cd /usr/local/
git clone https://github.com/radondb/xenon.git
# 安装
cd xenon
make build
make
# 验证
/usr/local/xenon/bin/xenoncli version
#xenoncli:[{Tag:v1.1.4-34-gbae9e0d Time:2022/11/09 12:04:30 Git:bae9e0d GoVersion:go1.18.8 Platform:linux amd64}]
所有机器执行,按照自己的环境修改配置中的IP地址为本机的IP。
# 进入配置文件目录
cd /usr/local/xenon/conf
# 主库创建xenon账号
#grant all on *.* to xenon@'10.10.8.%' identified by '123456';flush privileges;
# 创建备份目录
mkdir -p /mydata/backup/3306
# 拷贝配置文件
cp xenon-sample.conf.json xenon.json
# 创建日志目录
mkdir /usr/local/xenon/log
# 编辑配置文件
vim xenon.json
{
"server":
{
//修改为当前服务器的IP
"endpoint":"10.10.8.203:8801"
},
"raft":
{
"meta-datadir":"raft.meta",
"heartbeat-timeout":1000,
"election-timeout":3000,
// 修改为自己的VIP、子网掩码和网卡名
"leader-start-command":"/sbin/ip a add 10.10.8.207/23 dev ens192 && arping -c 3 -A 10.10.8.207 -I ens192",
"leader-stop-command":"/sbin/ip a del 10.10.8.207/23 dev ens192"
},
"mysql":
{
// 数据库连接管理账号(需要在主库创建此账号)
"admin":"xenon",
"passwd":"123456",
"host":"10.10.8.203",
"port":3306,
// mysql安装路径
"basedir":"/mysql/mysql57",
// mysql配置文件路径
"defaults-file":"/mydata/3306/etc/my.cnf",
"ping-timeout":1000,
"master-sysvars":"super_read_only=0;read_only=0;sync_binlog=default;innodb_flush_log_at_trx_commit=default",
"slave-sysvars": "super_read_only=1;read_only=1;sync_binlog=1000;innodb_flush_log_at_trx_commit=2"
},
"replication":
{
// 指定主从的账号密码
"user":"repl",
"passwd":"123456"
},
"backup":
{
// root账号连接信息
"ssh-host":"10.10.8.203",
"ssh-user":"root",
"ssh-passwd":"123456",
"ssh-port":22,
// 备份文件保存路径(建议空间大的目录,不要直接使用根下的目录)
"backupdir":"/mydata/backup/3306",
// xtrabackupex 安装路径
"xtrabackup-bindir":"/usr/bin",
"backup-iops-limits":100000,
// xtrabackupex 使用内存大小
"backup-use-memory": "1GB",
"backup-parallel": 2
},
"rpc":
{
"request-timeout":500
},
"log":
{
"level":"INFO"
}
}
第一次启动需要手动指定VIP
主库执行,按自己的环境需改即可。
/sbin/ip a add 10.10.8.207/23 dev ens192 && arping -c 3 -A 10.10.8.207 -I ens192
# 开启
nohup /usr/local/xenon/bin/xenon -c /usr/local/xenon/conf/xenon.json >>/usr/local/xenon/log/xenon.log 2>&1 &
# 停止
pkill xenon
# 指定配置文件路径 // 不指定报错
echo "/usr/local/xenon/conf/xenon.json" >/usr/local/xenon/bin/config.path
# 加入集群
/usr/local/xenon/bin/xenoncli cluster \
add 10.10.8.203:8801,10.10.8.204:8801,10.10.8.206:8801
# 检查集群raft状态
/usr/local/xenon/bin/xenoncli cluster raft
# 检查集群状态
/usr/local/xenon/bin/xenoncli cluster status
# 检查集群mysql状态
/usr/local/xenon/bin/xenoncli cluster mysql
# 检查集群 gtid 状态
/usr/local/xenon/bin/xenoncli cluster gtid
# 删除节点
/usr/local/xenon/bin/xenoncli cluster \
remove 10.10.8.206:8801
# 重建节点 // 再需要重建的机器上执行
#/usr/local/xenon/bin/xenoncli mysql rebuildme
# ./xenoncli mysql -h
mysql related commands
Usage:
xenoncli mysql [command]
Available Commands:
backup 将这个 mysql 备份到备份目录
cancelbackup 取消备份
changepassword 更新 mysql 普通用户密码
createsuperuser 创建 mysql 超级用户
createuser 创建 mysql 普通用户
createuserwithgrants 创建具有权限的 mysql 普通用户
dropuser 删除 mysql 普通用户
kill 杀死 mysql pid (beareful!)
rebuildme 重建从库 --from=endpoint
shutdown 关闭 mysql
start 启动 mysql
startmonitor 启动 mysqld 监视器
status mysql状态 JSON格式现实(mysqld/slave_SQL/IO is running)
stopmonitor 停止 mysqld 监视器
sysvar 设置全局变量
当节点出现故障xenon无法自动拉起时,在故障节点使用rebuildme
重建节点是比较简单的。
# 在要做重建的节点执行
xenoncli mysql rebuildme
# 可指定参数
--from=10.10.8.204:8081 # 指定使用哪个从库进行备份
--from=IP:XENON_PORT
,可以指定从哪个数据库备份。当集群需要主库做升级等一些特殊操作时可以选择手动切换主库,以达到串行操作的目的。
在预选的主库(新主库)上执行重新选主的操作。
# 在预选的主库上执行重新选主的操作
/usr/local/xenon/bin/xenoncli raft trytoleader
# 查看状态
/usr/local/xenon/bin/xenoncli cluster status
# 查看VIP是否切换成功
ip a|grep 207
我们通过 Quickstack 爬取 MySQL 进程,看看 MySQL 是如何调用栈信息的。对问题的后续分析进行了简化。
该quickstack
速度很快,对流程的影响很小。
# 需要安装quickstack命令,项目地址如下:
https://github.com/yoshinorim/quickstack
# 使用quickstack捕获mysqld的堆栈
/usr/local/xenon/bin/xenoncli perf quickstack
# 开启半同步复制检查
/usr/local/xenon/bin/xenoncli raft enablechecksemisync
# 关闭半同步复制检查
/usr/local/xenon/bin/xenoncli raft disablechecksemisync
参考github:https://github.com/radondb/xenon
本文章仅供参考。