.NET性能優化-使用內存+磁盤混合緩存

我們回顧一下上一篇文章中的內容,有一個朋友問我這樣一個問題:

我的業務依賴一些數據,因為數據庫訪問慢,我把它放在 Redis 里面,不過還是太慢了,有什么其它的方案嗎?

其實這個問題比較簡單的是吧?Redis 其實屬于網絡存儲,我對照下面的這個表格,可以很容易的得出結論,既然網絡存儲的速度慢,那我們就可以使用內存 RAM 存儲,把放 Redis 里面的數據給放內存里面就好了。

操作速度
執行指令1/1,000,000,000 秒 = 1 納秒
從一級緩存讀取數據0.5 納秒
分支預測失敗5 納秒
從二級緩存讀取數據7 納秒
使用 Mutex 加鎖和解鎖25 納秒
從主存(RAM 內存)中讀取數據100 納秒
在 1Gbps 速率的網絡上發送 2Kbyte 的數據20,000 納秒
從內存中讀取 1MB 的數據250,000 納秒
磁頭移動到新的位置(代指機械硬盤)8,000,000 納秒
從磁盤中讀取 1MB 的數據20,000,000 納秒
發送一個數據包從美國到歐洲然后回來150 毫秒 = 150,000,000 納秒

提出這個方案以后,接下來就遇到了另外一個問題:

但是數據比我應用的內存大,這怎么辦呢?

在上篇文章中,我們提到了使用 FASTER 作為內存+磁盤混合緩存的方案,但是由于 FASTER 的 API 比較難使用,另外在純內存場景中表現不如ConcurrentDictionary,所以最后得出的結論也是僅供參考。

經過一段時間的研究,筆者實現了一個基于微軟 FasterKv 封裝的進程內混合緩存庫(內存+磁盤),它有著更加易用的 API,接下來就和大家討論討論它。

FasterKvCache 架構

這里需要簡單的說一說 FasterKvCache 的架構,它核心使用的 FasterKv,所以架構實際上和 FasterKv 一致,其原理比較復雜,所以筆者簡化了原理圖,大概就如下所示:

86eca8ac83e3655438d8a5b66246cd43.png

FasterKv 的熱數據會在內存中,而全量的數據會持久化在磁盤中。這中間有一些緩存淘汰算法,所以大家看到這張圖就能明白 FasterKvCache 適用和不適用哪些場景了。bca78ffad5c0463cef1f1aaf68ba2ba8.png

如何使用它

筆者之前給 EasyCaching 提交了 FasterKv 的實現,但是由于有一些 EasyCaching 的高級功能在 FasterKv 上目前無法高性能的實現,所以單獨創建了這個庫,提供高性能和最基本的 API 實現;如果大家已經使用了 EasyCaching,那么可以直接使用 EasyCaching.FasterKv 這個 NuGet 包。

如果使用需要 FasterKvCache 的話,只需要安裝 Nuget 包,Nuget 包不同的功能如下所示,其中序列化包可以只安裝自己需要的即可。

軟件包名版本備注
FasterKv.Cache.Core[1]1.0.0-rc1緩存核心包,包含 FasterKvCache 主要的 API
FasterKv.Cache.MessagePack[2]1.0.0-rc1基于 MessagePack 的磁盤序列化包,它具有著非常好的性能,但是需要注意它稍微有一點使用門檻,大家可以看它的文檔。
FasterKv.Cache.SystemTextJson[3]1.0.0-rc1基于 System.Text.Json 的磁盤序列化包,它是.NET 平臺上性能最好 JSON 序列化封裝,但是比 MessagePack 差。不過它易用性非常好,無需對緩存實體進行單獨配置。

使用

直接使用

