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