mysql高可用架构

目录

  • 背景
  • mysql8安装
  • 备机安装mysql8
    • 主备状态查看
  • mysql router安装
  • keepalived安装
  • proxy安装
  • MHA安装
  • my.cnf配置
  • Granafa监控
  • 主从同步处理
    • 主从error处理
      • pt-table-sync安装
      • 手动处理
      • 自动处理
    • 主挂了从升主处理
    • 主挂了从升主之后,原主恢复变从

背景

  • centos7.6机器,256G内存,64C,3.5T SSD
  • 之前线上已经有mysql运行中的机器了,所以会在原有基础上修改/etc/my.cnf配置文件
  • 目前架构是一主一台,两个集群,数据是应用层双写,业务不太敏感数据轻微不一致
  • 使用mysql router做集群内的读写分离,两台都安装router,并使用vip做router的高可用
  • 没用使用MHA等方案监控自动主从切换,当主挂了时,人工介入目前,后续可能考虑
  • 架构,单集群展示,VIP会漂移到Router A或者Router B,然后根据读写到mysqlA或者mysqlB


    image.png

mysql8安装

  • 安装repo, 注意看有没报错哈,没报错就我截图那样
yum install -y https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
image.png
  • 安装mysql8, 注意看有没报错哈,没报错就我截图那样
yum install -y --nogpgcheck mysql-community-server
image.png
  • 看下机器之前有没mysql数据, 有的话考虑rm -rf掉
ll /var/lib/mysql/
  • 我是在本地编辑my.cnf然后上传上去的,所以我这边执行删除之前旧的my.cnf,再上传,如果你使用默认的就忽略就好
cd /etc
rm my.cnf
rz 上传本地编辑的文件
chmod 644 /etc/my.cnf
  • 我的SSD盘是/cache1盘,my.inf配置了对应数据盘
mkdir -p /cache1/mysql_data
chmod 750 /cache1/mysql_data
  • 开启mysql并自启动,没报错就是启动成功,这种启动方式能自动重启, kill -9可以测试
systemctl start mysqld
systemctl enable mysqld
  • 改密码, 先看机器上初始密码,我的是qMP-Vqed_6ec,我的密码是没有特殊符合不符合安全规则,我是先随便设置了个符合的然后SET GLOBAL validate_password.special_char_count = 0;再改回来