我們可以直接通過new FasterKvCache(...)的方式使用它,目前它只支持基本的三種操作GetSetDelete。為了方便使用和性能的考慮,我們將 FasterKvCache 分為兩種 API 風格,一種是通用對象風格,一種是泛型風格。

  • 通用對象:直接使用new FasterKvCache(...)創建,可以存放任意類型的 Value。它底層使用object類型存儲,所以內存緩沖內訪問值類型對象會有裝箱和拆箱的開銷。

  • 泛型:需要使用new FasterKvCache<T>(...)創建,只能存放T類型的 Value。它底層使用T類型存儲,所以內存緩沖內不會有任何開銷。

當然如果內存緩沖不夠,對應的 Value 被淘汰到磁盤上,那么同樣都會有讀寫磁盤、序列化和反序列化開銷。

通用對象版本

代碼如下所示,同一個 cache 實例可以添加任意類型:

using?FasterKv.Cache.Core;
using?FasterKv.Cache.Core.Configurations;
using?FasterKv.Cache.MessagePack;//?create?a?FasterKvCache
var?cache?=?new?FasterKv.Cache.Core.FasterKvCache("MyCache",new?DefaultSystemClock(),new?FasterKvCacheOptions(),new?IFasterKvCacheSerializer[]{new?MessagePackFasterKvCacheSerializer{Name?=?"MyCache"}},null);var?key?=?Guid.NewGuid().ToString("N");//?sync
//?set?key?and?value?with?expiry?time
cache.Set(key,?"my?cache?sync",?TimeSpan.FromMinutes(5));//?get
var?result?=?cache.Get<string>(key);
Console.WriteLine(result);//?delete
cache.Delete(key);//?async
//?set
await?cache.SetAsync(key,?"my?cache?async");//?get
result?=?await?cache.GetAsync<string>(key);
Console.WriteLine(result);//?delete
await?cache.DeleteAsync(key);//?set?other?type?object
cache.Set(key,?new?DateTime(2022,2,22));
Console.WriteLine(cache.Get<DateTime>(key));

輸出結果如下所示:

my?cache?sync
my?cache?async
2022/2/22?0:00:00
泛型版本

泛型版本的話性能最好,但是它只允許添加一個類型,否則代碼將編譯不通過:

//?create?a?FasterKvCache<T>
//?only?set?T?type?value
var?cache?=?new?FasterKvCache<string>("MyTCache",new?DefaultSystemClock(),new?FasterKvCacheOptions(),new?IFasterKvCacheSerializer[]{new?MessagePackFasterKvCacheSerializer{Name?=?"MyTCache"}},null);

Microsoft.Extensions.DependencyInjection

當然,我們也可以直接使用依賴注入的方式使用它,用起來也非常簡單。按照通用和泛型版本的區別,我們使用不同的擴展方法即可:

var?services?=?new?ServiceCollection();
//?use?AddFasterKvCache
services.AddFasterKvCache(options?=>
{//?use?MessagePack?serializeroptions.UseMessagePackSerializer();
},?"MyKvCache");var?provider?=?services.BuildServiceProvider();//?get?instance?do?something
var?cache?=?provider.GetService<FasterKvCache>();

泛型版本需要調用相應的AddFasterKvCache<T>方法:

var?services?=?new?ServiceCollection();
//?use?AddFasterKvCache<string>
services.AddFasterKvCache<string>(options?=>
{//?use?MessagePack?serializeroptions.UseMessagePackSerializer();
},?"MyKvCache");var?provider?=?services.BuildServiceProvider();//?get?instance?do?something
var?cache?=?provider.GetService<FasterKvCache<string>>();

配置

FasterKvCache 構造函數

