-
MySQL 中讀寫分離可能遇到的問題
- 前言
-
讀寫分離的架構
- 基于客戶端實現讀寫分離
- 基于中間代理實現讀寫分離
-
MySQL 中如何保證主從數據一致
- 循環(huán)復制問題
- 主從同步延遲
- 主從同步延遲的原因
-
主從延遲如何處理
- 強制走主庫方案
- Sleep 方案
- 判斷主從無延遲方案
- 配合semi-sync
- 等主庫位點方案
- 等 GTID 方案
- 總結
- 參考
MySQL 中讀寫分離可能遇到的問題
前言
MySQL 中讀寫分離是經常用到了的架構了,通過讀寫分離實現橫向擴展的能力,寫入和更新操作在源服務器上進行,從服務器中進行數據的讀取操作,通過增大從服務器的個數,能夠極大的增強數據庫的讀取能力。
MySQL 中的高可用架構越已經呈現出越來越復雜的趨勢,但是都是才能夠最基本的一主一從演化而來的,所以這里來弄明白主從的基本原理。
首先來弄明白主從和主備,以及雙主模式之間的區(qū)別
雙主

有兩個主庫,每個主庫都能進行讀寫,并且兩個主庫之間都能進行數據的同步操作。
主從

主從中,數據寫入在主節(jié)點中進行,數據讀取在從節(jié)點中進行,主庫會同步數據到從庫中。
主備

主備,備庫只是用來進行數據備份,沒有讀寫操作的發(fā)生,數據的讀取和寫入發(fā)生在主庫中,主庫會同步數據到備庫中。
下面討論的數據延遲,主要是基于主從模式。主從,主備,雙主數據同步原理一樣,這里不展開分析了。
讀寫分離的架構
常用的讀寫分離有下面兩種實現:
1、客戶端實現讀寫分離;
2、基于中間代理層實現讀寫分離。
基于客戶端實現讀寫分離
客戶端主動做負載均衡,根據 select、insert
進行路由分類,讀請求發(fā)送到讀庫中,寫請求轉發(fā)到寫庫中。
這種方式的特點是性能較好,代碼中直接實現,不需要額外的硬件支持,架構簡單,排查問題更方便。
缺點需要嵌入到代碼中,需要開發(fā)人員去實現,運維無從干預,大型代碼,實現讀寫分離需要改動的代碼比較多。

基于中間代理實現讀寫分離
中間代理層實現讀寫分離,在 MySQL 和客戶端之間有一個中間代理層 proxy,客戶端只連接 proxy, 由 proxy 根據請求類型和上下文決定請求的分發(fā)路由。

