1. 程式人生 > >MySQL主從復制和半同步復制

MySQL主從復制和半同步復制

MySQL主從復制

MySQL主從復制和半同步復制

主從復制原理

1、主從復制主要是基於二進制日誌(binlog)進行的,二進制日誌記錄的是一個個完整的事件。

2、把主服務器的二進制日誌拿到從服務器再運行一遍。

3、復制過程:

1,slave端的IO線程連上master端,請求   
2,master端返回給slave端,bin log文件名和位置信息      
3,IO線程把master端的bin log內容依次寫到slave端relay bin log裏,並把master端的bin-log文件名和位置記錄到master.info裏。    
4,salve端的sql線程,檢測到relay bin log中內容更新,就會解析relay log裏更新的內容,並執行這些操作;也就是說salve執行和master一樣的操作而達到數據同步的目的;

復制過程涉及到的3個線程:

1、從庫開啟一個IO線程,負責鏈接主庫請求和接收binlog日誌並寫入到relay-log
2、從庫開啟一個sql線程,負責解析relay-log中的事件並執行
3、主庫開啟一個dump線程,負責響應從庫來的IO線程的請求。

主從搭建配置示例

以MySQL多實例進行搭建配置

環境說明
[root@anuo ~]# getenforce 
Disabled
[root@anuo ~]# /etc/init.d/iptables status 
iptables:未運行防火墻。
[root@anuo ~]# mysql --version
mysql  Ver 14.14 Distrib 5.6.25, for Linux (x86_64) using  EditLine wrapper

主庫的配置文件

[root@anuo ~]# vim /data/3306/my.cnf 
[mysqld]
user=mysql
port=3306
socket=/data/3306/mysql.sock
basedir=/usr/local/mysql
datadir=/data/3306/data
log-bin=/data/3306/mysql-bin    --指定binlog的存放路徑
server-id=1                 --主庫和從庫的server-id 不能一樣
skip_name_resolve=0             --表示跳過域名解析

[client]
socket=/data/3306/mysql.sock

[mysqld_safe]
log-error=/data/3306/mysql_3306.err
pid-file=/data/3306/mysql.pid

從庫的配置文件

[root@anuo ~]# vim /data/3307/my.cnf 
[mysqld]
user    = mysql
port    = 3307
socket  = /data/3307/mysql.sock
basedir = /usr/local/mysql
datadir = /data/3307/data
log-bin = /data/3307/mysql-bin      --從庫的binlog可以不開啟
server-id = 2           --server-id和主庫的不一樣
skip_name_resolve = 0
read_only = 1           --從庫只讀

[client]
port            = 3307
socket          = /data/3307/mysql.sock

[mysqld_safe]
log-error=/data/3307/mysql_3307.err
pid-file=/data/3307/mysqld.pid

啟動數據庫

[root@anuo data]# /data/3306/mysql start
2018-05-27 06:03:37 MySQL--啟動中... 

[root@anuo data]# /data/3307/mysql start
2018-05-27 06:03:47 MySQL--啟動中... 

[root@anuo data]# netstat -nltup|grep mysql
tcp        0      0 :::3306          :::*          LISTEN      4028/mysqld         
tcp        0      0 :::3307          :::*          LISTEN      4268/mysqld         

主庫上創建用於復制的用戶

[root@anuo data]# mysql -uroot -p -S /data/3306/mysql.sock  --登陸主庫
Enter password: 

mysql> grant super,replication slave on *.* to ‘hb‘@‘10.0.0.%‘ identified by ‘123‘;         --創建用戶並授權
Query OK, 0 rows affected (0.12 sec)

mysql> flush privileges;    --刷新權限
Query OK, 0 rows affected (0.05 sec)

mysql> show master status;      --查看master的當前時間寫到的二進制文件名和位置
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000011 |      409 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

--只有打開二進制日誌,這句命令才有結果,表示當前數據庫的二進制日誌寫到什麽位置

(註:如果主庫的之前就已經開啟並有重要數據的話要先把數據進行備份傳到從庫進行恢復。我這是測試環境就忽略了這步驟。)

