mysql主從複製

一、MySQL主從複製

1.1 爲什麼需要主從?

數據庫損壞了(業務不能使用數據庫)
原因:

  • 外在原因
    1. 網絡
    2. 業務應用有問題
  • 本身原因
    1. 物理損壞:機器壞了、硬盤損壞、存儲壞了、數據文件損壞
    2. 邏輯損壞:錯誤的drop、delete、truncate、update。。。

解決方案:

  1. 備份(物理損壞丟失數據)
  2. 主從複製

1.2 MySQL複製介紹

複製是MySQL的一項功能,允許服務器將更改從一個實例複製到另一個實例。

  • 主服務器將所有數據和結構更改記錄到二進制日誌中。
  • 從屬服務器從主服務器請求該二進制日誌並在本地應用其內容。

1.2.1 複製作用:

  • 高可用
  • 輔助備份
  • 分擔負載

1.2.2 應用場景:

  • 應用場景1:從服務器作爲主服務器的實時數據備份
  • 應用場景2:主從服務器實現讀寫分離,從服務器實現負載均衡
  • 應用場景3:把多個從服務器根據業務重要性進行拆分訪問

1.2.3 複製前提

  • 主服務器必須開啓二進制日誌(binlog)
  • 多臺服務器
  • 保證開始複製時主從服務器結構一致。
    • 對於新建的數據庫可以直接進行復制;
    • 對於運行了一段時間的數據庫,就要通過備份讓主從數據庫結構保證一致。
  • 主庫必須要有對從庫複製請求的用戶
  • 從庫需要有relay-log設置,存放從主庫傳來的binlog
  • 首次連接,從庫需要change master to連接主庫
  • 需要保存change master信息需要存放在master.info文件中
  • 通過relay-log.info裏記錄的已經使用過的事件,從庫知道主庫發生了變化
  • 複製中的線程
    • 主庫
      1. dump thread:負責響應從庫的IO線程
    • 從庫
      1. IO thread :負責連接主庫,請求binlog,接收binlog並寫入relay-log
      2. SQL thread :複製執行relay-log中的事件

1.2.4 複製原理

mysql主從複製

mysql主從複製

mysql主從複製

異步複製過程
總體來說,複製有3個步驟:

  • 主服務器把數據更改記錄到二進制日誌中。(這叫做二進制日誌事件)
  • 從服務器把主服務器的二進制日誌拷貝到自己的中繼日誌中。
    1. 從服務器和主服務器之間建立master/slave連接,相關信息存放在從服務器的master.info文件中
    2. 從服務器用IO線程詢問主服務器是否有新的binlog
    3. 主服務器用dump線程讀取binlog併發送給從服務器
    4. 從服務器接收binlog並存放在relay-log中
    5. 從服務器的SQL線程執行relay-log中的binlog,寫入數據庫
    6. 執行完畢的relay-log放在relay-log.info文件中
  • 從服務器重放中繼日誌中的事件,把更改應用到自己的數據上。

1.3 主從複製部署

兩臺主機安裝mysql 5.6
注意在兩臺主機的配置文件中/etc/my.cnf中需要添加server-id=參數。

  • 創建複製用戶

    grant replication slave on *.* to repl@'10.0.0.%' identified by '123';
  • 初始化從庫

    [root@db01 ~]# mysqldump -uroot -poldboy123 -A -F > /tmp/server.sql
    [root@db01 ~]# scp /tmp/server.sql 10.0.0.8:/tmp
    在從庫中source執行
  • 開啓主從複製

    • 在主庫中查看binlog起始點:
    mysql> mysql> show master;
    +----------------+----------+--------------+------------------+-------------------+
    | File          | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
    +----------------+----------+--------------+------------------+-------------------+
    | log-bin.000013 |      120 |              |                  |                  |
    +----------------+----------+--------------+------------------+-------------------+
    1 row in set (0.00 sec)
    • 從庫開啓複製:
      mysql> change master to
      master_host='10.0.0.51',
      master_port=3306,
      master_user='repl',
      master_password='123',
      master_log_file='log-bin.000013',
      master_log_pos=120;

    注意:也可以設置relay-bin的名稱。

  • 檢查狀態

    start slave;
    show slave status\G

    成功的標誌是:

    Slave_IO_Running: Yes
    Slave_SQL_Running: Yes

    1.4 監控主從複製狀態

