MySQL Replication

整體架構

內部架構

arch

鏈接管理

MySQL服務端採用線程池維護客戶端鏈接mysql

SQL解析

分析查詢語句,生成解析樹,並將解析結果放入緩存中sql

優化器

優化包括選擇合適的索引,數據的讀取方式,分析語句執行的開銷以及統計信息,優化器能夠和存儲引擎直接交互,儘管看起來彷佛沒必要要。數據庫

執行

執行查詢語句,返回結果緩存

緩存

緩存SQL解析器解析後的結果bash

存儲引擎

  1. 粒度服務器

    • 表級鎖(table lock) : 資源消耗最少,但併發度低
    • 行級鎖(row lock) : 資源消耗較多,但併發度高
  2. 死鎖

死鎖的簡單例子:兩個transaction同時開始執行,它們分別開始執行第一條update的語句時,便鎖住了對方的資源,你拿着個人資源不放,我拿着你的資源不放,最後二人都僵持着,當事人事不關己高高掛起,旁觀者疾呼:死鎖!微信

# transaction 1
START TRANSACTION;
UPDATE USER SET NAME='Bob' WHERE ID=1;
# sleep for some time;
UPDATE USER SET NAME='Jack' WHERE ID=2;
COMMIT;
# transaction 2
START TRANSACTION;
UPDATE USER SET NAME='Bob' WHERE ID=2;
# sleep for some time
UPDATE USER SET NAME='Jack' WHERE ID=1;
COMMIT;
  1. 顯示鎖定和隱式鎖定

隱式鎖定就是系統自動加鎖而不是人爲的添加鎖,顯示鎖定就是人爲的添加鎖,好比lock tables或者unlock tables。架構

事務

事務的特色由存儲引擎決定,是MySQL與其它數據庫的不一樣。
不支持事務的存儲引擎有:併發

  • MYISAM
  • MEMORY
  • ARCHIEVE

MySQL中的表按是否支持事務,分爲:事務型表和非事務型表。
非事務型表沒有commit或者rollback的概念。dom

SET AUTOCOMMIT=OFF;

或者

SET AUTOCOMMIT=0;

能設置當前鏈接是不是自動提交的。不過對非事務型表沒有做用。

  1. ACID屬性

    • 原子性:事務是不可分割的最小工做單元,整個事務要麼所有提交要麼所有回滾失敗。
    • 一致性:數據庫老是從一個一致性狀態轉換到另外一個一致性的狀態。
    • 隔離性: 一個事務所作的更改在最終提交以前其它事務是不可見的。
    • 持久性:事務一旦提交所作的修改就會永久保存在數據庫中,即便系統崩潰,數據也不會丟失。
  2. 隔離級別

    • 未提交讀(READ UNCOMMITTED):未提交讀隔離級別也叫讀髒,就是事務能夠讀取其它事務未提交的數據。
    • 提交讀(READ COMMITTED):在其它數據庫系統好比SQL Server默認的隔離級別就是提交讀,已提交讀隔離級別就是在事務未提交以前所作的修改其它事務是不可見的。
    • 可重複讀(REPEATABLE READ):保證同一個事務中的屢次相同的查詢的結果是一致的,好比一個事務一開始查詢了一條記錄而後過了幾秒鐘又執行了相同的查詢,保證兩次查詢的結果是相同的,可重複讀也是mysql的默認隔離級別。
    • 可串行化(SERIALIZABLE):可串行化就是保證讀取的範圍內沒有新的數據插入,好比事務第一次查詢獲得某個範圍的數據,第二次查詢也一樣獲得了相同範圍的數據,中間沒有新的數據插入到該範圍中。

查詢和設置隔離級別:

# 查詢系統默認隔離級別,當前會話隔離級別
    select @@global.tx_isolation,@@tx_isolation;
    # 設置系統隔離級別:
    SET global transaction isolation level read committed;
    # 設置會話隔離級別:
    SET SESSION transaction isolation LEVEL read committed;

Replication概念

複製意味着一份數據能夠有多個副本,一個數據庫中的數據,能夠複製至另外一個數據庫。
圖片描述
複製在咱們的生活中無處不在,同一份數據,有可能在你我的的電腦上有一份,U盤上有一份,雲端的網盤上也可能會有一份。甚至在我的電腦裏,一樣一份數據也會有多個副本。
這裏,咱們之因此會將數據複製出多份,目的是顯而易見的:備份
當你抱着本身的電腦準備接上投影儀,準備向老闆展現你苦戰數個通宵後的PPT時,硬盤忽然壞了,或者文件誤刪,莫名其妙的找不到了,不要緊,你的U盤還有一份。什麼!U盤忘了帶了?不要緊,你的網盤裏還有一個。
複製備份的是兩件不一樣的事情,能夠經過複製來實現備份的目的。可是,複製的卻不僅是能提供備份而已。