sudo grep 'temporary password' /cache1/mysql_data/*.err
mysql -uroot -pqMP-Vqed_6ec
ALTER USER 'root'@'localhost' IDENTIFIED BY 'xxxx';
  • 配置备库读取权限
# 主库执行
CREATE USER 'repl_user'@'备库' IDENTIFIED BY '密码';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'备库';
FLUSH PRIVILEGES;

备机安装mysql8

  • 步骤基本跟上面一致,就是my.cnf配置备注部分要改
  • 也配置下读取备库(万一主从切换)权限
# 备库执行
CREATE USER 'repl_user'@'主库' IDENTIFIED BY '密码';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'主库';
FLUSH PRIVILEGES;
  • 备库要执行开启同步
CHANGE MASTER TO
MASTER_HOST='主库ip',
MASTER_PORT=设置的端口,
MASTER_USER='repl_user',
MASTER_PASSWORD='密码',
MASTER_AUTO_POSITION=1;

START SLAVE;

SHOW SLAVE STATUS\G;

主备状态查看

  • 查看主备状态具体
# 看下有没erro
1. SHOW SLAVE STATUS\G;
# 有error可能具体报错
SELECT * FROM performance_schema.replication_applier_status_by_worker\G;

mysqlrouter安装

  • 安装命令,注意看有没报错, 中途记得输入y
wget https://repo.mysql.com//mysql80-community-release-el7-7.noarch.rpm
sudo rpm -ivh mysql80-community-release-el7-7.noarch.rpm
sudo yum clean all

sudo yum install mysql-router --nogpgcheck
image.png
  • 查看版本
mysqlrouter --version
image.png
  • 修改配置文件
vim /etc/mysqlrouter/mysqlrouter.conf
  • 在某尾加上
# 写路由,所有写流量只走主库
[routing:write]
bind_address = 0.0.0.0:7001
mode = read-write
destinations = 主库:xxx

# 读路由,优先走从库,从库挂了才能fallback到主库,当然读也可以不走主库,另外拓展出一台读机器,因为给的资源有限制,主库要拿来读了
[routing:read]
bind_address = 0.0.0.0:7002
mode = read-only
destinations = 从库:xxx,主库:xxx
  • 启动
sudo systemctl start mysqlrouter
sudo systemctl enable mysqlrouter
  • 查看效果
sudo netstat -lntp | grep mysqlrouter

image.png

keepalived安装

  • 考虑到mysqlrouter单点故障,这边使用keepalived做高可用
  • 安装, 中间记得输入y,注意看有没报错
yum install keepalived
image.png
  • 看下网卡, 我的是输出eth2,如果主备keepalived机器网卡不同则virtual_ipaddress配置需不同
ip link show | grep 'state UP' | awk -F': ' '{print $2}'
  • 修改配置文件
vim /etc/keepalived/keepalived.conf
  • 配置文件数据,mysqlrouter有两台,主的设置如下
global_defs {
   router_id MYSQL_ROUTER_MASTER
}

vrrp_script check_mysqlrouter {
    script "killall -0 mysqlrouter"
    interval 2
    weight 2
}

vrrp_instance VI_1 {
    state MASTER
    interface eth2
    virtual_router_id 211
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 你的密码
    }
    track_script {
        check_mysqlrouter
    }
    virtual_ipaddress {
        你的vip地址(我这边是找公司申请的)
    }
}

  • 配置文件数据,mysqlrouter有两台,备的设置如下,我的网卡是一致的,如果你的网卡不一致要特殊配置
global_defs {
   router_id MYSQL_ROUTER_SLAVE
}

vrrp_script check_mysqlrouter {
    script "killall -0 mysqlrouter"
    interval 2
    weight 2
}

vrrp_instance VI_1 {
    state SLAVE
    interface eth2
    virtual_router_id 211
    priority 99
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass xxx须跟主保持一致
    }
    track_script {
        check_mysqlrouter
    }
    virtual_ipaddress {
        你的vip需要跟主保持一致(我这边是找公司申请的vip)
    }
}
  • 启动
# 启动服务(所有节点)
systemctl start keepalived

# 设置开机自启
systemctl enable keepalived

# 检查服务状态
systemctl status keepalived
image.png

验证vip功能

# 在主节点停止服务
systemctl stop keepalived

# 在备节点检查VIP(应自动接管),eth2 网要根据你自己的来
watch -n1 "ip addr show eth2 | grep 'inet '"

# 恢复主节点
systemctl start keepalived

# 观察VIP回切(根据preempt配置)
tail -f /var/log/keepalived.log

验证绑定, 注意eth2可能要改:
ip addr show eth2 | grep 'inet '

proxy安装

  • 由于mysqlrouter已经符合要求,并且mysqlrouter更加轻量化,故不考虑使用proxy

MHA安装

  • 目前没考虑自动主备切换,后续有需要再安装
  • 注意MHA 不会自动回切或恢复旧主
  • MySQL InnoDB Cluster中MySQL Group Replication支持旧主重新假如自动修复,带需依赖旧主恢复时间和新主保留二进制数据的时间
  • 大型mysql集群可以用
  1. MySQL InnoDB Cluster
  2. PXC多主,但是强一致性数据要求,跨集群有点蛋疼
  3. 分布式中间件(如 ProxySQL + 分片)
  4. MHA + Keepalived

Granafa监控

  • 做好监控查看各个指标

主从同步处理

主从error处理

  • 处理之前需要主从机器上面的router都把备库踢掉
pt-table-sync安装

// centos7.6,建议主备两台机器都装上,防止备升主,主降备

sudo yum install [https://repo.percona.com/yum/percona-release-latest.noarch.rpm](https://repo.percona.com/yum/percona-release-latest.noarch.rpm) 

sudo percona-release enable tools release

sudo yum install percona-toolkit

pt-table-sync --version
手动处理
  • 看下error的地方,大部分的错误是从库不小心写入数据

// 看下error

SHOW SLAVE STATUS\G;

// 看具体error

SELECT * FROM performance_schema.replication_applier_status_by_worker\G;

  • 跳过某个异常, 可能有多个, 跳过后注意看异常的表,然后执行查看具体哪张表问题,再处理,有可能下面要循环多次以解决异常

STOP SLAVE;

// 这个gtid是你从 performance_schema.replication_applier_status_by_worker看到具体的错误来的
SET GTID_NEXT = '14c92d46-3541-11f0-a4f6-90e2ba00f37c:1222';
BEGIN;
COMMIT;
SET GTID_NEXT = 'AUTOMATIC';
START SLAVE;
SHOW SLAVE STATUS\G;

自动处理
  • 使用pt-table-sync自动查看,注意有时候数据量太多会卡住,可能某张表太大卡住,这时候就要手动接入处理掉卡住的大表

// --table不配置的话就是整个库查看异同

pt-table-sync h=主库host,P=port,u=xxx,p=xxxx \
h=从库host,P=port,u=xxx,p=xxxx \
--database xxx--table xx,xxx \
--print --no-check-slave --no-transaction > repair.sql

  • 人工看下repair.sql数据确认下
  • 自动修复

// 这里我配置了不可手动写入

STOP SLAVE;

SET GLOBAL super_read_only = OFF;

// 执行修复

mysql -hxxx -Pxxx -uxx -pxxxx 库名< repair.sql

SET GLOBAL super_read_only = ON;

// 确定要跳过的gtid, 看Last_SQL_Error

SHOW SLAVE STATUS\G;

SET GTID_NEXT='xxx:123';  
BEGIN;
COMMIT;
SET GTID_NEXT='AUTOMATIC';

START SLAVE;
SHOW SLAVE STATUS\G;

主挂了从升主处理


1\. 将从库提升为新主库
- vim /etc/my.cnf
将read_only=1 super_read_only=1反向设置都为0

2\. 确认主库故障
- SHOW SLAVE STATUS\G;
- 确保 Slave_IO_Running 和 Slave_SQL_Running 均为 Yes,且 Seconds_Behind_Master 为 0(无延迟)
3\. 停止从库复制进程
在从库执行以下命令,停止复制并解除与原主库的关联
STOP SLAVE;
RESET SLAVE ALL;  -- 清除复制信息
4\. 主备的/etc/mysqlrouter/mysqlrouter.conf,router写库改掉
systemctl restart mysqlrouter

主挂了从升主之后,原主恢复变从

  • 当原主库恢复后,MHA 默认不会自动将其加入集群 ,需要人工干预或配置脚本自动处理。备份新主库数据 (确保安全)。在原主库上重建数据

  • 如果差别不大,比如binlog保存三天,只挂了一天,那就走上面提到的自动处理流程

  • 如果差异比较大执行下面步骤,注意主库数据可以定时备份


1\. 停止并重置从库
STOP SLAVE;
RESET SLAVE ALL; 

2\. 备份主库
# 主库执行(GTID 模式专用)
mysqldump -h xxx -P xx-u xxx -pxxxx \
--single-transaction --set-gtid-purged=ON \
--databases xxx> xxx_full_backup.sql

2.1 传输, 公司传输需要通过跳板机
# 跳板机执行拉
scp -P xx [root@x](mailto:root@xxx)xx:/root/xxx_full_backup.sql /home/xxxx
# 跳板机执行推
scp -P xx  xx_full_backup.sql [root@x](mailto:root@xxx)xxx:/root
# 避免重复
rm xxxx_full_backup.sql 

3\. 清空从库 xxx库, 执行前主从都要将router read去掉从库
-- 从库执行
SET GLOBAL super_read_only = OFF;
DROP DATABASE IF EXISTS xxx;
SET GLOBAL super_read_only = ON;

4\. 导入到从库
# 移除 SET GTID_PURGED 语句
sed '/GTID_PURGED/d' XXX_full_backup.sql > clean_backup.sql

可以开两个窗口
SET GLOBAL super_read_only = OFF;
mysql -uxxx -pxxxx < clean_backup.sql
SET GLOBAL super_read_only = ON;
5\. 重新链接
-- 从库执行
grep 'GTID_PURGED' xxx_full_backup.sql
STOP SLAVE;
RESET MASTER;
SET GLOBAL GTID_PURGED = 'ea6a933c-5647-11f0-afa0-e4434bb74caa:1-1485';
CHANGE MASTER TO
  MASTER_HOST = 'xxx',
  MASTER_PORT = xxx,
  MASTER_USER = 'xxx',
  MASTER_PASSWORD = 'xxxxxxx',
  MASTER_AUTO_POSITION = 1;
START SLAVE;
SHOW SLAVE STATUS\G;


my.cnf配置

  • 贴出 centos7.6机器,256G内存,64C,3.5T SSD对应的配置,主库,从库根据注释改改就好, 线上机器是join 临时表量很大超级多,所以按照下面配置了
[mysqld]
# 只同步 mydb 这个数据库
replicate-wild-do-table=xxx.%

# 不同步xxx.test
#replicate-ignore-table=xxx.test
# 兼容旧版本
default_authentication_plugin=mysql_native_password 
max_connections=3500
tmp_table_size=17179869184
max_heap_table_size=17179869184
table_open_cache=8192
innodb_buffer_pool_size=171798691840
innodb_io_capacity_max=20000
innodb_io_capacity=10000
binlog_cache_size=33554432
#expire_logs_days=1 已废弃
binlog_expire_logs_seconds=86400
long_query_time=30
innodb_flush_neighbors=0
lower_case_table_names=0
binlog_ignore_db=scheduler_task

performance_schema_instrument=wait/lock/metadata/sql/mdl=ON
default_authentication_plugin=mysql_native_password
#query_cache_size=0 已废弃
#query_cache_type=0 已废弃
relay_log_info_repository=TABLE
master_info_repository=TABLE
explicit_defaults_for_timestamp=1
key_buffer_size=4G
server_id=12502990
report_port=ss
report_host=你的ip
port=ss
datadir=/cache1/mysql_data
socket=/cache1/mysql_data/mysql.sock
log_error=/cache1/mysql_data/mysql_error.err
pid_file=/cache1/mysql_data/mysqld.pid
slow_query_log=1
slow_query_log_file=slow_query.log
#log_bin=mysql-bin
relay_log=mysql-relay-bin
relay_log_space_limit=10737418240
general_log=0
general_log_file=mysql-general.log
binlog_format=ROW
sync_binlog=0
log_slave_updates=1
# 主库两个都设置0
read_only=0
super_read_only=0

event_scheduler=0
transaction_isolation=REPEATABLE-READ
max_allowed_packet=64M
sort_buffer_size=32M
read_buffer_size=64M
read_rnd_buffer_size=32M
join_buffer_size=32M
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
group_concat_max_len=64K
innodb_stats_on_metadata=0
innodb_file_per_table=1
thread_cache_size=1024
skip_external_locking
skip_name_resolve
innodb_log_file_size=256M
innodb_flush_log_at_trx_commit=2
innodb_log_buffer_size=16M
character_set_server=utf8
log_bin_trust_function_creators=1
open_files_limit=60000
secure_file_priv=''
slave_net_timeout=30
binlog_error_action=IGNORE_ERROR
#show_compatibility_56=on
#log_warnings=1
optimizer_switch='semijoin=OFF'
gtid_mode=ON
enforce_gtid_consistency=ON
mysqlx=0

[mysql]
no_auto_rehash
prompt="\u \d>"
[mysqldump]
quick

[client]
socket=/cache1/mysql_data/mysql.sock


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容