mysql> show slave status\G
*************************** 1. row ***************************
              Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.0.0.51
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: log-bin.000014
          Read_Master_Log_Pos: 120
              Relay_Log_File: web01-relay-bin.000002
                Relay_Log_Pos: 281
        Relay_Master_Log_File: log-bin.000014
            Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              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: 120
              Relay_Log_Space: 454
              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: d4519488-d005-11e7-a4ac-000c2924dc94
            Master_Info_File: /application/mysql-5.6.38-linux-glibc2.12-x86_64/data/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
          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
1 row in set (0.00 sec)

1.4.1 注意事項

  • Slave_*_Running:

    • Slave_IO_RunningI/O 線程正在運行、未運行還是正在運行但尚未連接到主服務器。可能值分別爲Yes、No 或Connecting。
    • Slave_SQL_RunningSQL 線程當前正在運行、未運行,可能值分別爲Yes、No
  • 主服務器日誌座標:

    • Master_Log_File和Read_Master_Log_Pos標識主服務器二進制日誌中I/O 線程已經傳輸的最近事件的座標。
    • 如果Master_Log_File和Read_Master_Log_Pos的值遠遠落後於主服務器上的那些值,這表示主服務器與從屬服務器之間事件的網絡傳輸可能存在延遲。
  • 中繼日誌座標:

    • Relay_Log_File和Relay_Log_Pos列標識從屬服務器中繼日誌中SQL 線程已經執行的最近事件的座標。這些座標對應於Relay_Master_Log_File和Exec_Master_Log_Pos列標識的主服務器二進制日誌中的座標。
    • 如果Relay_Master_Log_File和Exec_Master_Log_Pos列的輸出遠遠落後於Master_Log_File和Read_Master_Log_Pos列(表示I/O 線程的座標),這表示SQL 線程(而不是I/O 線程)中存在延遲。即,它表示複製日誌事件快於執行這些事件。
  • Last_IO_Error、Last_SQL_Error:
    +分別導致I/O 線程或SQL 線程停止的最新錯誤的錯誤消息。在正常複製過程中,這些字段是空的。如果發生錯誤並導致消息顯示在以上任一字段中,則錯誤值也顯示在錯誤日誌中。

  • Last_IO_Errno、Last_SQL_Errno:

    • 與分別導致I/O 線程或SQL 線程停止的最新錯誤關聯的錯誤編號。在正常複製過程中,這些字段包含編號0。
  • Last_IO_Error_Timestamp、Last_SQL_Error_Timestamp:
    • 分別導致I/O 線程或SQL 線程停止的最新錯誤的時間戳,格式爲YYMMDD HH:MM:SS。在正常複製過程中,這些字段是空的。

1.4.2 錯誤實例

  • 從庫binlog落後於主庫

    Master_Log_File: log-bin.000014
    Read_Master_Log_Pos: 120

    從庫的logbin比主庫的logbin慢的原因:

    1. 網絡問題
    2. 主庫dump線程繁忙
    3. 從庫IO線程繁忙

    【擴展】
    延時節點概念:是SQL線程延時,不是IO線程延時。

  • SQL線程報錯
    原因:
    1. 主庫操作對象在從庫中不存在
    2. 主庫操作對象的屬性和從庫不一致
    3. 主從操作順序顛倒

解決方法:

  1. 跳過錯誤
    stop slave;
    set global sql_slave_skip_counter = 1;
    start slave;

    也可以在配置文件中跳過錯誤號碼:

    [mysqld]
    slave-skip-errors = 1032,1062,1007

1.5 企業實例

  • 背景:標準主從複製結構,在業務邏輯中有oldboy數據庫,oldboy數據庫下有t1表爲生產表。
  • 故障原因:開發人員在從庫創建了一個oldgirl庫,覺得不對,後又在主庫中做了相同的操作。導致了從庫複製失效。
  • 解決方案:
    主從複製故障及解決
    stop slave; #<==臨時停止同步開關。
    set global sql_slave_skip_counter= 1 ; #<==將同步指針向下移動一個,如果多次不同步,可以重複操作。
    start slave;
    /etc/my.cnf
    slave-skip-errors = 1032,1062,1007
  • 如何避免問題?
    1. 從庫設置爲只讀庫
      在my.cnf中添加read_only=1
    2. 單獨在從庫創建一個只讀用戶
      在主庫創建寫用戶
      優點:
    3. 配置時不需要重啓
    4. 故障切換時也不需要重啓