public?FasterKvCache(string?name,?//?如果存在多個Cache實例,定義一個名稱可以隔離序列化等配置和磁盤文件ISystemClock?systemClock,?//?當前系統時鐘,new?DefaultSystemClock()即可FasterKvCacheOptions??options,?//?FasterKvCache的詳細配置,詳情見下文IEnumerable<IFasterKvCacheSerializer>??serializers,?//?序列化器,可以直接使用MessagePack或SystemTextJson序列化器ILoggerFactory??loggerFactory)?//?日志工廠?用于記錄FasterKv內部的一些日志信息

FasterKvCacheOptions 配置項

對于 FasterKvCache,有著和 FasterKv 差不多的配置項,更詳細的信息大家可以看FasterKv-Settings[4],下方是 FasterKvCache 的配置:

  • IndexCount:FasterKv 會維護一個 hash 索引池,IndexCount 就是這個索引池的 hash 槽數量,一個槽為 64bit。需要配置為 2 的次方。如 1024(2 的 10 次方)、 2048(2 的 11 次方)、65536(2 的 16 次方) 、131072(2 的 17 次方)。默認槽數量為 131072,占用 1024kb 的內存。

  • MemorySizeBit: FasterKv 用來保存 Log 的內存字節數,配置為 2 的次方數。默認為 24,也就是 2 的 24 次方,使用 16MB 內存。

  • PageSizeBit:FasterKv 內存頁的大小,配置為 2 的次方數。默認為 20,也就是 2 的 20 次方,每頁大小為 1MB 內存。

  • ReadCacheMemorySizeBit:FasterKv 讀緩存內存字節數,配置為 2 的次方數,緩存內的都是熱點數據,最好設置為熱點數據所占用的內存數量。默認為 20,也就是 2 的 20 次方,使用 16MB 內存。

  • ReadCachePageSizeBit:FasterKv 讀緩存內存頁的大小,配置為 2 的次方數。默認為 20,也就是 2 的 20 次方,每頁大小為 1MB 內存。

  • LogPath:FasterKv 日志文件的目錄,默認會創建兩個日志文件,一個以.log結尾,一個以obj.log結尾,分別存放日志信息和 Value 序列化信息,注意,不要讓不同的 FasterKvCache 使用相同的日志文件,會出現不可預料異常默認為{當前目錄}/FasterKvCache/{進程 Id}-HLog/{實例名稱}.log

  • SerializerName:Value 序列化器名稱,需要安裝序列化 Nuget 包,如果沒有單獨指定Name的情況下,可以使用MessagePackSystemTextJson默認無需指定

  • ExpiryKeyScanInterval:由于 FasterKv 不支持過期刪除功能,所以目前的實現是會定期掃描所有的 key,將過期的 key 刪除。這里配置的就是掃描間隔。默認為 5 分鐘

  • CustomStore:如果您不想使用自動生成的實例,那么可以自定義的 FasterKv 實例。默認為 null

所以 FasterKvCache 所占用的內存數量基本就是(IndexCount*64)+(MemorySize)+ReadCacheMemorySize,當然如果 Key 的數量過多,那么還有加上OverflowBucketCount * 64

容量規劃

從上面提到的內容大家可以知道,FasterKvCache 所占用的內存字節基本就是(IndexCount * 64)+(MemorySize) + ReadCacheMemorySize + (OverflowBucketCount * 64)。磁盤的話就是保存了所有的數據+對象序列化的數據,由于不同的序列化協議有不同的大小,大家可以先進行測試。

內存數據存儲到 FasterKv 存儲引擎,每個 key 都會額外元數據信息,存儲空間占用會有一定的放大,建議在磁盤空間選擇上,留有適當余量,按實際存儲需求的 1.2 - 1.5 倍預估。

如果使用內存存儲 100GB 的數據,總的訪問 QPS 不到 2W,其中 80%的數據都很少訪問到。那么可以使用 【32GB 內存 + 128GB 磁盤】 存儲,節省了近 70GB 的內存存儲,內存成本可以下降 50%+。

性能

目前作者還沒有時間將 FasterKvCache 和其它主流的緩存庫進行比對,現在只對 FasterKvCache、EasyCaching.FasterKv 和 EasyCaching.Sqlite 做的比較。下面是 FasterKVCache 的配置,總占用約為 2MB。

services.AddFasterKvCache<string>(options?=>
{options.IndexCount?=?1024;options.MemorySizeBit?=?20;options.PageSizeBit?=?20;options.ReadCacheMemorySizeBit?=?20;options.ReadCachePageSizeBit?=?20;//?use?MessagePack?serializeroptions.UseMessagePackSerializer();
},?"MyKvCache");

由于作者筆記本性能不夠,使用 Sqlite 無法在短期內完成 100W、1W 個 Key 的性能測試,所以我們在默認設置下將數據集大小設置為 1000 個 Key,設置 50%的熱點 Key。進行 100%讀、100%寫和 50%讀寫隨機比較。

可以看到無論是讀、寫還是混合操作 FasterKvCache 都有著不俗的性能,在 8 個線程情況下,TPS 達到了驚人的 1600w/s

緩存類型線程數Mean(us)Error(us)StdDev(us)Gen0Gen1Allocated
fasterKvCacheRead859.953.8542.5491.52597.02NULL
fasterKvCacheWrite863.671.0320.6830.79353.63NULL
fasterKvCacheRandom464.421.3920.9211.7098.38NULL
fasterKvCacheRead464.670.6280.3742.563511.77NULL
fasterKvCacheRandom864.803.6392.1661.09865.33NULL
fasterKvCacheWrite465.573.452.0530.97664.93NULL
fasterKvRead892.1510.6787.0635.7373-26.42 KB
fasterKvWrite499.4921.04610.7422-49.84 KB
fasterKvWrite8108.505.2283.1115.6152-25.93 KB
fasterKvRead4109.371.4760.77210.9863-50.82 KB
fasterKvRandom8119.9414.1759.3765.7373-26.18 KB
fasterKvRandom4124.316.1914.09510.7422-50.34 KB
fasterKvCacheRead1207.773.3071.739.277343.48NULL
fasterKvCacheRandom1208.711.8320.9586.347729.8NULL
fasterKvCacheWrite1211.261.5571.033.41816.13NULL
fasterKvWrite1378.6017.75511.74442.4805-195.8 KB
fasterKvRead1404.5717.47711.5643.457-199.7 KB
fasterKvRandom1441.2214.1079.33142.9688-197.75 KB
sqliteRead87450.11260.279172.15854.68757.8125357.78 KB
sqliteRead414309.94289.113172.047109.37515.625718.9 KB
sqliteRead156973.531,774.351,173.624001002872.18 KB
sqliteRandom8475535.01214,015.71141,558.14--395.15 KB
sqliteRandom41023524.8797,993.1964,816.43--762.46 KB
sqliteWrite81153950.8448,271.4728,725.58--433.7 KB
sqliteWrite42250382.93110,262.7272,931.96--867.7 KB
sqliteWrite14200783.0843,941.6929,064.71--3462.89 KB
sqliteRandom15383716.10195,085.96129,037.28--2692.09 KB

總結

可以看到 FasterKvCache 有著不俗的性能,目前也在筆者朋友的項目使用上了,反饋不錯,解決了他的緩存問題。由于現在還只是 1.0.0-rc1 版本,還有很多特性沒有實現。可能有一些 BUG 還存在,歡迎大家試用和反饋問題。

Github 開源地址: https://github.com/InCerryGit/FasterKvCache

參考鏈接

https://developer.aliyun.com/article/740811

參考資料

[1]

FasterKv.Cache.Core: https://www.nuget.org/packages/FasterKv.Cache.Core

[2]

FasterKv.Cache.MessagePack: https://www.nuget.org/packages/FasterKv.Cache.MessagePack

[3]

FasterKv.Cache.SystemTextJson: https://www.nuget.org/packages/FasterKv.Cache.SystemTextJson

[4]

FasterKv-Settings: https://microsoft.github.io/FASTER/docs/fasterkv-basics/#fasterkvsettings

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/281009.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/281009.shtml
英文地址,請注明出處:http://en.pswp.cn/news/281009.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

最小生成樹詳解

注&#xff1a;本文算法使用鏈式前向星數據結構實現。學習鏈接&#xff1a;鏈式前向星-學習筆記 一、Prim算法 普通prim算法模板&#xff1a; //用前向星錄數據的時候記得把head初始化為-1 fill(dist,distLEN,MAX); memset(vis,0,sizeof vis); int ans0; dist[1]0; //如…

dropbox文件_Dropbox即將發布的擴展程序更新將添加更多文件編輯支持,包括Pixlr照片...

dropbox文件Dropbox is perhaps the best-known cloud storage platform for consumers, but it’s hoping to become something more. With an upcoming overhaul to its user tools, Dropbox will add more complex editing tools, in addition to what it already provides …

黑客竊取思科、IBM與甲骨文認證管理系統內的敏感數據

目前一套被思科、F5、IBM以及甲骨文等企業所廣泛使用的認證管理系統(即Credential Manager System)正面臨著數據泄露風險&#xff0c;其中的敏感數據也許已經被黑客們所獲取。 根據Pearson VUE(主營計算機測試方案開發與交付)發布的一項公告&#xff0c;某惡意軟件已經藏身于該…

Spring下載地址

下載地址&#xff1a;https://repo.spring.io/libs-release-local/org/springframework/spring/ 進入后可選擇下載版本&#xff0c;選擇版本后&#xff0c;進入目錄結構。其中dist是最終發布版本&#xff0c;包含開發所需lib和源碼。docs是開發文檔。schema是一些約束文件。 Do…

C#字符串:轉數組、數字

1.List<string> 轉數組&#xff0c;字符串 string[] strs list.ToArray();string s string.Join(",", list.ToArray());//數組轉list string[] strArr new string[3] { "1", "2", "3" }; List<string> strList strArr…

.NET7發布,一大批優秀.NET6項目沒人看了嗎...(都是好項目)

恍惚間都已經.NET7.0了&#xff0c;不能再呆在舊版本了&#xff01;這里分享一套Vue3 Axios TS Vite Element Plus .NET 6 WebAPI JWT SqlSugar的通用管理后臺&#xff0c;各種最新框架組件&#xff0c;學習必備&#xff01;這里把源碼、腳本以及專門錄制的視頻教程都打…

Python的日志記錄-logging模塊的使用

一、日志 1.1什么是日志 日志是跟蹤軟件運行時所發生的事件的一種方法&#xff0c;軟件開發者在代碼中調用日志函數&#xff0c;表明發生了特定的事件&#xff0c;事件由描述性消息描述&#xff0c;同時還包含事件的重要性&#xff0c;重要性也稱為級別或嚴重性。 1.2何時使用日…

詢問HTG:白噪聲屏幕保護程序,有效的文件命名以及從密碼泄露中恢復

Once a week we share three of the questions we’ve answered from the Ask HTG inbox with the greater readership; this week we’re looking at white noise screen savers, efficient file naming systems, and recovering from a password compromise. 每周一次&#…

專家預測第二波WannaCry勒索病毒攻擊即將到來!

WannaCry的傳播腳步今晨戛然而止 今天一大早&#xff0c;全網的WannaCry蠕蟲病毒攻擊突然減弱消退了!所有這一切功勞來自于英國研究人員malwaretech&#xff0c;他通過逆向發現WannaCry代碼中有一個特殊域名地址&#xff1a; www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.co…

01.HTML基礎命令筆記

目錄 HTML結構 body內常用標簽 常用 div與span img a標簽 超鏈接標簽 其他格式標簽 列表 表格 表單 select標簽 label標簽 textarea多行文本 HTML結構 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"&…

ios numlock_從“提示”框:默認情況下啟用NumLock,無廣告的iOS應用和立體聲供電的派對燈...

ios numlockOnce a week we round up some of the great tips readers have sent into the tip box. This week we’re looking at how to enable the NumLock by default, stripping ads from iOS apps, and turning Christmas lights into audio-responsive party lights. 每…

Windows 7 自動更新失敗導致無法進系統解決方案

故障現象&#xff1a;自動更新后&#xff0c;重啟電腦&#xff0c;提示&#xff1a;&#xff08;配置Windows update 失敗 還原更改 請勿關閉計算機&#xff09;&#xff0c; 而計算機一直停留該界面&#xff0c;如果半個小時以上都無反應。此時&#xff0c;就不要再繼續等待了…

Net程序員為什么要學點其他語言副業

最近看了很多同行的文章、或者是現實中身邊的例子也好&#xff0c;真的覺得大家太不容易了。感覺說的就是自己。入門上學的時候接觸了.NET&#xff0c;它的簡單以及宇宙無敵的Visual Studio&#xff0c;讓我深深地迷戀上它。畢業之后&#xff0c;就成功的做來一名.Neter&#x…

PaperWeekly 第28期 | 圖像語義分割之特征整合和結構預測

“ 余昌黔 華中科技大學碩士 研究方向為圖像語義分割 知乎專欄 https://zhuanlan.zhihu.com/semantic-segmentation 前言 近來閱讀了 PASCAL VOC 2012 排行榜上前幾的文章&#xff0c;包括 PSPNet 和林國省老師的幾篇論文&#xff0c;覺得現在在 semantic segmentation 領域對于…

POJ.2774.Long Long Message/SPOJ.1811.LCS(后綴數組 倍增)

題目鏈接 POJ2774SPOJ1811 LCS - Longest Common Substring 比后綴自動機慢好多(廢話→_→)。 \(Description\) 求兩個字符串最長公共子串 \(Solution\) 任何一個子串一定是某個后綴的前綴 可以將兩個字符串拼在一起&#xff0c;中間用一個從未出現過的字符隔開&#xff0c;這樣…

02.CSS基礎筆記及導入

CSS是什么 CSS&#xff08;Cascading Style Sheet&#xff0c;層疊樣式表)定義如何顯示HTML元素。 當瀏覽器讀到一個樣式表&#xff0c;它就會按照這個樣式表來對文檔進行格式化&#xff08;渲染&#xff09;。 CSS樣式 CSS引入HTML 內部樣式與外部樣式 <!DOCTYPE> …

如何還原桌面圖標_如何為Windows 10桌面圖標還原或更改文本的默認外觀?

如何還原桌面圖標For whatever reason, sooner or later we all have someone or something mess around with our keyboards and create ‘interesting’ results. With that in mind, today’s SuperUser Q&A post has a simple and elegant way to help a frustrated re…

「前端早讀君007」css進階之徹底理解視覺格式化模型

今日勵志 不論你在什么時候開始&#xff0c;重要的是開始之后不要停止。 前言 對于部分前端工程師來講&#xff0c;有時候CSS令他們很頭疼&#xff0c;明明設置了某個樣式&#xff0c;但是布局就是不起作用。 如果你也有這種問題&#xff0c;那么是時候學習下什么是css視覺格式…

.NET周報【11月第3期 2022-11-22】

國內文章.NET Conf China 2022 第一批講師陣容大揭秘&#xff01;整個期待了&#xff01;https://mp.weixin.qq.com/s/4p89hhBPw6qv-0OB_T_TOg目光看過來 2022 年 12 月 3-4 日&#xff0c;一場社區性質的國內規模最大的 線上線下.NET Conf 2022 技術大會 即將盛大開幕。目前大…

解讀Facebook CAN:如何給人工智能賦予藝術創作的力量

雷鋒網 AI 科技評論按&#xff1a;能夠迭代進化、模仿指定數據特征的GAN&#xff08;生成式對抗性網絡&#xff09;已經是公認的處理圖像生成問題的好方法&#xff0c;自從提出以來相關的研究成果不少&#xff0c;在圖像增強、超分辨率、風格轉換任務中的效果可謂是驚人的。 &a…