Mysql讀寫分離過期常用解決方案
mysql讀寫分離的坑
讀寫分離的主要目標是分攤主庫的壓力,由客戶端選擇後端資料庫進行查詢。還有種架構就是在MYSQL和客戶端之間有一箇中間代理層proxy,客戶端之連線proxy,由proxy根據請求型別和上下文決定請求的分發路由。
- 客戶端直連方案:因為少了一層proxy轉發,所以查詢效能稍微好一點兒,並且整體架構簡單,排查問題更方便。但是這種方案,由於要了解後端部署細節,所以在出現主備切換、庫遷移等操作的時候,客戶端都會感知到,並且需要調整資料庫連線資訊。
- 帶proxy架構:對客戶端比較友好。客戶端不需要關注後端細節,連線維護、後端資訊維護等工作,都是由proxy完成的。但這樣的話,對後端維護團隊的要求會更高。
無論使用哪種架構,由於主從可能存在延遲,客戶端執行完一個更新事務後馬上發起查詢,如果查詢選擇的是從庫的話,就有可能讀到剛剛的事務更新之前的狀態。這種“在從庫上會讀到系統的一個過期狀態”的現象,我們暫且稱之為“過期讀”。
方案一:強制走主庫方案
將查詢請求分為兩類:
- 對於必須要拿到最新結果的請求,強制將其發到主庫上。比如,在一個交易平臺上,賣家釋出商品以後,馬上要返回主頁面,看商品是否釋出成功。那麼,這個請求需要拿到最新的結果,就必須走主庫。
- 對於可以讀到舊資料的請求,才將其發到從庫上。在這個交易平臺上,買家來逛商鋪頁面,就算晚幾秒看到最新發布的商品,也是可以接受的。那麼,這類請求就可以走從庫。這個方案的最大問題在於會碰到所有查詢都不是“過期讀”的需求,比如金融類業務,這樣就要放棄讀寫分離,所有的壓力都在主庫。採用以下方案。
方案二:Sleep方案
主庫更新後,讀從庫之前先sleep一下,類似執行了select sleep(1)命令,這個方案的假設是,大多數情況下主備延遲在1秒之內,做一個sleep可以有很大概率拿到最新的資料。
以賣家釋出商品為例,商品釋出後,用Ajax直接把客戶端輸入的內容作為“新的商品”顯示在頁面上,而不是真正地去資料庫做查詢。這樣,賣家就可以通過這個顯示,來確認產品已經發布成功了。等到賣家再重新整理頁面,去檢視商品的時候,其實已經過了一段時間,也就達到了sleep的目的,進而也就解決了過期讀的問題。
方案三:判斷主備無延遲方案:
第一種方法:先用show slave status結果里的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(全域性事物ID)確保主備無延遲
- Auto_Position=1 ,表示這對主備關係使用了GTID協議。
- Retrieved_Gtid_Set,是備庫收到的所有日誌的GTID集合;
- Executed_Gtid_Set,是備庫所有已經執行完成的GTID集合。
如果這兩個集合相同,表示備庫接收到的日誌都已經同步完成。
方案四:等主庫位點方案
select master_pos_wait(file,pos[,timeout]);
這條命令是在從庫執行的 ,引數file和pos指的是主庫上的檔名和位置,timeout表示這個函式最多等待N秒。
- 這個命令正常返回的結果是一個正整數M,表示從命令開始執行,到應用完file和pos表示的binlog位置,執行了多少事務。
- 如果備庫同步執行緒發生異常,則返回null
- 如果等待超過N秒,就返回-1
- 如果剛開始執行就發現已經執行過了,則返回0
如圖:先執行trx1,再執行一個查詢請求的邏輯,要保證能夠查到正確的資料,我們可以使用
這個邏輯
1. trx1事物更新完成後,馬上執行show master status得到當前主庫執行到的File和Position;
2. 選定一個從庫執行查詢語句;
3. 在從庫上執行select master_pos_wait(File,Position,1);
4. 如果返回值是>=0的正整數,則在這個從庫執行查詢語句;
5. 否則,到主庫執行查詢語句。
這里我們假設,這條select查詢最多在從庫上等待1秒。那麼,如果1秒內master_pos_wait返回
一個大於等於0的整數,就確保了從庫上執行的這個查詢結果一定包含了trx1的資料。
5到主庫執行查詢語句,是這類方案常用的退化機制。因為從庫的延遲時間不可控,不能無
限等待,所以如果等待超時,就應該放棄,然後到主庫去查。按照我們設定不允許過期讀的要求,就只有兩種選擇,一種是超時放棄,一種是轉到主庫查詢。
併發連線和併發查詢
innodb_thread_concurrency引數是控制innodb的併發執行緒上限。一旦超過這個數值,新請求就會進入等待。
- show processlist看到的幾千個連線,是值併發連線,而當前正在執行的語句,才是併發查詢。併發連線影響不大,只是會多佔記憶體,而併發查詢才是CPU殺手。
- 線上程進入鎖等待以後,併發執行緒的計數會建議,也就是等行鎖的執行緒是不算在併發查詢裡的。因為所等待已經不吃CPU了
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。