1.6 主從架構演變

備份

  1. 相當於實時備份
  2. 使用從庫備份

問題:
如果從庫只是作爲備份服務器使用,那麼主庫的壓力會增加,因爲所有的業務都在主庫進行讀寫(dump線程讀取併發送給binlog)

解決方法:

  1. 一主一從
    分出部分讀業務到從庫(讀寫分離)
  2. 一主多從,分擔壓力(針對讀業務多的需求)
    但是這種一主多從的模式會使dump線程壓力更大了
  3. 多級主從
    使用中間庫分擔主庫dump線程讀取分發binlog的壓力,由於中間庫只作爲分發者,不需要其他操作,爲了提高中間庫的性能,可以使用blackhole存儲引擎。
  4. 雙主模型
  5. 環狀複製

1.7 高級應用架構

  • 性能

    • 讀寫分離——MySQLproxy、amoeba、xx-dbproxy等。
    • 分庫分表——cobar、自主研發等。
      比較依賴於業務
    • 實施思路:
      1. 判斷語句類型
      2. 根據語句類型進行分發
      3. 負載均衡,分發到從庫
      4. 會話持續性(減少用戶認證之類的操作)
      5. 判斷語句是否執行過(提高性能,減少重複操作)
  • 高可用
    • MMM架構——mysql-mmm(google)(不在使用)
    • MHA架構——mysql-master-ha(日本DeNa)
    • MGR ——5.7 新特性MySQLGroup replication
    • PXC、MySQLCluster架構

1.8 多級主從部署(級聯主從)

mysql主從複製

類似於一主一從的部署
不同之處在於主從之間多了一箇中間服務器

[mysqld]
basedir = /application/mysql/
datadir = /application/mysql/data/
socket = /application/mysql/tmp/mysql.sock
character_set_server=utf8
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
server-id = 2
log-bin=/tmp/log-bin
binlog-format=row
autocommit=1
log-slave-updates

[client]
socket = /application/mysql/tmp/mysql.sock

在中間服務器的my.cnf文件中需要開啓binlog並添加log-slave-updates參數,表示強制刷新binlog,否則binlog日誌不會刷新。
相當於做了兩套主從。

reset slave;重置slave(關閉狀態)

1.9 擴展

1.9.1 複製延時

  • 問題:
    主服務器的錯誤操作會同步到從服務器,導致數據恢復比較麻煩。
  • 解決方法:
    採用複製延時,這樣主服務器操作錯誤,從服務器由於延時複製可以在一段時間內避免應用錯誤操作,這樣就可以及時恢復數據。

複製延時是在SQL線程的層面進行控制,不允許SQL線程實時的執行relay log中的操作。

  • 如何設置:
    
    stop slave;

change master to master_delay = 30; #單位是秒

start slave;

