.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.mzph.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…

.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;就不要再继续等待了…

PaperWeekly 第28期 | 图像语义分割之特征整合和结构预测

“ 余昌黔 华中科技大学硕士 研究方向为图像语义分割 知乎专栏 https://zhuanlan.zhihu.com/semantic-segmentation 前言 近来阅读了 PASCAL VOC 2012 排行榜上前几的文章&#xff0c;包括 PSPNet 和林国省老师的几篇论文&#xff0c;觉得现在在 semantic segmentation 领域对于…

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…

全向轮底盘磁导轨寻迹

全向轮底盘上安装两条磁传感器带用于磁导轨寻迹 如简图所示&#xff0c;两条与Y直线相交的黑色线条我们认为是两条磁检测传感器带 矢量方法修正车体位置 定义轨道左为负向&#xff0c;轨道右为正向。传感器左检测为负&#xff0c;右检测为正&#xff1b; 定义底盘坐标系为αβ&…

02-1.CSS边框,边界,布局相关笔记

目录 CSS盒子模型 padding内填充 边框 边框属性 border-radius margin外边距 CSS盒子模型 Content(内容): 盒子的内容&#xff0c;显示文本和图像 >>>>类似word 文字A&#xff0c;改变字体与大小padding: 用于控制内容与边框之间的距离 …

android仿ios弹框_在“提示”框中:iOS外观(在Android上运行),Google Maps作为Time Machine,下载Wii游戏保存...

android仿ios弹框Once a week we round up some great reader tips and share them with everyone. Read on to see how to make your Android phone look like iOS, use a Google Maps mashup like a time machine, and download Wii game saves. 每周一次&#xff0c;我们收集…