基于Docker搭建MySQL主從復制架構(gòu)實踐
下面,直接進入主題,如果還沒接觸過Docker的朋友,建議先去學習一下Docker。Docker對于個人開發(fā)者來說也是一大神器,會大大降低我們很多學習成本,比如搭建各種組件環(huán)境等。
創(chuàng)建網(wǎng)段
因為是搭建一個主從復制架構(gòu),master和slave數(shù)據(jù)庫都需要進行網(wǎng)絡通信,所以需要保證master和slave的網(wǎng)絡是通的。
我們可以基于Docker模擬一個內(nèi)網(wǎng)網(wǎng)段。如下,創(chuàng)建mysql-replication網(wǎng)絡:
docker network create mysql-replication
查看剛才創(chuàng)建的網(wǎng)絡:
docker network inspect mysql-replication
輸出內(nèi)容如下:
[{"Name":"mysql-replication","Id":"8e0e22b80aff26987986959c2814fa90a2b390f2de36020f7c245d79a308bc91","Created":"2021-02-20T10:08:28.364053029+08:00","Scope":"local","Driver":"bridge","EnableIPv6":false,"IPAM":{"Driver":"default","Options":{},"Config":[{"Subnet":"172.29.0.0/16","Gateway":"172.29.0.1"}]},"Internal":false,"Attachable":false,"Ingress":false,"ConfigFrom":{"Network":""},"ConfigOnly":false,"Containers":{},"Options":{},"Labels":{}}]
這樣我們就創(chuàng)建好了網(wǎng)絡,模擬了一個內(nèi)網(wǎng)網(wǎng)段。
創(chuàng)建mysql容器
1.拉取mysql鏡像
這里我們以拉去5.7版本為例
docker pull mysql:5.7
2.啟動兩個mysql容器
啟動mysql容器,命名為mysql-a
docker run -d \--network=mysql-replication \--name=mysql-a \-p 3308:3306 \-v /root/mysql-replication-test/mysql-a/data:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD=root mysql:5.7
啟動mysql容器,命名為mysql-b
docker run -d \--network=mysql-replication \--name=mysql-b \-p 3309:3306 \-v /root/mysql-replication-test/mysql-b/data:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD=root mysql:5.7
這樣,我們就啟動了兩個mysql容器了,并且都處于mysql-replication這個網(wǎng)絡下。
搭建主從
我們讓mysql-a擔任Master角色
數(shù)據(jù)準備
查看mysql-a、mysql-b的ip
docker inspect mysql-a | grep "IPAddress"docker inspect mysql-b | grep "IPAddress"
mysql-a的ip=172.29.0.2,mysql-b的ip=172.29.0.3
修改master數(shù)據(jù)庫配置
進入mysql容器修改配置
docker exec-ti mysql-a bash
然后修改配置:
設置mysql id
開啟binlog日志
vim /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]pid-file =/var/run/mysqld/mysqld.pidsocket =/var/run/mysqld/mysqld.sockdatadir =/var/lib/mysql#log-error = /var/log/mysql/error.log# By default we only accept connections from localhost#bind-address = 127.0.0.1# Disabling symbolic-links is recommended to prevent assorted security riskssymbolic-links=0### 配置mysql id,要確保主從的id不同server-id=100### 開啟binlog日志log-bin=mysql-bin
重啟mysql-a容器,讓配置生效
docker restart mysql-a
重新登錄mysql-a的mysql,執(zhí)行show master status查看當前狀態(tài),后面配置slave mysql需要用到,這里我們查到:
我們后面會用到File和Position字段的值
master數(shù)據(jù)庫創(chuàng)建同步用戶
在master mysql上面,創(chuàng)建一個用戶,用于同步數(shù)據(jù)。
# 創(chuàng)建用戶slave_01,密碼是salve_01,允許ip為172.29.0.*的機器同步數(shù)據(jù)create user 'slave_01'@'172.29.0.%' identified by'slave_01';# 授權grant replication slave on *.* to 'slave_01'@'172.29.0.%';# 生效flush privileges;
備份master數(shù)據(jù)庫到slave數(shù)據(jù)庫
如果master數(shù)據(jù)庫沒有需要同步備份到從數(shù)據(jù)庫的數(shù)據(jù),這一步可以不處理。
在mysql-a容器里,執(zhí)行命令:
mysqldump --single-transaction -uroot -p --master-data=2-A>dump.sql
這樣在當前目錄就可以看到了dump.sql,把dump.sql文件移動到和宿主機共享的目錄:
mv dump.sql /var/lib/mysql
退出mysql-a容器,到dump.sql目錄拷貝dump.sql到容器mysql-b:
docker cp dump.sql b2a06688fe70:/
其中,b2a06688fe70是mysql-b容器的id。
登錄mysql-b,導入備份數(shù)據(jù):
docker exec-ti mysql-b bash# 登錄mysqlmysql -u root -p# 登錄上mysql后,執(zhí)行備份sqlsource /dump.sql
這樣,我們就把mysql-a的數(shù)據(jù)備份到mysql-b。
修改slave數(shù)據(jù)庫配置
修改mysql配置文件:
vim /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]pid-file =/var/run/mysqld/mysqld.pidsocket =/var/run/mysqld/mysqld.sockdatadir =/var/lib/mysql#log-error = /var/log/mysql/error.log# By default we only accept connections from localhost#bind-address = 127.0.0.1# Disabling symbolic-links is recommended to prevent assorted security riskssymbolic-links=0# 設置salve mysql id,不和master重復server-id=101# 開啟并配置slave的binlog文件名稱log-bin=mysql-slave-bin# 配置binlog中繼文件log-bin=mysql-slave-bin
重啟mysql-b,讓配置生效:
docker restart mysql-b
配置從庫從主庫復制數(shù)據(jù):
change master to master_host='172.29.0.2',master_user='slave_01',master_password='slave_01',master_port=3306,master_log_file='mysql-bin.000001',master_log_pos=154,master_connect_retry=30
master_host:master的host
master_user:用于復制數(shù)據(jù)用的賬號
master_password:用戶復制數(shù)據(jù)用的賬號密碼
master_port:master的端口
masterlogfile:master的binlog的File名稱,在show master status命令可以查出來
masterlogpost:master的binlog的Position,在show master status命令可以查出來
masterconnectretry:連接重試時間,單位:秒
開啟主從復制:
start slave;
查看開啟狀態(tài):
show slave status \G;
如果看到:
SlaveSQLRunning: YES
SlaveIORunning: YES
SlaveSQLRunning_State: Slave has read all relay log; waiting for more updates
那么主從復制就已經(jīng)配置完成了。
驗證是否完成主從復制
我們可以在mysql-a添加一條數(shù)據(jù),然后到mysql-b上面看,是不是有新添加的數(shù)據(jù)。
有就表示主從復制已經(jīng)完成,沒有就表示主從復制沒有完成。
半同步復制優(yōu)化
我們到這里是搭建好了MySQL的主從復制,但是有個問題,它是異步復制的。在一些極端條件下會導致數(shù)據(jù)問題。比如master插入一條數(shù)據(jù)并成功提交事務了,這個時候binlog還沒有同步到slave,master就宕機了。當主從發(fā)生切換后,新的master是沒有舊的master新插入的那條數(shù)據(jù)的。
解決這個問題,業(yè)界有個方案:半同步。這里不展開說半同步的原理,只說怎么實現(xiàn)半同步主從復制。
安裝半同步插件
在master上安裝半同步插件:
# 安裝插件install plugin rpl_semi_sync_master soname 'semisync_master.so';# 開啟插件setglobal rpl_semi_sync_master_enabled=1;# 查詢是否開啟了半同步,Rpl_semi_sync_master_status=ON表示半同步開啟show status like 'Rpl%';
配置mysql重啟后加載半同步插件:
vim /etc/mysql/mysql.conf.d/mysqld.cnf
# 半同步插件加載plugin-load=rpl_semi_sync_master=semisync_master.so# 打開主的半同步rpl_semi_sync_master_enabled=1
在slave上安裝半同步插件:
# 安裝插件install plugin rpl_semi_sync_slave soname 'semisync_slave.so'# 開啟插件setglobal rpl_semi_sync_slave_enabled=1;# 重啟同步線程stop slave io_thread;start slave_io_thread;# 查詢是否開啟了半同步,Rpl_semi_sync_slave_status=ON表示半同步開啟show status like 'Rpl%';
配置mysql重啟加載半同步插件:
vim /etc/mysql/mysql.conf.d/mysqld.cnf
# 從庫半同步插件加載plugin-load=rpl_semi_sync_slave=semisync_slave.so# 打開從的半同步rpl_semi_sync_slave_enabled=1
到這里就開啟了半同步。
從庫設置為只讀
我們配置主從復制的時候,一般是不允許從庫寫入的,這樣會導致數(shù)據(jù)不一致,因為從庫數(shù)據(jù)無法同步給到主庫。所以我們一般會把從庫設置為只讀。
# 查看只讀狀態(tài),read_only=ON是開啟,OFF是關閉show global variables like "%read_only%";# 給所有表加上讀鎖flush tables with read lock;# 設置只讀setglobal read_only=1;# 如果想解除只讀,執(zhí)行下面兩行命令即可unlock tables;setglobal read_only=0;
注意點
我們安裝的mysql容器,是沒有vim工具的,需要我們自行安裝,安裝步驟:
apt-get updateapt-get install vim
