本文記錄了搭建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 sql_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應用與實戰教程