帶 proxy 的架構,對客戶端比較友好??蛻舳瞬恍枰P注后端細節(jié),連接維護、后端信息維護等工作,都是由 proxy 完成的。但這樣的話,對后端維護團隊的要求會更高。而且,proxy 也需要有高可用架構。因此,帶 proxy 架構的整體就相對比較復雜。
不過那種部署方式都會遇到讀寫分離主從延遲的問題,因為主從延遲的存在,客戶端剛執(zhí)行完成一個更新事務,然后馬上發(fā)起查詢,如果選擇查詢的是從庫,可能讀取到的狀態(tài)是更新之前的狀態(tài)。
MySQL 中如何保證主從數據一致
MySQL 數據進行主從同步,主要是通過 binlog 實現的,從庫利用主庫上的binlog進行重播,實現主從同步。
來看下實現原理
在主從復制中,從庫利用主庫上的 binlog 進行重播,實現主從同步,復制的過程中蛀主要使用到了 dump thread,I/O thread,sql thread
這三個線程。
IO thread
: 在從庫執(zhí)行 start slave
語句時創(chuàng)建,負責連接主庫,請求 binlog,接收 binlog 并寫入 relay-log;
dump thread
:用于主庫同步 binlog 給從庫,負責響應從 IO thread
的請求。主庫會給每個從庫的連接創(chuàng)建一個 dump thread
,然后同步 binlog 給從庫;
sql thread
:讀取 relay log
執(zhí)行命令實現從庫數據的更新。
來看下復制的流程:
1、主庫收到更新命令,執(zhí)行更新操作,生成 binlog;
2、從庫在主從之間建立長連接;
3、主庫 dump_thread 從本地讀取 binlog 傳送剛給從庫;
4、從庫從主庫獲取到 binlog 后存儲到本地,成為 relay log
(中繼日志);
5、sql_thread 線程讀取 relay log
解析、執(zhí)行命令更新數據。
需要注意的是
一開始創(chuàng)建主從關系的時候,同步是由從庫指定的。比如基于位點的主從關系,從庫說“我要從 binlog 文件 A 的位置 P ”開始同步, 主庫就從這個指定的位置開始往后發(fā)。
而主從復制關系搭建完成以后,是主庫來決定“要發(fā)數據給從庫”的。只有主庫有新的日志,就會發(fā)送給從庫。
binlog 有三種格式 statement,row
和 mixed。
1、Statement(Statement-Based Replication,SBR):每一條會修改數據的 SQL 都會記錄在 binlog 中,里面記錄的是執(zhí)行的 SQL;
Statement 模式只記錄執(zhí)行的 SQL,不需要記錄每一行數據的變化,因此極大的減少了 binlog 的日志量,避免了大量的 IO 操作,提升了系統(tǒng)的性能。
正是由于 Statement 模式只記錄 SQL,而如果一些 SQL 中包含了函數,那么可能會出現執(zhí)行結果不一致的情況。
比如說 uuid() 函數,每次執(zhí)行的時候都會生成一個隨機字符串,在 master 中記錄了 uuid,當同步到 slave 之后,再次執(zhí)行,就獲取到另外一個結果了。
所以使用 Statement 格式會出現一些數據一致性問題。
2、Row(Row-Based Replication,RBR):不記錄 SQL 語句上下文信息,僅僅只需要記錄某一條記錄被修改成什么樣子;
Row 格式的日志內容會非常清楚的記錄下每一行數據修改的細節(jié),這樣就不會出現 Statement 中存在的那種數據無法被正常復制的情況。
比如一個修改,滿足條件的數據有 100 行,則會把這 100 行數據詳細記錄在 binlog 中。當然此時,binlog 文件的內容要比第一種多很多。
不過 Row 格式也有一個很大的問題,那就是日志量太大了,特別是批量 update、整表 delete、alter 表等操作,由于要記錄每一行數據的變化,此時會產生大量的日志,大量的日志也會帶來 IO 性能問題。
3、Mixed(Mixed-Based Replication,MBR):Statement 和 Row 的混合體。
因為有些 statement 格式的 binlog 可能會導致主從不一致,所以要使用 row 格式。
但 row 格式的缺點是,很占空間。比如你用一個 delete 語句刪掉10萬行數據,用 statement 的話就是一個SQL語句被記錄到binlog中,占用幾十個字節(jié)的空間。但如果用 row 格式的 binlog,就要把這10萬條記錄都寫到 binlog 中。這樣做,不僅會占用更大的空間,同時寫 binlog 也要耗費IO資源,影響執(zhí)行速度。所以,MySQL就取了個折中方案,也就是有了 mixed 格式的 binlog。
mixed 格式的意思是,MySQL 自己會判斷這條SQL語句是否可能引起主從不一致,如果有可能,就用 row 格式,否則就用 statement 格式。也就是說,mixed 格式可以利用 statment 格式的優(yōu)點,同時又避免了數據不一致的風險。
不過現在越來越多的場景會把把 MySQL 的 binlog 格式設置成 row,例如下面的場景數據恢復。
這里從 delete、insert
和 update 這三種 SQL 語句的角度,來看看數據恢復的問題。
1、delete:如果執(zhí)行的是 delete 操作,需要恢復數據。row 格式的 binlog 也會把被刪掉的行的整行信息保存起來。所以,如果在執(zhí)行完一條 delete 語句以后,發(fā)現刪錯數據了,可以直接把 binlog 中記錄的 delete 語句轉成 insert,把被錯刪的數據插入回去就可以恢復了;
2、insert:如果執(zhí)行的是 insert 操作,需要恢復數據。row 格式下,insert 語句的 binlog 里會記錄所有的字段信息,這些信息可以用來精確定位剛剛被插入的那一行。這時,可以直接把 insert 語句轉成 delete 語句,刪除掉這被誤插入的一行數據就可以了;
3、update:如果執(zhí)行的是 update 操作,需要進行數據恢復。binlog里面會記錄修改前整行的數據和修改后的整行數據。所以,如果誤執(zhí)行了 update 語句的話,只需要把這個 event 前后的兩行信息對調一下,再去數據庫里面執(zhí)行,就能恢復這個更新操作了。
循環(huán)復制問題
上面 binlog 的原理,我們可以知道 MySQL 中主從數據同步就是通過 binlog 來保持數據一致的。
不過,雙 M 結構可能存在循環(huán)復制的問題。