從庫上復制的操作

[root@anuo ~]# mysql -S /data/3307/mysql.sock       --登陸從庫
mysql> change master to
    -> master_host=‘10.0.0.15‘,     --主的IP
    -> master_port=3306,            --主的端口
    -> master_user=‘hb‘,            --對應前面主授權時的用戶
    -> master_password=‘123‘,       --對應前面主授權時的密
    -> master_log_file=‘mysql-bin.000011‘,      ----主上面查到的文件名
    -> master_log_pos=409;                  --主上面查到的位置號
Query OK, 0 rows affected, 2 warnings (0.11 sec)

mysql> start slave;         --啟動從庫復制
Query OK, 0 rows affected (0.07 sec)

mysql> show slave status\G
*************************** 1. row ***************************
        ……
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes      --看到這兩人個線程為yes,代表搭建成功
        ……

進行測試主從同步

在主庫上創建庫或表,再到從庫上查看是否同步成功。 此步驟忽略。

MySQL一主多從搭建

一主多從也就是在上面的一主一從的基礎上多加一臺從服務器

(我這裏多加一臺centos7.3的做從進行演示)

[root@vm1 ~]# vim /etc/my.cnf       --編輯配置文件
[mysqld]
port=3306 
datadir=/data/mysql 
pid-file=/data/mysql/mysql.pid 
socket=/data/mysql/mysql.socket 
log-error=/data/mysql/mysql-err.log 
user=mysql  
server-id=3         --多加一條server-id號跟之前的不一樣就可以了

[client]
socket=/data/mysql/mysql.socket

[root@vm1 ~]# systemctl restart mysqld.service      --重啟
[root@vm1 ~]# lsof -i:3306

登陸數據庫操作跟上面的從服務器操作是一樣的
mysql> change master to
    -> master_host=‘10.0.0.15‘,
    -> master_port=3306,
    -> master_user=‘hb‘,
    -> master_password=‘123‘,
    -> master_log_file=‘mysql-bin.000011‘,
    -> master_log_pos=409;
Query OK, 0 rows affected, 2 warnings (0.01 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.0.0.15
                  Master_User: hb
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000011
          Read_Master_Log_Pos: 503
               Relay_Log_File: mysql-relay-bin.000002
                Relay_Log_Pos: 377
        Relay_Master_Log_File: mysql-bin.000011
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes      --看到2給yes也就是成功了

半同步搭建

所謂的半同步復制就是master每commit一個事務,要slave應用這個事物後回給master信號。這樣master才能把事物成功commit。這樣就保證了master-slave的數據絕對的一致(但是以犧牲master的性能為代價).但等待時間也是可以調整的。 mysql半同步復制等待時間超時後(默認時間為10秒),會自動轉換成異步復制 ,相對於異步復制,半同步復制提高了數據的安全性。

安裝mysql5.5之後的版本,因為這個版本之後才實現的半同步復制

第一大步: 先要搭建好mysql主從異步復制,上面已經搭過了就過程省略 。

第二大步:在異步基礎上轉成半同步復制

1)在master上安裝這個插件
mysql> install plugin rpl_semi_sync_master soname ‘semisync_master.so‘;
Query OK, 0 rows affected (1.51 sec)

(--刪除插件的方法 mysql > uninstall plugin rpl_semi_sync_master;)

mysql> show global variables like ‘rpl_semi_sync%‘;       --安裝OK後,主上會多幾個參數
+------------------------------------+-------+
| Variable_name                      | Value |
+------------------------------------+-------+
| rpl_semi_sync_master_enabled       | OFF   |      --OFF表示半同步還沒有開啟
| rpl_semi_sync_master_timeout       | 10000 |      --默認主等待從返回信息的超時間時間,10秒。
| rpl_semi_sync_master_trace_level   | 32    |       --監控 
| rpl_semi_sync_master_wait_no_slave | ON    |      --是否允許每個事物的提交都要等待slave的信號.on為每一個事物都等待
+------------------------------------+-------+
4 rows in set (0.83 sec)

