日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

《MySQL——如何解决一主多从的读写分离的过期读问题》

發布時間:2023/12/1 数据库 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《MySQL——如何解决一主多从的读写分离的过期读问题》 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

    • 兩種架構
    • 兩種架構特點
    • 強制走主庫方案
    • Sleep方案
    • 判斷主備無延遲方案
    • 配合semi-sync
    • 等主庫位點方案
    • GTID方案

兩種架構

基于一主多從的讀寫分離,如何處理主備延遲導致的讀寫分離問題。

讀寫分離的主要目標:分攤主庫壓力。

有兩種架構:

1、客戶端主動做負載均衡,把數據庫的連接信息放在客戶端的連接層。由客戶端選擇后端數據庫進行查詢。

2、MySQL和客戶端之間加上一個中間代理層proxy,客戶端只連接proxy,由proxy根據請求類型和上下文決定請求的分發路由

兩種架構特點

1、客戶端直連方案,少了一層proxy轉發,查詢性能較好,結構也比較簡單。

由于要了解后端部署細節,所以在出現主備切換、庫遷移等操作時,客戶端都會感知到,并且調整數據庫連接信息。客戶端再分配一個負責管理后端的組件,讓業務端只注重于業務邏輯開發

2、帶proxy的架構,使客戶端不需要關注后端細節。

連接維護、后端信息維護等工作,都是由proxy完成的。但是架構整體相對復雜

兩種架構都會遇到"過期讀"問題:

由于主從可能存在延遲,客戶端執行完一個更新事務后馬上發起查詢,如果查詢選擇的是從庫的話,就有可能讀到的是事務更新之前的狀態。

客戶端希望的是查詢從庫的數據結果和查主庫的數據結果是一樣的。

下面是解決方案:

強制走主庫方案; sleep方案; 判斷主備無延遲方案; 配合semi_sync方案; 等主庫位點方案; 等GTID方案;

實際應用中,這幾個方案可以混合使用。

比如,現在客戶端對請求做分類,區分哪些請求可以接受過期讀,哪些請求完全不餓能接受過期讀。然后,對于不能接受過期讀的語句,再使用等GTID或等位點的方案,

過期讀本質上是由一寫多讀導致的,為了避免過期讀,只有兩種選擇:

1、超時放棄

2、轉到主庫查詢

強制走主庫方案

將查詢請求做分類:

1、對于必須要拿到最新結果的請求,強制將其發到主庫上。

2、對于可以讀到舊數據的請求,才將其發到從庫上。

這種方案雖然取巧,但是好用。

此方案最大的問題在于:當遇到實時性比較高要求的業務需求,就要放棄讀寫分離,所有的讀寫壓力都在主庫,等同于放棄了擴展性。

Sleep方案

主庫更新后,讀從庫之前先sleep。如執行一條select sleep(1)命令。

方案假設:大多數情況下主備延遲在1s之內,做一個sleep可以有很大概率拿到到最新的數據

該方案不精確:

1、如果這個查詢請求0.1s就能在從庫拿到正確結果,sleep(1)也會等1s

2、如果延遲超過1s,還是會出現過期讀

判斷主備無延遲方案

要確保備庫無延遲有三種做法:

在show slave status結果里的seconds_behind_master參數可以用來衡量主備延遲時間的長短。

第一種方法

每次從庫執行查詢請求前,先判斷seconds_behind_master是否等于0,如果不等于0就要等到這個參數變為0才執行查詢操作。

第二種方法

比對位點確保主備無延遲。

  • Master_Log_File 和 Read_Master_Log_Pos,表示的是讀到的主庫的最新位點;

  • Relay_Master_Log_File 和 Exec_Master_Log_Pos,表示的是備庫執行的最新位點;

如果Master_Log_File 和 Relay_Master_Log_File 值相同,且Read_Master_Log_Pos和Exec_Master_Log_Pos相同,說明接受到的日志已經同步完成。

第三種方法

對比GTID集合確保主備無延遲

