本文介紹常見的RDS MySQL只讀實例延遲時間變長的原因及解決方案。
問題描述
由于阿里云云數據庫RDS只讀實例采用MySQL原生的基于日志復制技術(異步復制或半異步復制),必然會有同步延遲。延遲會導致只讀實例與主實例的數據出現不一致,從而導致業務出現問題。另外,延遲也有可能引起日志堆積,導致只讀實例空間被迅速消耗。
若主實例正產生大量的日志,有可能會使只讀實例被鎖定。
日志復制延遲是通過
show slave status \G
命令的second_behind_master(單位為秒)字段顯示的。延遲的計算方法:延遲時長=當前時間(執行
show slave status \G
命令的時間)-當前備庫上正在應用的事務在主庫提交的時間。
按照延遲時長可將延遲分為以下兩種類型:
小于或等于1秒的延遲:由系統延遲計算精度、計算方法、采樣時刻、監控時間粒度引起,無問題,無需關注。
大于1秒的延遲:由只讀實例規格過小、主實例的TPS過高、主實例的大事務、主實例的DDL語句執行時間較長引起,需要排查處理。
問題原因
小于或等于1秒的延遲
小于1秒延遲出現原因:由監控時間范圍設置過長引起,實際并不存在小于1秒的延遲,無需關注。
如果設置的監控時間范圍比較長,就會導致監控的時間粒度比較大。例如,如果監控的時間范圍為3小時,默認的監控的時間粒度就會達到30秒級,每個時刻計算得出的數據就是30秒的平均值,就會出現小于1秒的延遲。而實際每個時刻計算出的延遲最小粒度為1秒。
如果想看到更準確的延遲,可以到RDS控制臺的性能趨勢頁面,將監控時間范圍縮小到6分鐘以內,可以看到時間粒度為1秒的監控值。詳情請參見性能趨勢。
1秒延遲出現原因:由系統延遲計算精度、計算方法、采樣時刻、是否存在跨秒事務引起,實際并不存在1秒的延遲,無需關注。
RDS MySQL中延遲的計算精度是秒級的,會忽略“秒”這一位之后的數據。例如,00:00:00.95會按照00:00:00來計算,00:00:01.05會按照00:00:01來計算。如果采集時刻在整秒剛過(例如00:00:01.05),就可能會導致將不滿1秒的延遲(例如0.15秒)計算為1秒,如下表中第4行所示:
事務
主庫提交時間
備庫提交時間
當前時間(show slave status命令執行的時間)
秒級精度的延遲
Trx1
00:00:00.30
00:00:00.50
00:00:00.35
0(0.35)-0(0.3)=0秒
00:00:00.45
0(0.45)-0(0.3)=0秒
Trx2
00:00:00.90
00:00:01.10
00:00:00.95
0(0.95)-0(0.9)=0秒
00:00:01.05
1(1.05)-0(0.9)=1秒
由于采集的間隔是1整秒,所以每次采集時刻都在整秒剛過,如果有業務壓力、存在跨秒事務,這樣每次都可能采集到1秒的延遲。而如果采集的時刻不是在整秒剛過(例如00:00:00.95),就會將延遲計算為0秒,如上表中第3行所示。
大于1秒的延遲
大于1秒的延遲,由以下幾種可能的原因引起:
只讀實例規格過小
這類延遲場景經常出現在只讀實例規格和主實例規格相差較大,而且只讀實例負載較重的情況下。例如,只讀實例IOPS過高。只讀實例為了和主實例保持同步,采用了MySQL原生的日志復制技術,由一個IO線程和一個SQL線程來完成。IO線程負責將主實例的日志拉取到只讀實例,SQL線程負責將這些日志應用到只讀實例。這兩個線程會消耗只讀實例的IO資源,所以當只讀實例的IOPS配置不高時,會導致只讀實例數據延遲。可以登錄RDS控制臺,通過監控信息確認IOPS較高。
主實例的TPS(Transaction Per Second)過高
由于只讀實例與主實例之前的同步采用的是單線程同步,若主實例并發多線程寫入數據,在主實例TPS過高的情況下容易出現只讀實例的數據延遲,可以通過觀察只讀實例的TPS與主實例的TPS性能數據來判斷。
大事務寫入
主實例執行一個涉及數據量非常大的update、delete、insert…select、replace…select等事務操作時,會生成大量的日志數據并同步到只讀實例。只讀實例需要花費與主實例相同的時間來完成該事務,因此會導致只讀實例同步延遲。例如,在主實例上執行一個持續80秒的刪除操作,只讀實例進行相同操作時也需要花費很長時間,于是會出現延遲情況。
雖然目前支持多表并發事務,但對于單表事務,只能單線程來完成復制,因此也會比較慢。
主實例的DDL語句執行時間較長
只讀實例和主實例數據同步是串行進行的,如果DDL操作在主實例操作的表過大,執行時間很長,或者執行大量慢查詢,則會產生大量的臨時表,將導致磁盤容量不足和磁盤IO增加,從而導致同步延遲。常見操作例如create index、repair table、alter table add column等。
只讀實例上執行的查詢或未完成的事務阻塞了來自主實例的DDL執行。
特殊情況
復制的SQL語句,沒有走到合適的索引,而導致大量的全表掃描,邏輯讀暴漲。
如果某張表中只有唯一索引,沒有主鍵,且唯一索引為空,slave復制時,會優先執行UK的執行計劃,而不是讓優化器選擇。所以即使where條件是個不錯的過濾項,也一定是執行UK的執行計劃。
排查方法
當只讀實例出現延遲時,小于或等于1秒的延遲無問題,無需處理。可以根據排查方法定位大于1秒延遲的原因:
只讀實例規格過小
在RDS控制臺【云數據庫RDS/實例列表「只讀實例」/基本信息/配置信息/實例規格】中查看實例規格,具體規格信息參見RDS MySQL標準版(原X86)只讀實例規格列表、RDS MySQL倚天版(原ARM)只讀實例規格列表。
在RDS控制臺【云數據庫RDS/實例列表「只讀實例」/監控與報警】中查看監控信息,檢查只讀實例的CPU/內存/IO帶寬/連接數,確認只讀實例是否存在資源瓶頸。
主實例的TPS(Transaction Per Second)過高
確認主實例/只讀實例的TPS是否正常,TPS相關數據可以通過自治服務的性能趨勢頁面查看,詳情請參見性能趨勢。
大事務寫入
在大事務同步到只讀實例導致延遲出現時,登錄數據庫,執行
show slave status \G
SQL語句,確認 Seconds_Behind_Master 不斷變化,而 Exec_Master_Log_Pos 卻保持不變,說明只讀實例的SQL線程在執行一個大事務或者DDL操作,系統顯示類似如下結果:最后通過
show processlist;
語句定位具體的線程。只讀實例執行
show slave status \G
命令,確定是否存在元數據鎖。如果binlog是row模式,大事務會導致binlog文件比較大。可以通過命令
show binary logs;
查看File_size的數值,如果大于max_binlog_size參數的大小,則一定是產生了大事務。
主實例的DDL語句執行時間較長
binlog來不及切割而變得很大,檢查只讀實例的binlog增長量,從側面判斷是否存在DDL寫入。
檢查只讀實例是否存在無主鍵表的刪除或者更新操作,可以通過在只讀實例上執行
show engine innodb status \G
語句查看,或者執行show open tables;
語句后,查看輸出結果的in_use列的值為1的表。查看慢日志信息,確認是否存在optimize、alter、repair和create等DDL操作,詳情請參見慢日志分析。
特殊情況【Unique Key為NULL的情況】
通過 sys.schema_index_statistics 視圖,定位業務表是否無主鍵只有唯一索引的字段。
進一步確認符合條件字段是否為NULL。
解決方案
如果對實例或數據有修改、變更等風險操作,務必注意實例的容災、容錯能力,確保數據安全。
如果對實例(包括但不限于ECS、RDS)等進行配置與數據修改,建議提前創建快照或開啟RDS日志備份等功能。
如果在阿里云平臺授權或者提交過登錄賬號、密碼等安全信息,建議及時修改。
根據上述排查方法定位的原因選擇對應的解決方法:
只讀實例規格過小
建議升級只讀實例規格,使只讀實例的配置大于或者等于主實例的配置,避免由于只讀實例規格較小導致延遲,詳情請參見變更配置。
主實例的TPS(Transaction Per Second)過高
如果TPS過高,則需要對業務進行優化或者拆分,保證主實例的TPS不會導致只讀實例出現延遲。
大事務寫入
建議將大事務拆分為小事務分別執行。例如,在delete語句中增加where條件子句,限制每次刪除的數據量,將一次刪除操作拆分為多次數據量較小的刪除操作進行。這樣只讀實例可以迅速地完成事務的執行,不會造成數據的延遲。
主實例的DDL語句執行時間較長
對于DDL直接引起的只讀實例延遲,建議在業務低峰期執行這些DDL。可根據業務情況通過以下方法進行解決:
對于來自主實例的DDL語句在只讀實例上被阻塞的情況:
在只讀實例上執行
show processlist;
語句,確認SQL線程的狀態為“waiting for table metadata lock”。使用kill命令終止只讀實例上引起阻塞的會話,恢復只讀實例和主實例的數據同步,詳情請參見解決MDL鎖導致無法操作數據庫的問題。
特殊情況
可直接對無主鍵業務表添加顯式主鍵即可。
常見問題
Q:為什么我的實例中,部分只讀實例有1秒延遲的現象?
A:每個實例的采集程序、啟動時間都不一樣,有些實例的采集時刻恰巧在剛過整秒的時間點,就會有此現象。其他實例的采集時刻不在剛過整秒的時間點,就不會有這個現象。詳情請參見小于或等于1秒的延遲。
Q:1秒延遲對我的實例有沒有影響?
A:沒有影響。1秒延遲并不代表實際存在1秒的延遲。例如,當實際延遲只有0.1秒時,如果采集時間在剛過整秒的時刻,也會采集到1秒的延遲,它是由系統延遲計算精度、計算方法、采樣時刻引起的。詳情請參見小于或等于1秒的延遲。
建議在配置告警或者代理的讀庫延遲閾值時,要根據自己的實際需求與配置,并滿足:讀庫延遲閾值>1秒。
Q:只讀實例頁面中顯示復制中斷,或收到了 Slave_SQL_Running 或 Slave_IO_Running 的報警,應該如何處理?
A:可以排查以下三個問題:
檢查只讀實例存儲空間是否充足。
當存儲空間不足時,只讀實例無法接收到主實例的Binlog。
說明可以在只讀實例基本信息頁面的使用量統計區域,查看存儲空間使用情況。
檢查復制延遲。
如果復制延遲在5分鐘內連續大于5秒,表示只讀實例延遲過高,會產生復制延遲的報警。導致復制延遲的原因可能是主庫寫入過于頻繁與實例性能不匹配、長期存在大事務等。
說明可以在只讀實例基本信息頁面左側單擊監控與報警,在標準監控頁簽,查看節點復制延遲(second)。
檢查慢日志。
慢日志非常消耗實例性能,可能會增加復制延遲,對復制產生較大影響。
說明可以在只讀實例基本信息頁面,通過以下兩種方式查看慢日志詳情:
在左側單擊日志管理,在慢日志明細頁簽查看。
在左側選擇自治服務>慢SQL,在頁面中查看。
若非上述問題產生的復制中斷,則不需要處理,系統會自動巡檢,修復產生復制中斷的實例。