搭建MySQL高可用集群
项目描述
项目名称:MySQL高可用主从复制集群
项目环境:CentOS(7.6.2003),MySQL(5.7.29),MySQL Router(8.0.21),Keepalived (v1.3.5),Ansible(2.9.13),Zabbix(4.4.6),nginx(1.19.2)
项目描述:利用Keepalived构建一个高可用MySQL集群,提供读写分离、主从复制、自动故障切换功能,使用Ansible实现自动化运维,使用Zabbix对集群进行监控。
项目步骤:
1. 准备6台虚拟机,做好初试化,如修改主机名、关闭防火墙、配置静态ip;
2. 管理主机ADMIN安装Ansible,配置管理服务器到其它所有机器的ssh免密通道;
3. 在所有主机上安装好相应的服务
* 所有服务器上安装Zabbix-agent
* 管理主机上安装Zabbix-server
* MYSQL-ROUTER-* 上安装MySQL-router
* MYSQL-MASTER、MYSQL-SLAVE-*上安装MySQL
4. 在MySQL集群服务器上配置好主从复制,一主二从;
5. 在MYSQL-ROUTER节点上配置读写分离;
6. 在MYSQL-ROUTER节点上安装好Keepalived,做好相关配置,设置好vip,实现高可用;
7. 在zabbix里配置好监控所有机器的cpu,内存,磁盘,网络带宽,MySQL服务的自定义监控项目(并发等参数的监控)以及微信告警。
8. 模拟MHA的思路,编写主从切换的监控脚本,实现自动的主从切换,提升另外的一台slave为master,其他的slave成为新的master的从。
遇到的问题:配置MySQL主从复制时Slave_IO_Running状态为No
故障原因:主从服务器上的MySQL来自同一个镜像,UUID一致
解决方式:删除auto.cnf,重新获取UUID
项目心得:通过这个项目对HA和负载均衡,读写分离有了更加深刻的认识,因为步骤比较多,需要细心,也锻炼了自己的troubleshooting的能力,编写类似MHA的主从切换故障转移的脚本,对主从复制有了更加深刻的了解。
拓扑结构
环境配置
配置 | 参数 |
---|---|
OS | CentOS Linux release 7.8.2003 (Core) |
disk | 20G |
memory | 512M |
MySQL | 5.7.29 |
MySQL Router | 8.0.21 |
Keepalived | Keepalived v1.3.5 (03/19,2017) |
Ansible | ansible 2.9.13 |
Zabbix | 4.4.6 |
NGINX | 1.19.2 |
ADMIN | 192.168.1.101 |
MYSQL-ROUTER 1 | 192.168.1.102 |
MYSQL-ROUTER 2 | 192.168.1.103 |
MYSQL-MASTER | 192.168.1.104 |
MYSQL-SLAVE-1 | 192.168.1.105 |
MSYQL-SLAVE-2 | 192.168.1.106 |
VIP(virtual ip) | 192.168.1.111 |
详细操作
一、准备工作
# 修改主机名
# 临时修改
hostname xxx
# 永久修改
hostnamectl set-hostname xxx
# 关闭NetworkManager,并禁止开机自启
systemctl stop NetworkManager
systemctl disable NetworkManager
# 修改网卡脚本,配置静态ip
yum install vim -y
vim /etc/sysconfig/network-scripts/ifcfg-ens33
# 重启服务
service network restart
# 关闭防火墙和selinux,并禁止开机自启
service firewalld stop
systemctl disable firewalld.service
setenforce 0
sed -i "s/SELINUX=enforcing/SELINUX=disabled/" /etc/selinux/config
二、安装Ansible
1. 配置免密通道
# 在主机A上使用命令将主机A的公钥传输至主机B,以实现主机A免密访问主机B
ssh-keygen
ssh-copy-id -i ~/.ssh/id_rsa.put root@192.168.8.101
# 或将主机A的公钥复制到主机B的~/.ssh/authorized_keys文件中实现主机A免密访问主机B
2. 安装Ansible
# 安装epel源
[root@admin ~]# yum install epel-release -y
# 安装ansible
[root@admin ~]# yum install ansible -y
# 查看ansible版本,是否安装成功
[root@admin ~]# ansible --version
3. 配置主机清单
[root@admin ~]# cat >> /etc/ansible/hosts <<EOF
[HA]
192.168.8.102
192.168.8.103
[MySQL]
192.168.1.104
192.168.1.105
192.168.1.106
EOF
三、安装在各主机上安装相应的服务
1. 编写MySQL编译安装脚本mysql_setup.sh
echo '#################################################'
echo '开始安装MySQL'
# 下载依赖包
yum install cmake ncurses-devel gcc gcc-c++ bzip2 openssl-devel -y
# 新建一个无家目录且禁止登录的用户mysql,这个用户是linux系统用来启动MySQL的。
useradd -r -s /sbin/nologin mysql
# 新建一个给MySQL存放数据的目录
mkdir -p /data/mysql
# 修改数据目录的属主为mysql用户
chown mysql:mysql /data/mysql
# 下载源码包
curl -O https://downloads.mysql.com/archives/get/p/23/file/mysql-community-5.7.29-1.el7.src.rpm
# 解压源码包
rpm -ivh mysql-community-5.7.29-1.el7.src.rpm
# 进入存放真正源码包的目录
cd rpmbuild/SOURCES
# 解压mysql-5.7.29.tar.gz,就是源码所在的压缩包。还有一个boost_1_59_0.tar.bz2包,Boost是为C++语言标准库提供扩展的一些C++程序库的总称。
tar xf mysql-5.7.29.tar.gz
tar xf boost_1_59_0.tar.bz2
# 将解压后的boost包目录移动到解压后的mysql包目录下
mv boost_1_59_0 mysql-5.7.29
# 进入解压后的mysql包
cd mysql-5.7.29
#进行编译前的配置
cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DMYSQL_DATADIR=/data/mysql -DSYSCONFDIR=/etc -DMYSQL_USER=mysql -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci -DWITH_BOOST=boost_1_59_0
# 编译
make
# 安装
make install
# 备份,并清空配置文件
cp /etc/my.cnf /root/mysql.cnf.bak &>/dev/null
>/etc/my.cnf
# 重置配置文件
cat >/etc/my.cnf << EOF
[mysqld_safe]
log-error=/var/log/mysql/mysql.log
[client]
socket=/tmp/mysql.sock
[mysqld]
socket=/tmp/mysql.sock
port = 3306
open_files_limit = 8192
innodb_buffer_pool_size = 512M
[mysql]
auto-rehash
prompt=\\u@\\d \\R:\\m mysql>
EOF
# 创建MySQL日志文件目录
mkdir -p /var/log/mysql
chown mysql:mysql /var/log/mysql
# 初始化MySQL
# 进入编译安装好的mysql的目录(安装目录)
cd /usr/local/mysql/bin
# 执行mysqld这个程序,初始化mysql,并且将日志和临时密码重定向到/root/temp_password.txt文件里
./mysqld --initialize --user=mysql --basedir=/usr/local/mysql/ --datadir=/data/mysql &>/root/temp_password.txt
# 将新的PATH变量重定向到/etc/bashrc文件(下次开机生效)
echo 'PATH=$PATH:/usr/local/mysql/bin' >>/etc/bashrc
# 刷新环境变量
#source /etc/bashrc
PATH=$PATH:/usr/local/mysql/bin
# 拷贝mysqld的程序文件到指定的目录,方便后面设置mysqld服务开机启动。
# 加斜杠直接覆盖不提示
\cp ../support-files/mysql.server /etc/init.d/mysqld
#关闭防火墙firewalld服务
service firewalld stop &>/dev/null
#设置firewalld服务开机不启动
systemctl disable firewalld &>/dev/null
#临时关闭selinux
setenforce 0 &>/dev/null
#永久修改selinux配置文件里的内容
sed -i 's/=enforcing/=disabled/g' /etc/selinux/config &>/dev/null
# 设置开机启动MySQL
chkconfig --add mysqld
# 启动MySQL
service mysqld start
#从保存的临时密码文件里,截取出临时密码,赋值给一个变量temp_pwd
temp_pwd=$(cat /root/temp_password.txt |tail -1|awk '{print $11}')
#给MySQL设置密码为MySqlroot123#
mysql -uroot -p$temp_pwd --connect-expired-password -e "set password='MySqlroot123#'"
echo '###### congratulation! your mysql has be installed successfully ######'
2. 编写MySQL-router安装脚本
MySQL Router安装脚本mysql_router_setup.sh。
# 下载安装CentOS7版本的rpm包
wget https://dev.mysql.com/get/Downloads/MySQL-Router/mysql-router-community-8.0.21-1.el7.x86_64.rpm
rpm -ivh mysql-router-community-8.0.21-1.el7.x86_64.rpm
3. 安装Zabbix
在ADMIN上搭建LNMP环境,安装Zabbix-server
# 下载所需要的包
[root@admin ~]# mkdir -p zabbix
[root@admin ~]# cd zabbix
[root@admin ~]# curl -O https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/zabbix-agent-4.4.6-1.el7.x86_64.rpm
[root@admin ~]# curl -O https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/zabbix-get-4.4.6-1.el7.x86_64.rpm
[root@admin ~]# curl -O https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/zabbix-java-gateway-4.4.6-1.el7.x86_64.rpm
[root@admin ~]# curl -O https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/zabbix-js-4.4.6-1.el7.x86_64.rpm
[root@admin ~]# curl -O https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/zabbix-proxy-mysql-4.4.6-1.el7.x86_64.rpm
[root@admin ~]# curl -O https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/zabbix-sender-4.4.6-1.el7.x86_64.rpm
[root@admin ~]# curl -O https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/zabbix-server-mysql-4.4.6-1.el7.x86_64.rpm
[root@admin ~]# curl -O https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/frontend/zabbix-nginx-conf-scl-4.4.6-1.el7.noarch.rpm
[root@admin ~]# curl -O https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/frontend/zabbix-web-4.4.6-1.el7.noarch.rpm
[root@admin ~]# curl -O https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/frontend/zabbix-web-japanese-4.4.6-1.el7.noarch.rpm
[root@admin ~]# curl -O https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/frontend/zabbix-web-mysql-scl-4.4.6-1.el7.noarch.rpm
[root@admin ~]# curl -O https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/frontend/zabbix-web-deps-scl-4.4.6-1.el7.noarch.rpm
[root@admin ~]# yum install zabbix-* -y
# 安装MySQL(Mariadb)
[root@admin ~]# yum install mariadb mariadb-server -y
[root@admin ~]# service mariadb restart
[root@admin ~]# ps -ef | grep mysqld
# 授权zabbix这个用户可以进入mariadb
[root@admin ~]# mysql
> create database zabbix character set utf8 collate utf8_bin;
> grant all privileges on zabbix.* to zabbix@localhost identified by 'zabbix123';
# 导入数据到zabbix库
[root@admin ~]# cd /usr/share/doc/zabbix-server-mysql-4.4.6/
[root@admin ~]# gunzip create.sql.gz
[root@admin ~]# mysql -uzabbix -p'zabbix123' zabbix < create.sql
# 修改zabbix_server.conf的数据库配置
[root@admin ~]# vim /etc/zabbix/zabbix_server.conf
DBHost=localhost
DBName=zabbix
DBUser=zabbix
DBPassword=zabbix123
DBSocket=/data/mysql/mysql.sock
DBPort=3306
# 启动服务
[root@admin ~]# service zabbix-server start
[root@admin ~]# systemctl enable zabbix-server
# 查看10051端口是否启动
[root@admin ~]# netstat -ntpl | grep 10051
其他主机作为被监控机,安装zabbix-agent
# 管理主机上使用ansible批量安装zabbix-agent
ansible all -m copy -a "src=./zabbix/zabbix-agent-4.4.6-1.el7.x86_64.rpm dest=/root/"
ansible all -m shell -a "yum install ~/zabbix-agent-* -y"
# 修改配置文件,运行zabbix-server过来采集数据
ansible all -m shell -a "sed -i 's/Server=127.0.0.1/Server=192.168.1.101/g' /etc/zabbix/zabbix_agentd.conf"
ansible all -m shell -a "sed -i 's/ServerActive=127.0.0.1/ServerActive=192.168.1.101/g' /etc/zabbix/zabbix_agentd.conf"
# 启动服务
ansible all -m service -a 'name=zabbix-agent state=started'
# 查看10050端口是否启动
ansible all -m shell -a "netstat -ntpl | grep 10050"
启动zabbix-web服务
# 管理主机安装nginx(这里直接粘贴我之前写的脚本)
!/bin/bash
yum -y install zlib zlib-devel openssl openssl-devel pcre pcre-devel gcc gcc-c++ autoconf automake make
useradd nginx -s /sbin/nologin
curl -O http://nginx.org/download/nginx-1.19.2.tar.gz
tar xf nginx-1.19.2.tar.gz
cd nginx-1.19.2
./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_realip_module --with-http_ssl_module --with-pcre --with-stream
make -j2 && make install
export PATH=$PATH:/usr/local/nginx/sbin/
echo 'export PATH=$PATH:/usr/local/nginx/sbin/' >>/etc/profile
# 启动nginx
/usr/local/nginx/sbin/nginx
echo 'nginx' >> /etc/rc.d/rc.local
chmod +x /etc/rc.d/rc.local
netstat -ntpl | grep 80
# 修改管理主机上zabbix前端配置的时区
[root@admin ~]# vim /etc/php-fpm.d/zabbix.conf
php_value[date.timezone] = Asia/Shanghai
# 使用nginx——》LNMP环境
[root@admin ~]# systemctl restart php-fpm
[root@admin ~]# systemctl enable php-fpm
# 修改nginx配置
[root@admin ~]# vim /etc/nginx/conf.d/zabbix.conf
server {
listen 80;
server_name www.Charramma.com
...
}
[root@admin ~]# vim /etc/nginx/conf.d/zabbix.conf
http {
include /etc/nginx/conf.d/zabbix.conf
...
}
# 重启nginx服务
[root@admin ~]# /usr/local/nginx/sbin/nginx -s reload
# 测试连通性
[root@admin ~]# zabbix_get -s 192.168.1.73 -p 10050 -k "system.cpu.load[all,avg1]"
0.060000
在Windows主机上的hosts文件中添加192.168.1.101 www.charramma.com
访问http://charramma.com/setup.php
账户:Admin
密码:zabbix
4. 编写playbook
编写playbook,安装MySQL、Keepalived、MySQL Router
service_setup.yml
- hosts: MySQL,HA
remote_user: root
tasks:
- name: install epel
yum:
name: epel-release
state: latest
- hosts: HA
remote_user: root
tasks:
- name: install keepalived
yum:
name: keepalived
state: latest
- name: keepalived service start
service:
name: keepalived
state: started
enabled: true
- name: mysql router setup
script: ./mysql_router_setup.sh
- hosts: MySQL
remote_user: root
tasks:
- name: mysql setup script copy
copy:
src: ./mysql_setup.sh
dest: /root
- name: mysql setup
shell: source /root/mysql_setup.sh
执行yml
[root@admin ~]# ansible-playbook service-setup.yml
至此,所需要的服务全部安装完成
四、MySQL集群配置主从复制
在MySQL集群上配置主从复制、一主二从
1. 开启二进制日志
mkdir -p /data/mysql/bin_log
chown -R mysql.mysql /data/mysql
vim /etc/my.cnf
[mysqld]
log_bin=/data/mysql/bin_log/myql_binlog
server_id=1
# 三台主机server_id各不相同
service mysqld restart
2. 配置主从复制
mysql-master上添加用于复制的用户
> grant replication slave on *.* to 'Tom'@'192.168.1.105' identified by 'MySqlTom123#';
> grant replication slave on *.* to 'Tom'@'192.168.1.106' identified by 'MySqlTom123#';
> flush privileges;
备份主服务器上的数据
[root@mysql-master ~]# mysqldump -uroot -p -B --all-databases > backup.sql
[root@mysql-master ~]# scp backup.sql root@192.168.1.105
[root@mysql-master ~]# scp backup.sql root@192.168.1.106
从服务器上导入数据
[root@mysql-slave-1 ~]# mysql -uroot -p < backup.sql
[root@mysql-slave-2 ~]# mysql -uroot -p < backup.sql
主服务器上查看当前二进制文件的名字和位置号
[root@mysql-master ~]# mysql -uroot -p
mysql>flush logs;
mysql>show master status;
+---------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------------+----------+--------------+------------------+-------------------+
| mysql_binlog.000001 | 154 | | | |
+---------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
从服务器配置主服务器信息
[root@mysql-slave ~]# mysql -uroot -p
mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.73',
-> MASTER_USER='Tom',
-> MASTER_PASSWORD='MySqlTom123#',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='mysql_binlog.000001',
-> MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.00 sec)
mysql> start slave;
mysql> show slave status \G;
*************************** 1. row ***************************
...
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
1 row in set (0.00 sec)
Slave_IO_Running
和Slave_SQL_Running
都是Yes,说明主从复制已经配置好了
五、配置读写分离
修改mysql-router的配置文件
[root@mysql-router-1 ~]# cat >> /etc/mysqlrouter/mysqlrouter.conf << EOF
[routing:read_write]
bind_address = 192.168.1.112 # mysql-router节点的ip
bind_port = 7001
mode = read-write
destinations = 192.168.1.114:3306 # mysql-master 用于读写
max_connect_errors = 65535
max_connetc_timeout = 9
[routing:read_only]
bind_address = 192.168.1.112 # mysql-router节点的ip
bing_port = 7002
mode = read-only
destinations = 192.168.1.115:3306,192.168.1.116:3306
max_connect_errors = 65535
max_connetc_timeout = 9
EOF
启动服务
[root@mysql-router-1 ~]# systemctl start mysqlrouter
[root@mysql-router-1 ~]# netstat -ntpl | grep mysqlrouter
tcp 0 0 192.168.1.112:7001 0.0.0.0:* LISTEN 4511/mysqlrouter
tcp 0 0 192.168.1.112:7002 0.0.0.0:* LISTEN 4511/mysqlrouter
mysql-router-2同样如此操作
六、配置高可用
mysql-router节点上配置keepalievd实现高可用
[root@mysql-router-1 ~]# vim /etc/keepalived/keepalived.conf
global_defs {
# 注释掉下面这一行
vrrp_strict
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.1.111
}
}
# 删掉下面所有内容
[root@mysql-router-2 ~]# vim /etc/keepalived/keepalived.conf
global_defs {
# 注释掉下面这一行
vrrp_strict
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 99
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.1.111
}
}
# 删掉下面所有内容
重启服务
service keepalived start
将vip绑定到MySQL-router上
vim /etc/mysqlrouter/mysqlrouter.conf
# 将bind_address改为192.168.1.111
# 重启mysql-router
systemctl restart mysql-router
未完成,有时间再补全。。。-_-||