複製解決了什麼問題

在MySQL中,複製能夠解決幾個問題:

  • 數據分佈
  • 讀寫分離
  • 備份
  • 高可用和故障切換

若是大家公司的數據中心位於全國各地,經過複製,能夠實現異地備份,但異地的數據同步會有較大的時間延遲。
同時,若是主數據庫的數據都同步複製至從庫,那麼當須要更新數據時,只須要更新主庫便可,新更新的數據將會經過主庫同步至從庫,在這個基礎上,即可以實現讀寫分離,即DML語句在主庫上執行,而查詢類SQL語句則在從庫上執行,因爲主從的同步有時延,所以這裏的數據一致性模型並不知足強一致性,是最終一致性模型。
由於有了主從副本,因此當主庫不可用(宕機,崩潰等緣由),從庫能夠臨危受命,升級爲主庫,保證數據庫服務的高可用性。

MySQL間如何複製

分爲3個步驟

  1. 在主庫上把數據更改記錄到二進制(binary log)日誌中。
  2. 從庫把主庫上的日誌複製到本身的中繼日誌(relay log)中。
  3. 從庫讀取中繼日誌中的事件,將其重放在從庫數據中。

圖片描述

主庫在每次事務準備提交前,按照事務的提交順序,將更新事件記錄到binary log中,並通知存儲引擎提交事務。而後,從庫會主動啓動一個線程與主庫創建鏈接,與此對應,主庫會啓動一個二進制轉儲(binlog dump)線程與之合做,將binary log發送給從庫,從庫接收併產生relay log,而後由從庫的一個SQL線程負責將relay log還原爲數據。

須要注意的是,從庫在relay時,是單線程執行,換言之,串行執行的。

Replication配置

複製的配置步驟

  1. 建立複製帳號
  2. 配置主庫和從庫
  3. 通知從庫開始進行復制

基於二進制日誌的主從複製

配置master

經過在my.cnf中添加一個配置項log-bin,來起用master的二進制日誌記錄功能,若是沒有配置log-bin,那麼master的二進制記錄功能並不會起用,log-bin在這裏有兩個做用

  • 起用master的日誌記錄功能
  • 指定日誌文件名的前綴

另外,須要在my.cnf中添加一個server-id配置項,用來指定master的惟一ID,範圍能夠是1到2^32-1。

[mysqld]
# Replication Configurations(by beanlam)
server-id=1
log-bin=bin-log

配置完成後須要重啓mysql server。

配置slave

一樣,slave也須要配置一個惟一的server-id,不容許跟master的server-id衝突,若是有多個slave,各個slave與master的server-id都應該是不一樣的。
slave也能夠配置log-bin,配置了之後slave也能夠和master同樣,記錄binary log。slave記錄binary log有其用武之地的,好比數據備份和崩潰恢復,若當前的replication環境拓撲結構比較複雜,slave須要做爲其它mysql server的master時,那麼這個slave也必須啓用binary log的功能。

[mysqld]
# Replication Configurations(by beanlam)
server-id=2

建立一個帳號用於複製

slave獲取master的binary log時,經過用戶名和密碼與master創建鏈接,能夠建立一個專用於複製的帳號,並只賦予這個帳號與複製有關的權限。

mysql> CREATE USER 'repl'@'%.mydomain.com' IDENTIFIED BY 'slavepass';
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%.mydomain.com';

除了REPLICATION SLAVE權限,還能夠給用戶受權REPLICATION CLIENT權限,這樣用戶就能夠用來監控和管理複製。

獲取master二進制文件的座標

slave必須事先了解從master的二進制文件的哪一個位置開始複製,所以須要先記錄master當前二進制日誌的座標,座標由文件名和偏移量決定。
得到master的二進制日誌座標,須要先保證沒有寫操做在進行。在master上執行如下語句:

mysql> FLUSH TABLES WITH READ LOCK;

這個語句能爲表得到讀鎖,阻止其它寫入操做。須要注意,執行這個語句的會話若是關閉,那麼這個鎖將會被釋放,若是會話沒有關閉,那麼鎖會一直持有。

在另外一個會話裏,用如下語句來查看master的二進制日誌座標

mysql> show master status;
+----------------+----------+-------------------------+------------------+-------------------+
| File           | Position | Binlog_Do_DB            | Binlog_Ignore_DB | Executed_Gtid_Set |
+----------------+----------+-------------------------+------------------+-------------------+
| bin-log.000005 |     1264 | beanlam_db1,beanlam_db2 |                  |                   |
+----------------+----------+-------------------------+------------------+-------------------+
1 row in set (0.00 sec)

File和Position即代表了slave應該從何處開始進行復制。

