共計 2648 個字符,預計需要花費 7 分鐘才能閱讀完成。
如何理解 MySQL 高可用數(shù)據(jù)庫內(nèi)核深度優(yōu)化的四重定制,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
近期我們的數(shù)據(jù)庫團隊對原生復制的多個方面進行了深度優(yōu)化,提升了 UDB 高可用數(shù)據(jù)庫的功能和性能。今天借社群這個平臺,跟大家分享一二。
一、UDB 高可用數(shù)據(jù)庫架構
UDB 以虛擬 IP、HAProxy、單節(jié)點 UDB 數(shù)據(jù)庫搭建雙節(jié)點高可用架構:
雙節(jié)點的 UDB 數(shù)據(jù)庫保證數(shù)據(jù)庫數(shù)據(jù)的全量冗余,同時保證數(shù)據(jù)庫的可用性;
HAProxy 在同一時間只連接一個 UDB 節(jié)點,避免多點寫入帶來的數(shù)據(jù)沖突問題;
雙節(jié)點 HAProxy 保證 Proxy 的可用性;
虛擬 IP 在 HAProxy 發(fā)生宕機時通過 IP 漂移的方式對 HAProxy 進行切換,用戶不需要再次修改 IP。
在上述架構中,從節(jié)點 UDB 的數(shù)據(jù)是否完整、是否與主庫保證數(shù)據(jù)一致性是整個高可用架構的關鍵,所以用于數(shù)據(jù)傳輸?shù)陌胪綇椭破鹬陵P重要的作用。針對原生的半同步復制,我們作了內(nèi)核層面的深度優(yōu)化。
二、UDB 數(shù)據(jù)庫深度優(yōu)化
UDB 是以開源數(shù)據(jù)庫 MySQL Community Server 5.7.16 為基線版本,圍繞高可用架構做內(nèi)核深度優(yōu)化。
復制流程,如上圖所示,主要經(jīng)過如下幾個步驟:
MySQL Server 執(zhí)行 SQL 成功后,記錄 binlog;
Dump 線程讀取 binlog 后,發(fā)送到從機 IO 線程;
IO 線程將接收到的 binlog 記錄到 relay log 中,同時記錄接收進度到 master.info 中;
SQL 讀取 relay log 中的日志內(nèi)容進行復現(xiàn),同時記錄復制日志的進度到 relay-log.info 中。
我們在原生復制的基礎上做了內(nèi)核的深度優(yōu)化,針對上述流程中的部分步驟,在功能和性能上做了改進,使得 UDB 更加穩(wěn)定。
1、Binlog 日志復制優(yōu)化
存在的問題
原生半同步復制存在退化問題,在網(wǎng)絡抖動導致超時或者從庫追趕主庫日志進度時,復制會由半同步復制退化為異步復制。
相比于可靠的半同步復制,異步復制過程中,從庫是沒有辦法感知接收到 relay log 與主庫的 binlog 是否一致。如果發(fā)生宕機,也就沒有辦法確認從庫數(shù)據(jù)是否與主庫一致,是否可以發(fā)生數(shù)據(jù)庫切換,這種不確定的情況是我們不希望看到的。
優(yōu)化方案
建立雙通道復制,在原有半同步復制的基礎上增加一條 UDB 復制通道:
建立一條新的復制通道與原有的復制并行,兩條通道互相獨立;
新的復制通道不傳輸數(shù)據(jù),只傳輸主庫的 SQL 執(zhí)行進度 (binlog 的文件名和位置);
新的復制通道使用半同步復制協(xié)議,但是不退化,超時后重連,只接收 *** 的 SQL 執(zhí)行進度 ;
新的復制通道不存在追補數(shù)據(jù)的問題,只要網(wǎng)絡正常的情況下,從庫永遠可以感知 SQL 的執(zhí)行進度。
如上圖所示,當從庫發(fā)生宕機或者網(wǎng)絡發(fā)生故障后,主從復制停止。當從庫復制恢復正常后,原生復制通道通過異步復制的方式進行數(shù)據(jù)追補,UDB 復制通道只接收 *** 的 binlog 記錄位置,這樣可以 *** 限度地減少主從之間異步復制的時間。即在網(wǎng)絡可連通的情況下,無論何時發(fā)生宕機,從庫均知道與主庫是否處于數(shù)據(jù)一致的狀態(tài)(或者落后了多少)。
2、Relay log 文件記錄的優(yōu)化
存在的問題
在 MySQL 中,binlog 是以 event 為基本單位進行記錄,以 MySQL 5.7 ROW 格式 (開啟 GTID) 的 binlog 為例,一個 DML(insert)會以 5 個 event 的格式記錄到 binlog 中(其他操作均以一個或者多個 event 組成,不再一一羅列),分別為:
GTID_EVENT:記錄當前事務的 GTID
QUERY_EVENT:事務開始
TABLE_MAP_EVENT:操作對應的表
WRITE_ROW_EVENT:插入記錄
XID_EVENT:提交事務
全部 event 組成一個完整的事務,完整的事務才會被 SQL 線程正確復現(xiàn)到從庫上。當前 IO 線程接收 binlog 時,是以 event 為單位進行接收,即接收到一個 event,記錄到 relay log 中后再繼續(xù)接收下一個。這種做法是低效的,也沒有充分利用到 MySQL 本身的文件緩存。
優(yōu)化方案
優(yōu)化 IO 線程記錄 relay log 的方式,將以 event 為單位記錄,修改為以事務為單位進行記錄。合并 IO 線程小的 IO 操作,提高 IO 性能。
將單個的 event 寫操作合并為多個 event 統(tǒng)一寫操作,將小的 IO 操作合并成較大的 IO 操作,提高 IO 性能。
3、Master.info 文件記錄的優(yōu)化
存在的問題
Master.info 文件在搭建復制時,記錄主庫 IP、PORT 等連接主庫的相關信息,在復制過程中,記錄 IO 線程從主庫接收到的 binlog 的文件名和位置,文件和位置會在每次記錄 relay log 成功后更新。
在基于 GTID 搭建復制后,master.info 中記錄的 binlog 文件和位置不再作為復制的依據(jù),所以 master.info 中記錄的 binlog 的文件和位置不再是有效的數(shù)據(jù),也就沒有必要每次進行更新。
優(yōu)化方案
在 IO 線程記錄 relay log 成功后,更新 master.info 文件之前,添加判斷。如果開啟了 GTID 并且使用 GTID 作為復制的依據(jù)(auto_position=1),那么不再更新 master.info 中 binlog 的文件和位置。
其它的 master.info 操作仍然保留,如 change master、shutdown 等操作。
4、Relay log 鎖的優(yōu)化
存在的問題
在 IO 線程和 SQL 線程復制進度相似的情況下,在操作 relay log 時,會使用同一塊文件緩存,在讀寫文件緩存時,需要加鎖來保證操作的正確性。而 IO 線程和 SQL 線程需要頻繁地讀寫這塊公共內(nèi)存,就需要對同一把鎖頻繁的競爭,從而導致性能下降。
優(yōu)化方案
將 IO 線程和 SQL 線程對 relay log 的操作拆分開來,不再使用同一塊文件緩存。雖然這樣做會導致 SQL 線程增加一次讀 IO 操作。但是消除了對鎖的競爭,大大地提高了 IO 線程和 SQL 線程整體的性能。
三、總結
優(yōu)化后的復制流程圖如下:
數(shù)據(jù)庫原生復制流程中包括記錄 binlog、記錄 relay log、記錄 master.info、relay-log.info 等,針對上述流程中的部分步驟以及其它未列出的優(yōu)化,在功能和性能上進行改進,UDB 高可用數(shù)據(jù)庫在功能和性能上均得到了明顯的提升。
看完上述內(nèi)容,你們掌握如何理解 MySQL 高可用數(shù)據(jù)庫內(nèi)核深度優(yōu)化的四重定制的方法了嗎?如果還想學到更多技能或想了解更多相關內(nèi)容,歡迎關注丸趣 TV 行業(yè)資訊頻道,感謝各位的閱讀!