讀寫分離遇到的問題與解決方案總結


1.ReadOnly標記問題:外部查詢接口需標記只讀,而內部事務內方法調用則不能標記,但都混雜在一起如何區分

解決方案:Dubbo請求入口處標記,如自定義Filter織入標記

2.主從延時導致過期數據加載到緩存問題

解決方案:緩存標記主庫變更,主從延時期間(目前暫定一分鍾,由於現在提前標記,可能需要延長)內從主庫加載數據

3.主庫發生變更到標記本次變更的間隙期間讀請求從從庫加載過期數據問題

解決方案:提前標記結合數據加載前后版本號檢查,使用過期數據重建緩存的概率幾乎為零,詳見下文4和5的解決方案

4.緩存覆蓋問題:查詢變更標記到設置緩存間隔期間(例如從庫慢查詢延時較長)主庫數據發生變更,從從庫加載的過期數據覆蓋緩存,類似的還有主庫段時間內頻繁變更多次,而多線程查詢時,先查詢到中間狀態的數據后返回,最終覆蓋緩存

解決方案:升級緩存的主庫變更標記為版本號,加載數據前查詢一次版本號,從數據庫load完數據后再檢查一次版本號(此次版本號為空例外,其標志版本號過期,數據庫未發生變更),如果兩者不一致,說明數據加載期間有過變更,則本次數據不更新到緩存

5.加載過期緩存且不會被刪除問題:目前程序中有大量事務內刪緩存操作,導致刪除緩存操作在數據變更之前(因為此時事務尚未提交),事務提交前若有查詢請求重建緩存,那么事務提交后主庫數據發生變更,但是緩存將不會被刪除,仍是過期數據

解決方案:AOP切入事務標簽方法,使用本地線程收集事務內刪除緩存的key,此處不做物理刪除,但提前升級變更標記版本號(阻斷主庫變更和標記變更間隙查詢,由於是提前標記,應該考慮延長標記過期時間,因為標記與數據庫實際發生變更之間有可能存在較長延時),事務結束后再刪除緩存

6.事務注解無章法配置可能導致方案5失效從而引發數據一致性問題:

項目中存在大量事務標記有@Transactional(rollbackFor = Exception.class )(checked異常回滾配置)也有@Transactional (默認checked異常不回滾)還有各種嵌套組合,有的還會將unchecked異常包裝成checked異常(如QuarkException),這樣會導致本該回滾的unchecked異常由於被包裝且配置不當而沒有回滾(該問題需要case by case梳理,工作量較大,在時間不允許的情況下后續版本優化),並且在方案5中會導致舊緩存由於拋異常而沒有被刪除,但是事務卻提交了數據庫發生變更,從而引發數據一致性問題

解決方案:AOP切入Spring源碼事務管理器中,在事務提交(commit方法級別,若事務需要回滾,不會進入該方法)主庫發生變更之后立即刪除事務內收集到的緩存,這樣只有真正數據庫發生變更才會刪除緩存,checked異常默認情況下由於不會回滾,也會提交事務,故而也會刪除緩存

7.多層事務嵌套且內層是PROPAGATION_REQUIRES_NEW類型事務場景下,存在部分緩存需提前刪除的情況,且不能刪除外層事務收集的緩存問題:

解決方案:開辟獨立的事務空間,且外層事務可自由獲取內存事務的緩存(相當於包含關系),這樣PROPAGATION_REQUIRES_NEW事務提交時,可僅僅刪除其自身空間以及其可包含的空間內的緩存數據,對其外層空間不影響

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM