Mysql分散式部署 - 多級複製

weixin_34208283發表於2018-02-11

1,概述

1.1,Mysql主從複製的常用體系結構基本原則

  • 每個Slave只能有一個 Master;
  • 每個Master或Slave只能有一個唯一的伺服器ID;
  • 每個Master可以有很多Slave;
  • 如果你設定了log_slave_updates,Slave可以是其他Slave的Master,從而擴散Master的更新;
  • MySQL不支援多主伺服器複製,即不支援一個 Slave 可以有多個 Master,但是,通過一些簡單的組合,我們卻可以建立靈活而強大的複製體系結構。

1.2,一主多從複製架構

場景

在主庫讀取請求壓力非常大的場景下,可以通過配置一主多從複製架構實現讀寫分離,把大量對實時性要求不是特別高的讀請求通過負載均衡到多個從庫上,降低主庫的讀取壓力。在主庫出現異常當機的情況下,可以把一個從庫切換為主庫繼續提供服務;

建議

  • 當 Slave 增加到一定數量時,Slave 對 Master 的負載以及網路頻寬都會成為一個嚴重的問題;
  • 不同的 Slave 扮演不同的作用(例如使用不同的索引,或者不同的儲存引擎);
  • 用一個 Slave 作為備用 Master,只進行復制;
  • 用一個遠端的 Slave,用於災難恢復。

1.3,多級複製架構

場景

一主多從的架構能夠解決大部分讀請求壓力特別大的場景需求,但主庫的I/O壓力和網路壓力會隨著從庫的增加而增長,而使用多級複製架構就可以解決一主多從場景下,主庫額外的I/O和網路壓力。 但要注意的是,多級複製場景下主庫的資料是經歷兩次才到達讀取的從庫,期間的延時比一主多從複製場景下只經歷一次複製的要大。

建議

  • 可能存在延時較長的風險;
  • 這種方案可以與第三方軟體結合使用,例如Slave+LVS+Keepalived 實現高可用。

1.4,雙主複製/Dual Master架構

場景

雙主/Dual Master架構適用於寫壓力比較大的場景,或者DBA做維護需要主從切換的場景,通過雙主/Dual master架構避免了重複搭建從庫的麻煩。

建議

  • 最大問題就是更新衝突;
  • 可以採用MySQL Cluster,以及將Cluster和Replication結合起來,可以建立強大的高效能的資料庫平臺。

2,基本原理和步驟

Slave服務配置log_slave_updates=1,可以保證Slave服務收到Master服務的資料更新操作後,在執行該操作之後,將操作寫入到bin-log中,從而,保證該Mysql服務既做Slave,又做Master。

6779176-f9074f49b7cc4bc3.jpg
mysql多級複製.jpg

3,實現過程(採用Docker方式部署)

3.1,主伺服器(計劃提供Master服務的一級Slave服務)

  • 開啟二進位制日誌,並配置唯一的server-id
# 在[mysqld]下增加配置
root@mysql_slave:/etc/mysql/mysql.conf.d# vi /etc/mysql/mysql.conf.d/mysqld.cnf 
...
...
# 開啟二進位制日誌,可以寫絕對路徑,例如/var/log/mysql/master-bin
log-bin   = mysql-bin
# Mysql服務ID,必須保證唯一
server-id = 2

# 不進行主從複製的db
binlog-ignore-db = mysql
binlog-ignore-db = information_schema
# 進行主從複製的db
binlog-do-db = test

# 只儲存最近7天的bin-log檔案,避免檔案過多
expire_logs_days=7

# 允許從master收到的資料再次寫入到bin-log中,從而完成slave到slave資料的傳播
log_slave_updates = 1
  • 重啟Mysql服務
root@mysql_slave:/etc/mysql/mysql.conf.d# service mysql restart
  • 建立一個用於slave和master通訊的使用者賬號slave1
mysql> CREATE USER 'slave1'@'%' IDENTIFIED BY '123456';
mysql> GRANT REPLICATION SLAVE ON *.* TO 'slave1'@'%';
  • 建立測試賬號和資料庫
