本文记录了搭建mysql一主二从集群,这样的一个集群master为可读写,slave为只读。过程中使用了docker,便于快速搭建单体mysql。
1,准备docker
docker的安装可以参考之前基于yum安装docker的文章[1]。
容器相关命令[2]。
查看正在运行的容器
docker ps
查看所有容器(查看正在运行的和已经停止运行的)
docker ps –a
docker ps -all
查看最后一次运行的容器
docker ps –l
查看停止的容器
docker ps -f status=exited
创建容器
docker run 参数 镜像名称:镜像标签 /bin/bash
-i:表示运行容器,如果不加该参数那么只是通过镜像创建容器,而不启动。
-t:表示容器启动后会进入其命令行。加入这两个参数后,容器创建就能登录进去。即分配一个伪终端(如果只加it两个参数,创建后就会自动进去容器)。
-d:在run后面加上-d参数,则会创建一个守护式容器在后台运行(这样创建容器后不会自动登录容器)。
--name :为创建的容器命名。
-v:表示目录映射关系(前者是宿主机目录,后者是映射到宿主机上的目录),可以使用多个-v做多个目录或文件映射。注意:最好做目录映射,在宿主机上做修改,然后共享到容器上。
-p:表示端口映射,前者是宿主机端口,后者是容器内的映射端口。可以使用多个-p做多个端口映射,例如:可以将Docker中Tomcat容器的8080端口映射到宿主机上的某一个端口8080,那么以后访问tomcat只需要:http://宿主机的IP:8080/
进入容器之后,初始化执行的命令:/bin/bash;可写可不写
删除指定的容器
#删除容器
docker rm 容器名称(容器ID)
#删除镜像
docker rmi 镜像ID(镜像名称)
2,跑起来3台mysql容器
搜索mysql镜像
docker search mysql
拉取mysql8镜像
docker pull mysql:8.0.29
注意:如果防火墙是开启的,需要关闭防火墙,容器才能启动。
运行3台msyql容器
master
docker run -d \
-p 3311:3306 \
-v /usr/local/docker-mount/mysql-master1/conf:/etc/mysql/conf.d \
-v /usr/local/docker-mount/mysql-master1/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name mysql-master1 \
mysql:8.0.29
slave1
docker run -d \
-p 3312:3306 \
-v /usr/local/docker-mount/mysql-slave1/conf:/etc/mysql/conf.d \
-v /usr/local/docker-mount/mysql-slave1/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name mysql-slave1 \
mysql:8.0.29
slave2
docker run -d \
-p 3313:3306 \
-v /usr/local/docker-mount/mysql-slave2/conf:/etc/mysql/conf.d \
-v /usr/local/docker-mount/mysql-slave2/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name mysql-slave2 \
mysql:8.0.29
这样,通过docker,我们就快速部署了3台mysql容器。
3,进入容器,搭建集群
进入容器,修改root密码。
下面示例的是master容器
docker exec –it mysql-master1 /bin/bash
进入容器的bash后,通过mysql -uroot -p
,即可进入mysql的命令行模式。
修改默认密码校验方式
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
slave1、slave2同理,修改root密码。
给3台容器配置不同的server-id
我们找到之前容器挂载的conf目录,在其中vim my.cnf
vim /usr/local/docker-mount/master1/conf/my.cnf
[mysqld]
# 服务器唯一id,默认值1
server-id=1
# 设置日志格式,默认值ROW
binlog_format=STATEMENT
vim /usr/local/docker-mount/slave1/conf/my.cnf
[mysqld]
# 服务器唯一id,每台服务器的id必须不同,如果配置其他从机,注意修改id
server-id=2
vim /usr/local/docker-mount/slave2/conf/my.cnf
[mysqld]
server-id=3
重启3台容器
需要配置的配置文件,到此已经结束,所以这里需要重新启动mysql容器,将修改的配置读取。命令如下,最后跟上容器名字或者id即可。
docker restart mysql-master1
在主库上创建从库同步账号
在主数据库上, 创建一个允许从数据库来访问的用户账号
用户: master_slave
密码:123456
主从复制使用 REPLICATION SLAVE
赋予权限
-- 创建slave用户
CREATE USER 'master_slave'@'%';
-- 设置密码
ALTER USER 'master_slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
-- 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'master_slave'@'%';
-- 刷新权限
FLUSH PRIVILEGES;
锁住主库,记住master_log_pos
主库的bin log需要同步到从库的中继日志relay log中。(bin log是一种记录了mysql所有DDL DML语句的二进制日志文件,而relay log从bin log接收了DDL DML语句后,在从库上执行,得到与主库相同的数据。)因此在搭建的时候,主库不能再接受数据,以免造成数据的不一致。
锁住主库,在master1上执行如下命令
-- 执行以下命令锁定数据库以防止写入数据。
FLUSH TABLES WITH READ LOCK;
在主机查看mater状态
show master status;
在从库上change master
在2台从库上执行如下命令
CHANGE MASTER TO MASTER_HOST='192.168.184.129',
MASTER_USER='master_slave',MASTER_PASSWORD='123456', MASTER_PORT=3311,
MASTER_LOG_FILE='binlog.000003',MASTER_LOG_POS=1345;
注意,MASTER_HOST、MASTER_PORT为主库的ip和端口(容器映射出来的端口,如我的这个是3311),前面申请的用来同步的用户和密码,以及最重要的,MASTER_LOG_FILE和MASTER_LOG_POS,这2个需要在主库锁住之后执行show master status查看,并填入对应的数值,如果对应不上,就会在SQL线程上出现问题,进而无法主从同步、
开启主从
start slave;
查看从库状态,看看pos和file和主库是否一致
show slave status\G;
如果一切正常,到了这里,已经主从同步了,可以在主库上尝试建表插数据,并且在从库上读,看看能否读到。
如果读不到,看看slave的IO_RUNNING和SQL_RUNNING是否为NO。如果是NO,那就是有问题,可以看接下来的踩坑记录,或者show slave status给出的结果中,有一些信息提示如error或state可以仔细观察下,也许能发现一些线索。
如果正常的话,最后不要忘记,回到主库把锁解掉
unlock tables;
安装过程中的踩坑
在安装的过程中,踩了不少的坑,记录如下。
1,挂载不要挂错。
有一些可能是docker挂载的时候没挂对,导致数据出现混乱,这个我建议大家最好还是在执行复杂命令之前把命令记下来反复核对,没问题再执行。
2,IO为NO
我遇到了这个问题,排查出是这个slave的server-id没有配置,无法识别这个slave,所以无法进行IO.
3,SQL为NO
问题到了这里,就开始比较复杂了。SQL线程跑不起来,可能有很多的原因,一般比较常见的就是pos没对上,解决方法如下
mysql> slave stop;
mysql> set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
mysql> slave start;
或者在slave上手动同步一次。
stop slave;
CHANGE MASTER TO MASTER_HOST='192.168.184.129',
MASTER_USER='master_slave',MASTER_PASSWORD='123456', MASTER_PORT=3311,
MASTER_LOG_FILE='binlog.000003',MASTER_LOG_POS=1345;
start slave;
如果还是解决不了的话,可以重新开始生成主库的binlog和从库的relay log
。
-- 在从机上执行。功能说明:用于删除SLAVE数据库的relaylog日志文件,并重新启用新的relaylog文件。
reset slave;
-- 在主机上执行。功能说明:删除所有的binglog日志文件,并将日志索引文件清空,重新开始所有新的日志文件。
-- 用于第一次进行搭建主从库时,进行主库binlog初始化工作;
reset master;
我这里当时忘记了reset master/slave,所以我直接把挂载目录清空并重新做了个容器,解决了问题。
过程中还尝试过直接启动sql线程,失败(因为有问题所以起不来,再次重启当然也起不来,毕竟问题还在那儿)。
start slave io_thread;
查看error_log,在mysql中执行如下命令
show variables like '%log_error%';
但是发现mysql容器是直接把错误输出在控制台?可是我没有看到error输出啊,于是去slave的挂载目录的my.cnf中指定了一下error_log路径。
[mysqld]
server-id=2
log-error=/var/log/mysqld.log
但是发现error log中还真的是没有error,只有2个无关紧要的warning,于是这条路走失败了。
后来分析很有可能就是relay log的问题,reset slave也许就能直接解决问题。
参考资料:
[1],【Docker】基于yum安装docker
[2],mycat应用与实战教程