什么是雙 M 架構,雙 M 結構和 M-S 結構,其實區(qū)別只是多了一條線,即:節(jié)點 A 和 B 之間總是互為主從關系。這樣在切換的時候就不用再修改主從關系。
業(yè)務邏輯在節(jié)點 A 中更新了一條語句,然后把生成的 binlog 發(fā)送給節(jié)點 B,節(jié)點 B 同樣也會生成 binlog 。
如果節(jié)點 A 同時又是節(jié)點 B 的從庫,節(jié)點 B 同樣也會傳遞 binlog 到節(jié)點 A,節(jié)點 A 會執(zhí)行節(jié)點 B 傳過來的 binlog。這樣,節(jié)點 A 和節(jié)點 B 會不斷的循環(huán)這個更新語句,這就是循環(huán)復制。
如何解決呢?
1、規(guī)定兩個庫的 server id
必須不同,如果相同,則它們之間不能設定為主從關系;
2、一個從庫接到 binlog 并在重放的過程中,生成與原 binlog 的 server id
相同的新的 binlog;
3、每個庫在收到從自己的主庫發(fā)過來的日志后,先判斷 server id
,如果跟自己的相同,表示這個日志是自己生成的,就直接丟棄這個日志。
這樣當設置了雙 M 結構,日志的執(zhí)行流就會變成這樣:
1、從節(jié)點 A 更新的事務,binlog 里面記的都是 A 的 server id
;
2、傳到節(jié)點 B 執(zhí)行一次以后,節(jié)點 B 生成的 binlog 的 server id
也是 A 的 server id
;
3、再傳回給節(jié)點 A,A 判斷到這個 server id
與自己的相同,就不會再處理這個日志。所以,死循環(huán)在這里就斷掉了。
主從同步延遲
主從同步延遲,就是同一個事務,在從庫執(zhí)行完成的時間和主庫執(zhí)行完成的時間之間的差值。
1、主庫 A 執(zhí)行完成一個事務,并且寫入到 binlog ,記錄這個時間為 T1;
2、傳遞數據給從庫,從庫接收這個 binlog,接收完成的時間記為 T2;
3、從庫 B 執(zhí)行完成這個接收的事務,這個時間記為 T3。
主從延遲的時間就是 T3-T1 之間的時間差。
通過 show slave status
命令能到 seconds_behind_master 這個值就表示當前從庫延遲了多少秒。
seconds_behind_master 的計算方式:
1、每個事務的 binlog 都有一個時間字段,用于記錄主庫寫入的時間;
2、從庫取出當前正在執(zhí)行的事務的時間字段的值,計算他與當前系統(tǒng)時間的差值,就能得到 seconds_behind_master。
簡單的講 seconds_behind_master 就是上面 T3 -T1
的時間差值。
如果主從機器的時間設置的不一致,會不會導致主從延遲的不準確?
答案是不會的,從庫連接到主庫,會通過 SELECT UNIX_TIMESTAMP()
函數來獲取當前主庫的時間,如果這時候發(fā)現主庫系統(tǒng)時間與自己的不一致,從庫在執(zhí)行 seconds_behind_master 計算的時候會主動扣減掉這差值。
主從同步延遲的原因
主從同步延遲可能存在的原因:
1、從庫的性能比主庫所在的機器性能較差;
從庫的性能比較查,如果從庫的復制能力,低于主庫,那么在主庫寫入壓力很大的情況下,就會造成從庫長時間數據延遲的情況出現。
2、從庫的壓力大;
大量查詢放在從庫上,可能會導致從庫上耗費了大量的 CPU 資源,進而影響了同步速度,造成主從延遲。
3、大事務的執(zhí)行;
有事務產生的時候,主庫必須要等待事務完成之后才能寫入到 binlog,假定執(zhí)行的事務是一個非常大的數據插入,這些數據傳輸到從庫,從庫同步這些數據也需要一定的時間,就會導致從節(jié)點出現數據延遲。
4、主庫異常發(fā)生主從或主從切換切換。
發(fā)生主庫切換的時候,可能會出現數據的不一致,主從切換會有下面兩種策略:
可靠性優(yōu)先策略:
1、首先判斷下從庫的 seconds_behind_master ,如果小于某個可以容忍的值,就進行下一步,否則持續(xù)重試這一步;
2、把主庫 A 改成只讀狀態(tài),設置 readonly 為 true;
3、判斷從庫 B 的 seconds_behind_master,直到這個值變成 0 為止;
4、把從庫 B 改成可讀寫狀態(tài),設置 readonly 為 false,從庫 B 變成新的主庫;
5、更新業(yè)務請求會切換到到從庫 B。
這個切換的過程中是存在不可用時間的,在步驟 2 之后,主庫 A 和從庫 B 都處于 readonly 狀態(tài),這時候系統(tǒng)處于不可寫狀態(tài),知道從庫庫 B readonly 狀態(tài)變成 false,這時候才能正常的接收寫請求。
步驟 3 判斷 seconds_behind_master 為 0,這個操作是最耗時的,通過步驟 1 中的提前判斷,可以確保 seconds_behind_master 的值足夠小,能夠減少步驟 3 的等待時間。
可用性優(yōu)先策略:
如果把步驟4、5調整到最開始執(zhí)行,不等主庫的數據同步,直接把連接切到從庫 B,讓從庫 B 可以直接讀寫,這樣系統(tǒng)就幾乎沒有不可用時間了。
這種策略能最大可能保障服務的可用性,但是會出現數據不一致的情況,因為寫請求直接切換到從庫 B 中,也就是設置 B 為新的主庫,因為 B 庫中還沒有同步到最新的數據,變成主庫之后,這部分數據就丟失了。
主從延遲如何處理
面對主從延遲,有下面幾種應對方案:
1、強制走主庫方案;
2、sleep方案;
3、判斷主從無延遲方案;
4、配合 semi-sync 方案;
5、等主庫位點方案;
6、等 GTID 方案。文章來源:http://www.zghlxwxcb.cn/news/detail-437129.html
強制走主庫方案
強制走主庫方案是實質上就是將查詢進行分類,將不能容忍同步延遲的查詢直接在主庫中進行。
1、對于必須要拿到最新結果的請求,強制將其發(fā)到主庫上。
2、對于可以讀到舊數據的請求,才將其發(fā)到從庫上。
這種方式有點投機的意思,如果所有的查詢都不允許有延遲的出現,也就意味所有的查詢,都會在主庫中出現。這樣就相當于放棄讀寫分離,所有的讀寫壓力都在主庫,等同于放棄了擴展性。
Sleep 方案
主庫更新完成,從庫在讀取數據之前,首先 sleep 一會。具體的方案就是,類似于執(zhí)行一條 select sleep(1)
命令。
這個方案的假設是,大多數情況下主從延遲在1秒之內,做一個sleep可以有很大概率拿到最新的數據。
這種方式不是一個靠譜的方案
1、如果一個查詢請求本來 0.5 秒就可以在從庫上拿到正確結果,也會等 1 秒;
2、如果延遲超過1秒,還是會出現過期讀。
判斷主從無延遲方案
可以通過主從是否有延遲,沒有延遲就在從庫中執(zhí)行查詢操作,有下面三種方法。
1、判斷 seconds_behind_master;
每次查詢之前首先判斷 seconds_behind_master 的值是否等于 0 。如果不等于 0 表示還有延遲,直到等于 0 才進行查詢操作。
2、對比位點確保主從無延遲;
-
Master_Log_File 和 Read_Master_Log_Pos,表示的是讀到的主庫的最新位點;
-
Relay_Master_Log_File 和 Exec_Master_Log_Pos,表示的是從庫執(zhí)行的最新位點。
如果 Master_Log_File 和 Relay_Master_Log_File、Read_Master_Log_Pos
和 Exec_Master_Log_Pos 這兩組值完全相同,就表示接收到的日志已經同步完成。
3、對比 GTID 集合確保主從無延遲:
-
Auto_Position=1
,表示這對主從關系使用了 GTID 協(xié)議; -
Retrieved_Gtid_Set
,是從庫收到的所有日志的 GTID 集合; -
Executed_Gtid_Set
,是從庫所有已經執(zhí)行完成的GTID集合。
如果 Retrieved_Gtid_Set 和 Executed_Gtid_Set 這兩個集合相同就表示從庫接收的日志已經同步完成。
什么是 GTID ?
GTID 的全稱是 Global Transaction Identifier
,也就是全局事務 ID,是一個事務在提交的時候生成的,是這個事務的唯一標識。
它由兩部分組成,格式是:
GTID=server_uuid:gno
-
server_uuid 是一個實例第一次啟動時自動生成的,是一個全局唯一的值;
-
gno 是一個整數,初始值是1,每次提交事務的時候分配給這個事務,并加1。
在 GTID 模式下,每一個事務都會跟一個 GTID 一一對應。GTID 有兩種生成方式,通過 session 變量 gtid_next 的值來決定:
1、如果 gtid_next=automatic
,代表使用默認值。這時,MySQL 就會把 server_uuid:gno
分配給這個事務。
a、記錄 binlog 的時候,先記錄一行 SET @@SESSION.GTID_NEXT=‘server_uuid:gno’
;
b、把這個 GTID 加入本實例的 GTID 集合。
2、如果 gtid_next 是一個指定的GTID的值,比如通過 set gtid_next='current_gtid’
指定為 current_gtid,那么就有兩種可能:
a、如果 current_gtid 已經存在于實例的GTID集合中,接下來執(zhí)行的這個事務會直接被系統(tǒng)忽略;
b、如果 current_gtid 沒有存在于實例的 GTID 集合中,就將這個 current_gtid 分配給接下來要執(zhí)行的事務,也就是說系統(tǒng)不需要給這個事務生成新的 GTID,因此 gno 也不用加1。
一個 current_gtid 只能給一個事務使用。這個事務提交后,如果要執(zhí)行下一個事務,就要執(zhí)行set 命令,把 gtid_next 設置成另外一個 gtid 或者 automatic。
每個 MySQL 實例都維護了一個 GTID 集合,用來對應“這個實例執(zhí)行過的所有事務”。
明白了 GTID 的概念,再來看下基于 GTID 的主從復制的用法。
在 GTID 模式下,從庫 C 要設置為主從庫 B 的從庫的語法如下:
我們把現在這個時刻,實例 B 的 GTID 集合記為set_b,實例 C 的 GTID 集合記為 set_c。接下來,我們就看看現在的主從切換邏輯。
我們在實例 C 上執(zhí)行 start slave
命令,取 binlog 的邏輯是這樣的:
1、實例 C 指定主庫 B,基于主從協(xié)議建立連接。
2、實例 C 把 set_c 發(fā)給主庫 B。
3、實例 B 算出 set_b 與 set_c 的差集,也就是所有存在于 set_b,但是不存在于 set_c 的 GITD 的集合,判斷 B 本地是否包含了這個差集需要的所有 binlog 事務。
a、如果不包含,表示 B 已經把實例 C 需要的 binlog 給刪掉了,直接返回錯誤;
b、如果確認全部包含,B 從自己的 binlog 文件里面,找出第一個不在 set_c 的事務,發(fā)給 C;
之后就從這個事務開始,往后讀文件,按順序取 binlog 發(fā)給 C 去執(zhí)行。
這個邏輯里面包含了一個設計思想:在基于 GTID 的主從關系里,系統(tǒng)認為只要建立主從關系,就必須保證主庫發(fā)給從庫的日志是完整的。因此,如果實例 C 需要的日志已經不存在,B 就拒絕把日志發(fā)給 C。
這跟基于位點的主從協(xié)議不同?;谖稽c的協(xié)議,是由從庫決定的,從庫指定哪個位點,主庫就發(fā)哪個位點,不做日志的完整性判斷。
我們再來看看引入 GTID 后,一主多從的切換場景下,主從切換是如何實現的。
由于不需要找位點了,所以從庫 C、D 只需要分別執(zhí)行 change master
命令指向實例 B 即可。
其實,嚴謹地說,主從切換不是不需要找位點了,而是找位點這個工作,在實例 B 內部就已經自動完成了。但由于這個工作是自動的,所以對HA系統(tǒng)的開發(fā)人員來說,非常友好。
之后這個系統(tǒng)就由新主庫 B 寫入,主庫 B 的自己生成的 binlog 中的 GTID 集合格式是:server_uuid_of_B:1-M
。
GTID 主從同步設置時,主庫 A 發(fā)現需同步的 GTID 日志有刪掉的,那么 A 就會報錯。
解決辦法:
從庫 C 在啟動同步前需要設置 gtid_purged,指定 GTID 同步的起點,使用備份搭建從庫時需要這樣設置。
如果在從庫上執(zhí)行了單獨的操作,導致主庫上缺少 GTID,那么可以在主庫上模擬一個與從庫 C 上 GTID 一樣的空事務,這樣主從同步就不會報錯了。
配合semi-sync
MySQL 有三種同步模式,分別是:
1、異步復制:MySQL 中默認的復制是異步的,主庫在執(zhí)行完客戶端提交的事務后會立即將結果返回給客戶端,并不關心從庫是否已經接收并且處理。存在問題就是,如果主庫的日志沒有及時同步到從庫,然后主庫宕機了,這時候執(zhí)行故障轉移,在從庫沖選主,可能會存在選出的主庫中數據不完整;
2、全同步復制:指當主庫執(zhí)行完一個事務,并且等到所有從庫也執(zhí)行完成這個事務的時候,主庫在提交事務,并且返回數據給客戶端。因為要等待所有從庫都同步到主庫中的數據才返回數據,所以能夠保證主從數據的一致性,但是數據庫的性能必然受到影響;
3、半同步復制:是介于全同步和全異步同步的一種,主庫至少需要等待一個從庫接收并寫入到 Relay Log
文件即可,主庫不需要等待所有從庫給主庫返回 ACK。主庫收到 ACK ,標識這個事務完成,返回數據給客戶端。
MySQL 中默認的復制是異步的,所以主庫和從庫的同步會存在一定的延遲,更重要的是異步復制還可能引起數據的丟失。全同步復制的性能又太差了,所以從 MySQL 5.5
開始,MySQL 以插件的形式支持 semi-sync 半同步復制。
因為本同步復制不需要等待所有的從庫同步成功,這時候在從庫中的查詢,就會面臨兩種情況:
1、如果查詢是落在這個響應了 ack 的從庫上,是能夠確保讀到最新數據;
2、如果是查詢落到其他從庫上,它們可能還沒有收到最新的日志,就會產生過期讀的問題。
等主庫位點方案
理解等主庫位點方案之前,首先來看下下面的這條命令的含義
select master_pos_wait(file, pos[, timeout]);
看下這條命令的幾個參數:
1、這條命令是在從庫中執(zhí)行的;
2、參數 file 和 pos 指的是主庫上的文件名和位置;
3、timeout 可選,設置為正整數 N 表示這個函數最多等待 N 秒。
這條命令的正常返回是一個正整數 M ,表示從命令開始執(zhí)行,到應用完 file 和 pos 表示的 binlog 位置,成功執(zhí)行的事務個數。
如果從庫執(zhí)行這個命令,表示從庫同步完 file 和 pos 表示的 binlog 位置,同步的事務數量,正常返回 M 表示從庫數據在 timeout 時間內相對于主庫已經沒有延遲了。
除了正常返回,也會有其它的執(zhí)行返回信息
1、如果執(zhí)行期間從庫同步發(fā)生異常,就返回 NULL;
2、如果等待超過 N 秒,聚返回 -1;
3、如果剛開始執(zhí)行的時候,就發(fā)現已經執(zhí)行過這個位置了,就返回 0。
弄明白了這條命令的作用,我們再來看下等主庫位點方案的具體執(zhí)行流程,如果我們在主庫中執(zhí)行一個數據更新,然后在從庫中查詢,執(zhí)行的過程就是:
1、更新事務執(zhí)行完成,馬上執(zhí)行 show master status
得到當前主庫執(zhí)行到的 File 和 Position;
2、選定一個從庫執(zhí)行查詢;
3、在從庫上執(zhí)行 select master_pos_wait(File, Position, 1)
;
4、如果返回值是 >=0 的正整數,則在這個從庫執(zhí)行查詢語句;
5、否則到主庫執(zhí)行查詢。
如果從庫的延遲都超過了的等待的 timeout 時間,那么所有的請求,最總還是會落到主庫中,查詢的壓力還是會爬到主庫中。
等 GTID 方案
如果開啟了 GTID 模式,對應的也有等待 GTID 的方案。
MySQL 中同樣提供了等待同步的命令
select wait_for_executed_gtid_set(gtid_set, 1);
執(zhí)行邏輯:
1、從庫在執(zhí)行命令的時候攜帶事務的 gtid,如果返回 0 表示該事務已經正常同步到從庫中,可以在從庫中執(zhí)行查詢;
2、超時測返回 1。
在前面等位點的方案中,我們執(zhí)行完事務后,還要主動去主庫執(zhí)行 show master status
。而 MySQL 5.7.6
版本開始,允許在執(zhí)行完更新類事務后,把這個事務的GTID返回給客戶端,這樣等 GTID 的方案就可以減少一次查詢。
等 GTID 方案的流程就是
1、主庫中執(zhí)行完成一個事務,從返回包直接獲取這個事務的 GTID,記為 gtid1;
2、選定一個從庫執(zhí)行查詢語句;
3、從庫中執(zhí)行 select wait_for_executed_gtid_set(gtid1, 1)
;
4、如果返回值是 0,就在從庫中執(zhí)行查詢;
5、返回值不是 0,表示該事務還沒有同步到從庫中,就需要到主庫中執(zhí)行查詢了。
和等主庫位點方案的方案一樣,等待超時就需要向主庫中發(fā)起查詢了。
總結
1、MySQL 中讀寫分離是經常用到了的架構了,通過讀寫分離實現橫向擴展的能力,寫入和更新操作在源服務器上進行,從服務器中進行數據的讀取操作,通過增大從服務器的個數,能夠極大的增強數據庫的讀取能力;
2、MySQL 數據進行主從同步,主要是通過 binlog 實現的,從庫利用主庫上的binlog進行重播,實現主從同步;
3、數據同步會存在一個問題及時同步延遲;
4、主從同步延遲可能存在的原因:
-
1、從庫的性能比主庫所在的機器性能較差;
-
2、從庫的壓力大;
-
3、大事務的執(zhí)行;
-
4、主庫異常發(fā)生主從或主從切換切換。
5、主從延遲應該如何處理?
面對主從延遲,有下面幾種應對方案:
-
1、強制走主庫方案;
-
2、sleep方案;
-
3、判斷主從無延遲方案;
-
4、配合 semi-sync 方案;
-
5、等主庫位點方案;
-
6、等 GTID 方案。
參考
【高性能MySQL(第3版)】https://book.douban.com/subject/23008813/
【MySQL 實戰(zhàn) 45 講】https://time.geekbang.org/column/100020801
【MySQL技術內幕】https://book.douban.com/subject/24708143/
【MySQL學習筆記】https://github.com/boilingfrog/Go-POINT/tree/master/mysql
【MySQL文檔】https://dev.mysql.com/doc/refman/8.0/en/replication.html
【淺談 MySQL binlog 主從同步】http://www.linkedkeeper.com/1503.html文章來源地址http://www.zghlxwxcb.cn/news/detail-437129.html
到了這里,關于MySQL 中讀寫分離數據延遲的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!