C# Memory Cache 踩坑記錄

背景

前些天公司服務器數據庫訪問量偏高,運維人員收到告警推送,安排我團隊小夥伴排查緣由.數據庫

咱們發現原來系統按期會跑一個迴歸測試,該測運行的任務較多,每處理一條任務都會到數據庫中取相關數據,高速地迴歸測試也帶來了高頻率的數據庫讀取.緩存

解決方案1

咱們認爲每一個任務要取的數據截然不同,所以咱們考慮對這個過程進行修改,加入MemoryCache把數據庫中讀取到的數據進行緩存.安全

整個修改很是簡單,相信對常年混跡在博客園中的各位大佬來講小菜一碟,所以小弟再也不敘述添加緩存的步驟細節.服務器

從緩存的添加,代碼提交,Teamcity 編譯經過,到測試環境,QA環境的安裝無比流暢,一切顯得如手到擒來.運維

嗯,優秀是一種習慣, 沒有一點辦法.測試

人生如戲,當咱們還沉浸在"我加的Cache不可能又BUG"的自信中時,QA傳來噩耗,迴歸測試大量未經過 ....日誌

故障排查

以前習慣了使用Redis緩存,所以,常識告訴咱們 ---  在數據庫中數據沒有改動的前提下,加了緩存後讀取的數據的效果和從數據庫中讀取的效果是如出一轍的.對象

除非  ,,,   除非  這個常識是錯誤的....blog

所以咱們加了日誌,對寫入緩存先後讀取出來的數據進行了對比,結果出人意料.ci

image

該死 MemoryCache 毀我老臉,丟我精度,拿命來!!!!!

從日誌中看到,第一行是從數據庫中讀取的結果,第二行是從cache中讀取的,前兩條數據徹底一致,到了第三條,第四條,第五條,仔細觀察發現,在小數點後面,竟然有些小數點後比較微小的變化,無論變化的大小但數據確實發生改變了,因此MemoryCache會影響數據精度??這樣會改變數據精度的MemoryCache又有何用?? 

機智的我,彷佛早已看穿了一切,這確定不是MenoryCache的鍋!!!

不同的MemoryCache

我從https://referencesource.microsoft.com 中扒出了MemoryCache的源碼一探究竟.

image

定位到MemoryCache中的AddOrGetExisting方法,咱們看到,其實咱們把數據存儲到該緩存的過程本質是把該對象存到一個名爲_entries的         Hashtable 中,一樣,取數據也是經過Key到該Hashtable中取出來,整個過程並無對該對象進行序列化反序列等,也沒有對該對象進行clone操做.這就意味着咱們以前存入的,和後面取出的(無論咱們從MemoryCache中取數據取多少次),永遠只取出同一個對象.

這一點,和我以前使用的RedisCache是有很大區別的.咱們在Redis中存入數據,是把對象序列化後存到Redis中,取數據是把Redis中的字節數據反序列成對象,意味着前一次存入的,和後一次取出的,已經不是同一個對象了,所以Redis中的數據是安全的.

猜測

我作出了一個大膽的猜測,以前從MemoryCache中取出來的數據之因此變化了,多是取出對象後,複雜的處理過程當中對該對象進行了什麼修改操做,因此後期,再次從數據庫中讀取數據,讀出來的已經已經不是最初存入的數據,而是前一次修改以後的數據.帶着這個猜測,我對代碼進行了修改.

解決方案2

從MenoryCache中取到數據後對結果進行clone(),這樣即便程序對取出來的結果進行了修改也不會影響Cache中的數據了.

又是一次提心掉到的提交,編譯,安裝後, 迴歸測試順利經過.

感受人生到達了高潮   -_-

把踩得坑分享出來,但願後面的小夥伴引覺得鑑,

相關文章
相關標籤/搜索