因MemoryCache闹了个笑话
前言
是這么一回事:
我正在苦思一個(gè)業(yè)務(wù)邏輯,捋著我還剩不多的秀發(fā),一時(shí)陷入冥想中……
突然聊天圖標(biāo)一頓猛閃,打開(kāi)一看,有同事語(yǔ)音;
大概意思是:同事把項(xiàng)目中Redis部分緩存換成MemoryCache/Memcached,還強(qiáng)調(diào)MemoryCache/Memcached的效率是Redis的2~5倍;
當(dāng)時(shí)我想到的是Memcached,聽(tīng)到的似乎也是,心想:怎么可能,就算有性能差,也不至于那么多;
因?yàn)楫?dāng)時(shí)同事代碼還沒(méi)提交,然后就陷入討論ing,最后還是沒(méi)聊通,我就跑到同事那當(dāng)面溝通(要去打架嗎,不不不,文明人);
溝通中…..,好幾分鐘過(guò)去了,突然同事說(shuō):他用的是微軟的MemoryCache;
雖然從讀音上我還沒(méi)區(qū)分出來(lái),但一聽(tīng)微軟,我就感覺(jué)我成笑話啦;
然后趕緊讓同事打開(kāi)代碼,我擦,真成笑話啦,還理直氣壯的溝通了好幾十分鐘。
為什么會(huì)那么“理直氣壯”?
對(duì)Memcached(聽(tīng)錯(cuò)的)性能高于Redis的2~5倍產(chǎn)生重大懷疑,經(jīng)驗(yàn)告訴我不可能,除非Redis用法有問(wèn)題;
同事把Redis換成Memcached(聽(tīng)錯(cuò)的),那肯定不行的,前期的技術(shù)選型,Memcached不太符合項(xiàng)目應(yīng)用場(chǎng)景;
最后因?yàn)?strong>MemoryCache成就了一場(chǎng)笑話,那MemoryCache和Memcached有什么區(qū)別呢?
MemoryCache不是分布式緩存,是基于程序存儲(chǔ)在內(nèi)存中的;是微軟封裝好的內(nèi)存緩存庫(kù),合理利用CPU,性能好;由于基于程序分配內(nèi)存,使用時(shí)避免了網(wǎng)絡(luò)通訊的消耗。
Memcached是分布式緩存,是存儲(chǔ)在公共機(jī)器上的,供不同程序使用的,存在一定的網(wǎng)絡(luò)傳輸消耗。
這樣比較感覺(jué)有點(diǎn)勉強(qiáng),雖然Memcached是分布式的,但也是基于內(nèi)存的,在數(shù)據(jù)存儲(chǔ)內(nèi)存的邏輯還是不同的,不過(guò)這里不打算講解源碼,我要說(shuō)應(yīng)用,哈哈哈。
附加-為什么Redis讓同事感覺(jué)性能不好
真實(shí)場(chǎng)景是這樣的,客戶端開(kāi)啟多線程頻繁讀取Redis數(shù)據(jù),當(dāng)訪問(wèn)比較多時(shí),導(dǎo)致Redis讀取數(shù)據(jù)超過(guò)20毫秒,對(duì)于Web項(xiàng)目來(lái)說(shuō)其實(shí)這還好,20毫秒的響應(yīng)用戶根本無(wú)法感知。但對(duì)于一個(gè)高性能要求的服務(wù)程序來(lái)說(shuō),對(duì)通訊要求就比較高,所以簡(jiǎn)單分析了一下拖慢的原因,大概以下兩點(diǎn):
客戶端增多,導(dǎo)致一個(gè)常用Key對(duì)應(yīng)的數(shù)據(jù)變大(其實(shí)不大,只是相對(duì)大,稍微影響了讀取速度,毫秒級(jí)別);
解決方案:同事使用MemoryCache多做一層緩存,將這個(gè)常用Key直接存在內(nèi)存中,提高讀取性能;
使用類似于Keys * 的命令頻繁獲取數(shù)據(jù),導(dǎo)致有些命令執(zhí)行在20毫秒左右(慢日志中可以看到);
解決方案:改用Scan類似命令獲取數(shù)據(jù);
Redis自身的持久化耗時(shí);
解決方案:適當(dāng)調(diào)整Redis持久化策略,讓持久化頻率沒(méi)那么高;
正文
回歸正題,既然說(shuō)到MemoryCache,就來(lái)簡(jiǎn)單聊聊,主要分享在項(xiàng)目實(shí)戰(zhàn)中如何使用;
主要依賴包:Microsoft.Extensions.Caching.Memory;
MemoryCache的使用很簡(jiǎn)單,就是在調(diào)用方法設(shè)置和獲取值就對(duì)啦;來(lái)直接看Demo吧;
1. 控制臺(tái)Demo
其實(shí)有很多程序是基于后臺(tái)服務(wù)運(yùn)行的,并不都是Web,所以寫(xiě)了一個(gè)控制臺(tái)的Demo,方便小伙伴參考;
1.1 引入相關(guān)包,項(xiàng)目中使用了Autofac作為依賴注入和其切面編程,則需要引入相關(guān)的依賴包,項(xiàng)目結(jié)構(gòu)和包引入如下圖:
1.2 編寫(xiě)示例代碼及注冊(cè)相關(guān)服務(wù)
IUserService就是簡(jiǎn)單接口;
接口和方法上標(biāo)注的Intercept和MyCache特性不是必須的,接下來(lái)會(huì)說(shuō);
UserService對(duì)接口的實(shí)現(xiàn);
MyCacheAttribute自定義特性,用于標(biāo)識(shí),里面沒(méi)有任何邏輯處理;
MyInterceptor自定義攔截器,面向切面的邏輯代碼在這里處理;
代碼完了,就開(kāi)始使用Autofac注冊(cè)服務(wù),進(jìn)行使用啦,如下:
注:Autofac不是必須的,根據(jù)自己需要進(jìn)行選擇使用,這里是為了要使用Autofac的切面編程功能。
1.3 兩種方式進(jìn)行緩存處理
通常在非Web程序中,有以下兩種方式進(jìn)行緩存處理:
代碼嵌入到業(yè)務(wù)邏輯,在真實(shí)業(yè)務(wù)邏輯處進(jìn)行緩存獲取或設(shè)置;
這樣很大一個(gè)缺點(diǎn)是每一個(gè)緩存的數(shù)據(jù)都需要手動(dòng)到指定業(yè)務(wù)邏輯中添加緩存處理,代碼后期不好維護(hù),緩存功能的開(kāi)啟和關(guān)閉也不好控制,需要修改代碼進(jìn)行滿足。
面向切面編程,無(wú)需嵌入多余代碼到業(yè)務(wù)中
通過(guò)面向切面的思想,以動(dòng)態(tài)代理的原理攔截方法,在方法前后進(jìn)行處理,如下:
緩存邏輯直接放在攔截器中處理即可,如下:
注冊(cè)服務(wù)時(shí),開(kāi)啟Autofac的面向切面功能即可
運(yùn)行看效果,第二次都是從緩存中獲取數(shù)據(jù),美美噠:
注:推薦使用面向切面的形式進(jìn)行處理,這樣緩存功能可插拔,代碼維護(hù)性也好。
2.WebApiDemo(項(xiàng)目名稱為:MemoryCacheWebApiDemo)
在WebApi中使用就比較簡(jiǎn)單啦,關(guān)于MemoryCache的依賴包已經(jīng)集成在框架中,如果需要使用,直接注冊(cè)服務(wù)就可以用啦;通常在WebApi中進(jìn)行緩存處理的方式有三種:
中間件形式:通過(guò)自定義中間件進(jìn)行緩存邏輯操作;
過(guò)濾器形式:使用MVC相關(guān)過(guò)濾器進(jìn)行緩存邏輯操作;
業(yè)務(wù)層面向切面形式:面向切面的方式,在業(yè)務(wù)層做緩存,集成Autofac即可,和控制臺(tái)Demo的面向切面一樣;
這里就用過(guò)濾器的形式進(jìn)行Demo演示,走起來(lái)~~~
2.1 編寫(xiě)過(guò)濾器
緩存如果能在最前面處理,就優(yōu)先在最前面,所以使用的ResourceFilter過(guò)濾器;關(guān)于過(guò)濾器之前寫(xiě)過(guò)一篇文章很詳細(xì)(跟我一起學(xué).NetCore之MVC過(guò)濾器,這篇看完走路可以仰著頭走),這里就不贅述了。
然后在Startup.cs中注冊(cè)服務(wù)和將自定義過(guò)濾器注冊(cè)即可,如下:
然后啟動(dòng)運(yùn)行,多次請(qǐng)求調(diào)試看看效果(小伙伴自己在過(guò)濾器中調(diào)試即可);
在WebApi中也可以使用業(yè)務(wù)層面向切面的方式進(jìn)行相關(guān)業(yè)務(wù)處理,集成Autofac即可;小伙伴可以參照這篇文章(跟我一起學(xué).NetCore之Asp.NetCore中集成Autofac擴(kuò)展)。關(guān)于AOP面向切面編程這塊,后續(xù)單獨(dú)整理一篇分享;
源碼地址:https://github.com/zyq025/DotNetCoreStudyDemo
總結(jié)
在一些開(kāi)發(fā)項(xiàng)目中,可能會(huì)使用Dictionary進(jìn)行數(shù)據(jù)緩存,如果是這樣,可以嘗試使用MemoryCache,性能合理利用CPU,而且還是線程安全的;另外在高并發(fā)場(chǎng)景,可以用其作為多級(jí)緩存,因?yàn)镸emoryCache還能設(shè)置過(guò)期時(shí)間,搭配Redis配合使用,效果杠杠的。
一個(gè)被程序搞丑的帥小伙,關(guān)注"Code綜藝圈",跟我一起學(xué)~~~
總結(jié)
以上是生活随笔為你收集整理的因MemoryCache闹了个笑话的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 从工作经历和实践理论看工业互联网的发展
- 下一篇: 如何友好的处理 WebApi 中抛出的错