結果:
```shell
mysql> show slave status\G
                    SQL_Delay: 30
          SQL_Remaining_Delay: NULL

生產場景中一般延時3-6小時

1.9.2 半同步複製

  • 注重安全,不注重性能
  • 普通異步主從中從庫的同步率是不可控的,總會有延時的
  • 對於安全性要求比較高的應用場景,比如金融、運營商等不會使用普通異步主從架構。
  • 爲了讓MySQL更加能夠適用於高安全性的場景纔有了半同步複製。
  • 半同步基於dump線程和IO線程,省略了SQL線程讀取寫入的部分

部署:
1、加載插件
主:

INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

從:

INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

2、查看是否加載成功:

show plugins;

3、啓動:

主:

SET GLOBAL rpl_semi_sync_master_enabled = 1;

從:

SET GLOBAL rpl_semi_sync_slave_enabled = 1;

只是臨時啓動,需要寫入配置文件中。
4、重啓從庫上的IO線程

STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;

5、查看是否在運行
主:

show status like 'Rpl_semi_sync_master_status';

從:

show status like 'Rpl_semi_sync_slave_status';

1.9.3 主從同步的故障轉移(failover)

MHA設計理念:
主服務器宕掉了,但是多臺從服務器的數據和主服務器同步不完整,這時就需要整合多臺從服務器中的同步的數據到新的主服務器中,儘量保證數據的完整性。

  1. 選擇新主
  2. 數據補償:判斷新主服務器和其他從節點數據的新舊,補全自己的數據,儘量恢復到比較新的數據,或者去舊主服務器中獲取binlog日誌補全自己的數據
  3. 啓動新主,將其他從服務器指向新主
  4. 公佈新主

1.9.4 GTID複製

中繼日誌(relay log):記錄了events和position號
在執行的事務中打上一個唯一標籤,這樣就可以保證事務之間的連續性及唯一性
爲了failover出現的更好的複製,5.6出現,5.7完善
GTID(Global Transaction ID)是對於一個已提交事務的編號,並且是一個全局唯一的編號。
它的官方定義如下:
GTID = source_id :transaction_id
7E11FA47-31CA-19E1-9E56-C43AA21293967:29

[root@web01 ~]# cat /application/mysql/data/auto.cnf 
[auto]
server-uuid=0b920fba-d0fa-11e7-aae4-000c292741de

注意:如果是克隆的mysql數據庫,那麼server-uuid相同會導致slave-IO無法啓動,需要修改server-uuid

  • 部署過程
    環境:
    需要兩臺mysql數據庫服務器,一臺爲主服務器,一臺爲從服務器。

1、修改配置文件

主:

[mysqld]
log_bin = /tmp/log-bin
binlog-format = row
basedir = /application/mysql/
datadir = /application/mysql/data
socket = /application/mysql/tmp/mysql.sock
server_id = 1
gtid-mode = on    #啓用gtid類型,否則就是普通的複製架構
enforce-gtid-consistency = true    #強制GTID的一致性
log-slave-updates = 1    #slave更新是否記入日誌
autocommit = 1
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 
character_set_server=utf8

[client]
socket = /application/mysql/tmp/mysql.sock

從:

[mysqld]
log_bin = /tmp/log-bin
binlog-format=ROW
basedir = /application/mysql/
datadir = /application/mysql/data/
server_id = 2
socket = /application/mysql/tmp/mysql.sock
gtid-mode = on
enforce-gtid-consistency = true
log_slave_updates = 1
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 
character_set_server=utf8
autocommit = 1

[client]
socket = /application/mysql/tmp/mysql.sock

注意:如果是新建的數據庫可以不需要從庫初始化;如果不是需要從庫初始化,同步主從的結構屬性

2、在主服務器添加複製用戶

grant replication slave on *.* to repl@'10.0.0.%' identified by '123';

3、在從服務器上設置change master

mysql> change master to
master_host='10.0.0.51',
master_port=3306,
master_user='repl',
master_password='123',
master_auto_position=1;

4、開啓slave

start slave;

5、查看效果
在主庫中添加一個數據,查看master

mysql> show master status;
+----------------+----------+--------------+------------------+------------------------------------------+
| File          | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                        |
+----------------+----------+--------------+------------------+------------------------------------------+
| log-bin.000003 |      552 |              |                  | ff185ff4-cec5-11e7-9c86-000c2924dc94:1-2 |
+----------------+----------+--------------+------------------+------------------------------------------+
1 row in set (0.00 sec)

再從庫中查看slave:

mysql> show slave status\G
*************************** 1. row ***************************
              Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.0.0.51
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: log-bin.000003
          Read_Master_Log_Pos: 552
              Relay_Log_File: db02-relay-bin.000004
                Relay_Log_Pos: 442
        Relay_Master_Log_File: log-bin.000003
            Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              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: 552
              Relay_Log_Space: 1252
              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: ff185ff4-cec5-11e7-9c86-000c2924dc94
            Master_Info_File: /application/mysql-5.6.38/data/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
          Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
    Last_SQL_Error_Timestamp: 
              Master_SSL_Crl: 
          Master_SSL_Crlpath: 
          Retrieved_Gtid_Set: ff185ff4-cec5-11e7-9c86-000c2924dc94:1-2
            Executed_Gtid_Set: ff185ff4-cec5-11e7-9c86-000c2924dc94:1-2
                Auto_Position: 1
1 row in set (0.00 sec)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章