2)在slave上安裝插件
mysql> install plugin rpl_semi_sync_slave soname ‘semisync_slave.so‘;
Query OK, 0 rows affected (0.63 sec)

mysql> show global variables like ‘rpl_semi_sync%‘;
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled     | OFF   |
| rpl_semi_sync_slave_trace_level | 32    |
+---------------------------------+-------+
2 rows in set (0.78 sec)

3)master上激活半同步復制
mysql>  set global rpl_semi_sync_master_enabled =on;
Query OK, 0 rows affected (0.04 sec)

4)slave上激活半同步復制並重啟IO線程
mysql> set global rpl_semi_sync_slave_enabled=on;   --激活半同步
Query OK, 0 rows affected (0.04 sec)

mysql> stop slave IO_THREAD;            --關閉IO線程
Query OK, 0 rows affected (0.14 sec)

mysql> start slave IO_THREAD;           --啟動IO線程
Query OK, 0 rows affected (0.11 sec)

5)在master查看狀態
mysql> show global status like ‘rpl_semi_sync%‘;
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 1     |  --有一個從服務器啟用半同步復制
| Rpl_semi_sync_master_net_avg_wait_time     | 0     |  --master等待slave回復的平均等待時間。單位毫秒
| Rpl_semi_sync_master_net_wait_time         | 0     |  --master總的等待時間。單位毫秒
| Rpl_semi_sync_master_net_waits             | 0     |  --master等待slave回復的總的等待次數
| Rpl_semi_sync_master_no_times              | 0     |  --master關閉半同步復制的次數
| Rpl_semi_sync_master_no_tx                 | 0     |  --master 等待超時的次數
| Rpl_semi_sync_master_status                | ON    |  --標記master現在是否是半同步復制狀態
| Rpl_semi_sync_master_timefunc_failures     | 0     |  --master調用時間(如gettimeofday())失敗的次數  
| Rpl_semi_sync_master_tx_avg_wait_time      | 0     |  --master花在每個事務上的平均等待時間
| Rpl_semi_sync_master_tx_wait_time          | 0     |  --master花在事物上總的等待時間
| Rpl_semi_sync_master_tx_waits              | 0     |  --master事物等待次數
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |  --後來的先到了,而先來的還沒有到的次數
| Rpl_semi_sync_master_wait_sessions         | 0     |  --當前有多少個session因為slave回復而造成等待
| Rpl_semi_sync_master_yes_tx                | 0     |  --標記slave是否在半同步狀態
+--------------------------------------------+-------+
14 rows in set (0.10 sec)

6)在slave上查看狀態就只有下面一條信息
mysql> show global status like ‘rpl_semi_sync%‘;
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)

第三大步 測試:

mysql> create database  btbcs;
Query OK, 1 row affected (0.10 sec)

mysql> show global status like ‘rpl_semi_sync%_yes_tx‘; 
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_yes_tx | 1     |     --表示這次事物成功從slave返回一次確認信號
+-----------------------------+-------+
1 row in set (0.04 sec)

模擬錯誤,把slave上的IO線程停掉

--再回到master上測試
mysql> create database  btbcs2;
Query OK, 1 row affected (10.34 sec)    --這次插入一個值需要等待10秒(默認的等待時間)

mysql> create database  btbcs3;
Query OK, 1 row affected (0.00 sec)     --再插入數據時候就發現自動轉成了原來的異步模式了

再把slave上的IO線程開啟,查看數據發現剛才slave關閉期間的那幾條數據還是會自動復制過來,數據又回到一致

如果是把slave上的mysql停掉,再次把slave啟動,看到半同步復制沒啟來,是異步模式,需要重新把同步模式再啟起來就可以了

mysql> set global rpl_semi_sync_slave_enabled=on;   --啟動半同步模式
mysql> stop slave IO_THREAD;        --關閉IO線程
mysql> start slave IO_THREAD;       --啟動IO線程

slave啟起來後數據也是一樣會回到一致

MySQL主從復制和半同步復制