C# Memory Cache 踩坑记录
背景
前些天公司服務器數(shù)據(jù)庫訪問量偏高,運維人員收到告警推送,安排我團隊小伙伴排查原因.
我們發(fā)現(xiàn)原來系統(tǒng)定期會跑一個回歸測試,該測運行的任務較多,每處理一條任務都會到數(shù)據(jù)庫中取相關(guān)數(shù)據(jù),高速地回歸測試也帶來了高頻率的數(shù)據(jù)庫讀取.
解決方案1
我們認為每個任務要取的數(shù)據(jù)大相徑庭,因此我們考慮對這個過程進行修改,加入MemoryCache把數(shù)據(jù)庫中讀取到的數(shù)據(jù)進行緩存.
整個修改非常簡單,相信對常年混跡在博客園中的各位大佬來說小菜一碟,因此小弟不再敘述添加緩存的步驟細節(jié).
從緩存的添加,代碼提交,Teamcity 編譯通過,到測試環(huán)境,QA環(huán)境的安裝無比流暢,一切顯得如手到擒來.
嗯,優(yōu)秀是一種習慣, 沒有一點辦法.
人生如戲,當我們還沉浸在"我加的Cache不可能又BUG"的自信中時,QA傳來噩耗,回歸測試大量未通過 ....
故障排查
之前習慣了使用Redis緩存,因此,常識告訴我們 ---? 在數(shù)據(jù)庫中數(shù)據(jù)沒有改動的前提下,加了緩存后讀取的數(shù)據(jù)的效果和從數(shù)據(jù)庫中讀取的效果是一模一樣的.
除非? ,,,?? 除非? 這個常識是錯誤的....
因此我們加了日志,對寫入緩存前后讀取出來的數(shù)據(jù)進行了對比,結(jié)果出人意料.
該死 MemoryCache 毀我老臉,丟我精度,拿命來!!!!!
從日志中看到,第一行是從數(shù)據(jù)庫中讀取的結(jié)果,第二行是從cache中讀取的,前兩條數(shù)據(jù)完全一致,到了第三條,第四條,第五條,仔細觀察發(fā)現(xiàn),在小數(shù)點后面,居然有些小數(shù)點后比較微小的變化,不管變化的大小但數(shù)據(jù)確實發(fā)生改變了,所以MemoryCache會影響數(shù)據(jù)精度??這樣會改變數(shù)據(jù)精度的MemoryCache又有何用???
機智的我,似乎早已看穿了一切,這肯定不是MenoryCache的鍋!!!
不一樣的MemoryCache
我從https://referencesource.microsoft.com?中扒出了MemoryCache的源碼一探究竟.
定位到MemoryCache中的AddOrGetExisting方法,我們看到,其實我們把數(shù)據(jù)存儲到該緩存的過程本質(zhì)是把該對象存到一個名為_entries的???????? Hashtable 中,同樣,取數(shù)據(jù)也是通過Key到該Hashtable中取出來,整個過程并沒有對該對象進行序列化反序列等,也沒有對該對象進行clone操作.這就意味著我們之前存入的,和后面取出的(不管我們從MemoryCache中取數(shù)據(jù)取多少次),永遠只取出同一個對象.
這一點,和我之前使用的RedisCache是有很大區(qū)別的.我們在Redis中存入數(shù)據(jù),是把對象序列化后存到Redis中,取數(shù)據(jù)是把Redis中的字節(jié)數(shù)據(jù)反序列成對象,意味著前一次存入的,和后一次取出的,已經(jīng)不是同一個對象了,因此Redis中的數(shù)據(jù)是安全的.
猜想
我做出了一個大膽的猜想,之前從MemoryCache中取出來的數(shù)據(jù)之所以變化了,可能是取出對象后,復雜的處理過程中對該對象進行了什么修改操作,所以后期,再次從數(shù)據(jù)庫中讀取數(shù)據(jù),讀出來的已經(jīng)已經(jīng)不是最初存入的數(shù)據(jù),而是前一次修改之后的數(shù)據(jù).帶著這個猜想,我對代碼進行了修改.
解決方案2
從MenoryCache中取到數(shù)據(jù)后對結(jié)果進行clone(),這樣即使程序?qū)θ〕鰜淼慕Y(jié)果進行了修改也不會影響Cache中的數(shù)據(jù)了.
又是一次提心掉到的提交,編譯,安裝后, 回歸測試順利通過.
感覺人生到達了高潮?? -_-
把踩得坑分享出來,希望后面的小伙伴引以為鑒,
原文地址:https://www.cnblogs.com/CoderAyu/p/10242230.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的C# Memory Cache 踩坑记录的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NET Core中的一个接口多种实现的
- 下一篇: C#如何安全、高效地玩转任何种类的内存之