mysql> Grant all privileges on *.* to 'test'@'%' identified by '123456' with grant option;
mysql> Create database test;
  • 檢視master狀態,獲得master二進位制日誌檔名及位置
mysql> show master status;
+------------------+----------+--------------+--------------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB         | Executed_Gtid_Set |
+------------------+----------+--------------+--------------------------+-------------------+
| mysql-bin.000008 |      1453| test         | mysql,information_schema |                   |
+------------------+----------+--------------+--------------------------+-------------------+
1 row in set (0.00 sec)

3.2,從伺服器(二級Slave服務)

  • 啟動新容器slave,命名為mysql_slave11,設定靜態IP為172.18.0.12
kevin@apple:~$ docker run -it --name mysql_slave11 -h mysql_slave11 \
-p 13308:3306 --net my_network --ip 172.18.0.12 \
--add-host mysql_master:172.18.0.11 \
mysql:latest /bin/bash

root@mysql_slave11:/# apt-get update
root@mysql_slave11:/# apt-get install vim
root@mysql_slave11:/# apt-get install net-tools
root@mysql_slave11:/# apt-get install tmux
  • 配置唯一的server-id
# 在[mysqld]下增加配置
root@mysql_slave11:/etc/mysql/mysql.conf.d# vi /etc/mysql/mysql.conf.d/mysqld.cnf 
...
...
# Mysql服務ID,必須保證唯一
server-id = 3
  • 使用master分配的使用者賬號讀取master二進位制日誌
mysql> CHANGE MASTER TO
MASTER_HOST='mysql_master',
MASTER_PORT=3307,
MASTER_USER='slave1',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysql-bin.000008',
MASTER_LOG_POS=1453;
  • 啟用slave服務,並檢視狀態
mysql> start slave;
mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: mysql_master
                  Master_User: slave1
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000008
          Read_Master_Log_Pos: 1453
               Relay_Log_File: mysql_slave-relay-bin.000004
                Relay_Log_Pos: 1637
        Relay_Master_Log_File: mysql-bin.000005
             Slave_IO_Running: Yes                                     # IO執行緒是啟動狀態,如果是No,可以檢視下面日誌,分析處理
            Slave_SQL_Running: Yes                                     # SQL執行緒是啟動狀態,如果是No,可以檢視下面日誌,分析處理
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1453
              Relay_Log_Space: 2016
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 0f5421ba-0ede-11e8-b442-0242ac12000a
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

3.3,開啟Mysql服務的Docker容器列表

kevin@apple:~$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS                               NAMES
39e9a461040c        mysql:lastest       "docker-entrypoint..."   About an hour ago   Up About an hour            0.0.0.0:13308->3306/tcp             mysql_slave11
6d0e157edf33        mysql:lastest       "docker-entrypoint..."   7 hours ago         Up 7 hours                  0.0.0.0:13307->3307/tcp             mysql_slave
8cbf65b6d05a        mysql:lastest       "docker-entrypoint..."   7 hours ago         Up 7 hours                  0.0.0.0:13306->3306/tcp             mysql_master

4,測試

4.1,測試用例1

  • 在master中,建立資料表,增加2行資料,觀察一級slave和二級slave的資料變化是否一致(結果一致)
mysql> CREATE TABLE test.`student` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

mysql> Insert into test.student(name) values('aaa');
mysql> Insert into test.student(name) values('bbb');

mysql> Select * from test.student;

4.2,測試用例2

  • 在master中,刪除1行資料,更新1行資料,觀察一級slave和二級slave的資料變化(結果一致)
mysql> delete from test.student where id = 1;
mysql> update test.student set name = 'ccc' where id = 2;

4.3,測試用例3

  • 在master中,刪除1個資料表,觀察一級slave和二級slave的資料變化(結果一致)
mysql> drop table student;

4.4,測試用例4

  • 在master中,刪除資料庫test,或建立資料庫test,觀察一級slave和二級slave的資料變化(結果一致)
mysql> drop database test;
mysql> create database test;

5,參考

相關文章