若是master以前沒有啓用過二進制日誌的功能,那麼show master status查詢結果將爲空。這時對於slave來講,File是一個空字符串,Position是4,之因此是4,與二進制日誌的文件格式有關。

slave開始複製

根據以上步驟,獲得了master二進制文件的座標後,只須要告訴slave,slave即可以埋頭進入複製的狀態中。

這裏根據master是否有舊數據須要同步,分爲兩種狀況:

  1. 若是master是一個新的數據庫服務器,其上沒有任何舊的數據須要複製,那麼就可使用change master to命令爲slave配置master的信息。

    CHANGE MASTER TO
    MASTER_HOST='master_host_name',
    MASTER_USER='replication_user_name',
    MASTER_PASSWORD='replication_password',
    MASTER_LOG_FILE='recorded_log_file_name',
    MASTER_LOG_POS=recorded_log_position;

    配置完後,能夠經過start slave命令正式開始進行復制。

  2. 若是master在啓用二進制日誌功能以前,已經存在有一部分數據,這一部分數據須要在複製開始以前,先同步至slave。

能夠經過mysqldump工具對當前master的數據庫數據作一個快照,生成一個dump文件,在slave開始複製以前,把這個文件的數據導入slave中。
基本的使用方法:

mysqldump --all-databases --master-data > dbdump.db

-all-databases代表爲全部數據庫做快照,也能夠用--databases來制定須要作快照的數據庫。
--ignore-table能夠跳過數據庫中的全部表
--master-data會自動地在dump文件里加上change master to語句,啓動slave複製,若是不加這個選項,則須要先開啓一個新的會話,對全部的表加讀。
當存儲引擎是InnoDB時,推薦使用mysqldump。
另一種方法是直接拷貝數據文件到slave。

Replication原理

基於語句的複製

基於語句的複製也稱爲(邏輯複製),slave把master上形成數據更改的SQL語句在本身的庫上也執行一次。

  • 優勢

master的binlog只記錄SQL語句,使得日誌文件體積更小。

  • 缺點

master除了傳輸SQL語句給slave,還須要傳輸一些元數據,好比當前時間戳。
還有一些語句沒法被正確複製,好比包含用戶自定義函數的語句,這些函數可能有不肯定的行爲。如下函數可能致使非正常的複製:

LOAD_FILE(), UUID(), UUID_SHORT(), USER(), FOUND_ROWS(), SYSDATE(), GET_LOCK(), IS_FREE_LOCK(), IS_USED_LOCK, MASTER_POS_WAIT, RAND(), RELEASE_LOCK(), SLEEP(), VERSION()

此外,INSERT......SELECT語句須要獲取更多的行級鎖,比起基於行的複製來講。
UPDATE語句可能致使全表掃描(where字句中沒有包含索引字段)
若是使用的是InnoDB引擎,帶有auto_incrementinsert語句會堵塞其它非衝突的insert語句。
slave上的更新是串行的,所以須要更多的鎖。另外,並非全部的存儲引擎都支持基於語句的複製。

基於行的複製

MySQL5.1開始支持基於行的複製

  • 優勢

更少的鎖

  • 缺點

對於某些語句,例如插入或者刪除語句,基於行的複製方式會將整行的數據都寫進binary log,致使binary log體積很大,也致使須要持有鎖的時間變長。
若是包含用戶自定義函數,這些函數輸出值很是大的文本,那麼採起行的複製,會把這麼大的文本也寫進日誌裏。
在slave端看不到執行了哪些SQL語句
當使用MyISAM引擎時,insert語句須要得到重量級的鎖,這意味着插入操做只能是串行的。

slave也做爲master

若是slave配置了log_slave_updates選項,slave也會像master同樣記錄binary log,從而能夠做爲一個master存在。
圖片描述

拓撲結構

  • 最多見的拓撲結構

圖片描述

  • MySQL不支持多主庫複製

圖片描述

  • 主動-被動模式下的主-主複製

被動服務器時只讀的(日誌裏記錄的事件都帶有一個server id,發現server id與本身的相同,則忽略這個事件)

圖片描述

  • 擁有備庫的主-主結構

圖片描述

  • 環形結構

很是脆弱,其中一個節點失效會致使由這個節點發起的事件在其它節點之間鏈式死循環,由於只有它本身能過濾掉與本身server id相同的事件。
圖片描述
改進:
圖片描述

  • 主庫-分發庫-備庫

主要用在當多個備庫執行復制請求時,致使主庫負載太高時,能夠引進分發庫來減小主庫的負載。
圖片描述

  • 樹形或金字塔形

故障處理過程更加複雜
圖片描述

Reference

mysql5.6 ref
mysql5.7 ref
《高性能MySQL》 3rd Edition

掃一掃關注個人微信公衆號

相關文章
相關標籤/搜索