Auto_Position = 1,表示這對主備關系使用了GTID協議 Retrieved_Gtid_Set,是備庫收到的所有日志的GTID集合 Executed_Gtid_Set,是備庫所有已經執行完成的GTID集合

如果兩個集合相同,表示備庫接收到了日志都已同步完成。

一個事務的binlog在主備庫之間的狀態:

1、主庫執行完成,寫入binlog,并反饋給客戶端;

2、binlog被從主庫發送給備庫,備庫收到

3、在備庫執行binlog完成。

我們上面判斷主備無延遲的邏輯是"備庫收到的日志都執行完成了",但是有一部分日志會處于客戶端已經收到提交確認,而備庫還沒收到日志的狀態。

在主庫上執行完成了三個事務trx1、trx2、trx3,前兩個已經傳到從庫并且執行完成了。trx3在主庫執行完成,并且已經回復給客戶端,但是還沒有傳到從庫中。此時在從庫B上執行查詢請求,按照上面的三個方法的邏輯,從庫會認為已經沒有同步延遲,但是還是會查不到trx3.

配合semi-sync

解決上面的問題,要引入半同步復制,即semi-sync replication

semi-sync是這樣做的:

1、事務提交的時候,主庫把binlog發給從庫;

2、從庫收到binlog以后,發回給主庫一個ack,表示收到了

3、主庫收到這個ack以后,才能給客戶端返回"事務完成"的確認

也就是說,如果啟用了semi-sync,就說明所有給客戶端發送過確認的事務備庫都已經收到了日志。

semi-sync+位點的判斷方案,在一主一備場景是成立的,在一主多從場景中,主庫只要等到一個從庫的ack,就開始給客戶端返回確認。

但是這樣會出現問題:

1、查詢落到沒有收到最新日志的從庫上,產生過期讀。

2、業務更新高峰期,主庫的位點或者GTID集合更新很快,兩個位點的等值判斷一直不成立,很可能出現從庫上遲遲無法響應查詢請求的情況

等主庫位點方案

select master_pos_wait(file, pos[, timeout]);

這個命令邏輯如下:

1、在從庫執行

2、參數file和pos指的是主庫的文件名和位置

3、timeout可選,設置為正整數N表示這個函數最多等待N秒

4、返回正整數M,表示從命令開始執行,到應用完file和pos表示的binlog位置執行了多少事務

返回值還有一下異常結果:

1、NULL,執行期間,備庫同步線程發生異常。

2、-1,等待時間超過N秒

3、0,這個位置已經執行過了

使用該方法步驟:

1、事務trx1更新完后,馬上執行show master status得到當前主庫執行到的File和Position

2、選定一個從庫執行查詢語句

3、在從庫上執行select master_pos_wait(File,Position,1)

4、如果返回值是>=0的正整數,則在這個從庫執行查詢語句

5、否則到主庫執行查詢語句。

假設,每條select最多在從庫上等待1s,如果1s內master_pos_wait返回一個>=0的整數,就確保了從庫上執行的這個查詢結果一定包含trx1數據。

如果每個從庫都延遲超過了1s,查詢壓力都會跑到主庫上去。

但是為了不允許過期讀,只有兩種方法:1、超時放棄 2、轉到主庫查詢

GTID方案

select wait_for_executed_gtid_set(gtid_set, 1);

命令邏輯是:

1、等待,直到這個庫執行的事務中包含傳入的gtid_set,返回0

2、超時返回1

等GTID的執行流程為:

1、事務trx1更新后,從返回包直接獲取這個事務GTID,記為gtid1

2、選定一個從庫執行查詢語句

3、在從庫上執行select wait_for_executed_gtid_set(gtid1,1)

4、如果返回值為0,在這個從庫中執行查詢語句

5、否則,到主庫執行查詢語句

tips:使MySQL在執行事務后,返回包中帶上GTID:

( 1. session_track_gtids設置為OWN_GTID 2. 通過API接口獲取mysql_session_track_get_first解析出gtid的值 )

總結

以上是生活随笔為你收集整理的《MySQL——如何解决一主多从的读写分离的过期读问题》的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。