内存不够用还要速度快,终于找到可以基于 File 的 Cache 了

一:背景

1. 讲故事

18年的时候在做纯内存项目的过程中遇到了这么一个问题,因为一些核心数据都是飘在内存中,所以内存空间对我们来说额外宝贵,但偏偏项目中有些数据需要缓存,比如说需要下钻的报表上的点,基于性能的考虑,不希望采用独立的缓存中间件,比如 redis, mongodb,毕竟再怎么滴还是要走网络io,但直接放在本机内存中也不现实,那有没有均衡于 native cache 和 cache server 之间的方案呢?对的,就是 disk cache,毕竟 磁盘IO 的读写要远大于网络IO,更何况配的是 SSD 呢。

二:寻找解决方案

1. 检索 github

有了 disk cache 这个大方向就可以去 github 上检索关键词,看看有没有类似的中间件,说实话,java的倒不少,比如著名的 guava,ehcache,不仅有cache的简单操作,还附带各种统计信息,刷新了对缓存认知的三观哈,尤其是 ehcache 太????????了,堆内,堆外,磁盘,分布式通通支持,用 C# 写的好不容易找到一个 disk cache 还不幸是收费的,气人哈,用 C# 调用 Java 肯定不现实了哈。

2. 使用sqlite作为 disk cache

既然开源社区没什么好的东西,看来只能自己封装一下了,像 ehcache 那种高阶的 diskcache 搞不定,用简单的 sqlite 作为本机的 diskcahe 还是可以的,接下来试试看。

class DiskCache{private static readonly string dbFile = $@"{Environment.CurrentDirectory}\mysqlite1.db";private static readonly string connectionString = $@"Data Source={dbFile};Version=3";//过期数据监测:【一分钟来一次】private static Timer timer = new Timer((arg) =>{}, null, 1000, 1000 * 60);static DiskCache(){if (!File.Exists(dbFile)){var schema = @"CREATE TABLE Cache (cachekey   VARCHAR (1000) PRIMARY KEY  NOT NULL,cachevalue TEXT                        NOT NULL,created    DATE                        NOT NULL,expried    DATE                        NOT NULL);";using (SQLiteConnection connection = new SQLiteConnection(connectionString)){connection.Execute(schema);}}}public static void Set<T>(string key, T value, int expiredMinutes){using (SQLiteConnection connection = new SQLiteConnection(connectionString)){var sql = $"delete from Cache where cachekey =@key;" +$"insert into Cache(cachekey,cachevalue,created,expried) values (@cachekey,@cachevalue,@created,@expried)";connection.Execute(sql, new{key = key,cachekey = key,cachevalue = Newtonsoft.Json.JsonConvert.SerializeObject(value),created = DateTime.Now,expried = DateTime.Now.AddMinutes(expiredMinutes)});}}public static T Get<T>(string key){using (SQLiteConnection connection = new SQLiteConnection(connectionString)){var sql = $"select cachevalue from Cache where cachekey=@cachekey and expried > @expried";var query = connection.QueryFirstOrDefault(sql, new { cachekey = key, expried = DateTime.Now });var json = JsonConvert.DeserializeObject<T>(query.cachevalue);return json;}}}

这里有二个注意点:

  • 因为是做缓存,所以数据库和表的创建都要通过程序自动化,数据库是否存在判断 file 文件是否存在即可。

  • 过期数据的问题,因为我有 expried 字段,这一点可以学习GC思想,使用 Timer 在后台定期清理。

有了这些基础之后,原子化的缓存就实现好了,接下来试一下基本的 Get / Set 方法。

这个方案很好的节省了我宝贵的内存,同时速度又是 networkio 和 native 之间的一个平衡,算是个不错的解决办法吧。

三:aspnetcore 的 EasyCaching

EasyCaching 是园子里 @Catcher Wong 的作品 [https://www.cnblogs.com/catcher1994/p/10806607.html],点赞~~~ 看了下提供了很多种 provider,如下图:

我想后面肯定还会有更多的 provider 出现,如:leveldb,Cassandra,接下来看看这玩意怎么玩。

1. 安装使用

在 nuget 上 搜一下 EasyCaching.SQLite 安装即可,接下来就是使用文档:https://easycaching.readthedocs.io/en/latest/SQLite/#2-config-in-startup-class 如下图:

文档中是采用依赖注入的方式,而我的程序是 console 模式的后端服务,并没有 ServiceCollection,先模拟着试试看。

static void Main(string[] args){IServiceCollection services = new ServiceCollection();services.AddEasyCaching(option =>{option.UseSQLite(c =>{c.DBConfig = new SQLiteDBOptions{FileName = "demo.db",CacheMode = SqliteCacheMode.Default,OpenMode = SqliteOpenMode.ReadWriteCreate,};}, "m1");});IServiceProvider serviceProvider = services.BuildServiceProvider();var factory = serviceProvider.GetService<IEasyCachingProviderFactory>();var cache = factory.GetCachingProvider("m1");cache.Set("user", "hello world!", TimeSpan.FromSeconds(20));var info = cache.Get<string>("user");Console.WriteLine(info);}

接下来用 SQLiteStudio 打开 demo.db 看一下数据呈现,如下图:

可以看到人家的框架比我的多了一个 name 字段,看样子是给 多个 cache 做隔离用的,不过这里貌似有三个需要优化的地方。

  • 并不是每一个程序都要使用 依赖注入 的方式 ,提供更便捷的方式初始化就更好了。

  • 看了下源码,并没有找到可以定期删除过期数据的业务逻辑。

  • 建议提供一些 cache 的统计信息,如命中次数,某一个key最后命中时间等等时分统计图。

四:总结

可能很多人说都什么年代了还用 disk cache,这偏偏这万千世界啥需求都有,这几年开源项目越来越多,社区向好,值得点赞。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/308121.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络:如何传输一条数据(详解)

一&#xff1a;不同的localhost如何传送信息 1:图示概览图 (1):无注解 (2):有注解 这里我在这个线路层中又连了一些新的 sw 和 router 其实还可以连更多&#xff0c;相当于一个网状的 注意同一个网络中只有一个网关&#xff0c;形象点理解网关就是通往别的网洛的大门 在下方…

为什么我们需要Logstash,Fluentd等日志摄取器?

前文传送门&#xff1a;如何利用NLog输出结构化日志&#xff0c;并在Kibana优雅分析日志&#xff1f;疑问&#xff1a;既然应用能直接向ElasticSearch写日志&#xff0c;为什么我们还需要Logstash,Fluentd等日志摄取器&#xff1f;而且这些日志摄取器组件还成为日志收集的事实标…

7-1 装载问题 (10 分)(思路+详解)

一&#xff1a;题目 Come 宝宝&#xff01;&#xff01; 输出格式: 输出所有可行的方案数量 输入样例1: 3 50 50 10 40 40结尾无空行 输出样例1: 4结尾无空行 输入样例2: 3 50 50 20 40 40结尾无空行 输出样例2: 0二:思路 1.这个解的空间选择的是子集树 2.递归函数参数 b…

程序员是终身学习的职业,应该怎么学习?

在上一篇《一款用了就不想走的工具》中介绍了一款工具 Notion &#xff0c;可以做学习的规划、时间的管理、学习的记录等&#xff0c;但学习本身还是需要一些方法的&#xff0c;本文谈谈我对学习的一些感悟。不管你是刚刚进入职场的新人&#xff0c;还是工作多年的老兵&#xf…

7-2 批处理作业调度 (10 分)(思路+详解)

一&#xff1a;题目:宝宝 你要永远开心&#xff0c;下雪了&#xff0c;多穿点&#xff0c; 输入格式: 第一行输入作业个数n。 第二行输入各任务在机器一上的完成时间。 第三行输入各任务在机器二上的完成时间。 输出格式: 最短完成时间和 输入样例: 3 2 3 2 1 1 3结尾无空…

WindowsSdkDir 从何处来?

缘起 我在《修复被破坏的 vs 工程设置》和《修复被破坏的 vs 工程设置&#xff08;续&#xff09;》这两篇文章中&#xff0c;分享了调查 VS 包含路径错误的问题&#xff0c;感兴趣的小伙伴儿可以查看。依稀记得在 2013 年的时候调查过类似的问题。前一阵子没翻到&#xff0c;这…

7-3 符号三角形 (10 分)(思路+详解)

一&#xff1a;题目 Come 宝 &#xff01;&#xff01;&#xff01; 输入格式: 第一行符号个数n 输出格式: 符合要求的三角形个数 输入样例: 4结尾无空行 输出样例: 6二:思路 思路: 1.如果我们确立的第一行的符号是什么 &#xff0c;那么我们就可以基本上确定我们的符号三…

7-1 内存分区分配--首次适应算法 (100 分)

一&#xff1a;题目7-1 内存分区分配–首次适应算法 (100 分) 宝 今天你看我博客了吗 输入内存的大小和阈值minsize&#xff0c;按照首次适应算法进行连续的分区分配。在划分时&#xff0c;若剩余的内存小于等于minsize&#xff0c;则将整块内存分配给该进程不再进行划分。 根…

如何在生产环境下用好EFCore

原文链接&#xff1a;https://www.thereformedprogrammer.net/handling-entity-framework-core-database-migrations-in-production-part-2/作者&#xff1a;Jon P Smith在生产中运用EFCore的模式实战这是使用EF Core迁移数据库的系列文章中的第二篇。本文着眼于将迁移应用于数…

39. 组合总和020(思路+详解)

一&#xff1a;题目&#xff1a; 给定一个无重复元素的正整数数组 candidates 和一个正整数 target &#xff0c;找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。 candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同&#xff0c;则两种…

8种方法解决vue创建项目报错:command failed: npm install --loglevel error

8种方法解决vue项目创建失败问题1、重建项目2、清除缓存3、重装淘宝源4、修改useTaobaoRegistry5、重装node6、删除npmrc文件7、 node版本问题8、css编辑工具选择9、管理员身份运行踩了这个巨大的坑&#xff01;&#xff01; 试了一个晚上终于找到了创建项目成功了T_T 当报错了…

40. 组合总和 II021(回溯法)

一&#xff1a;题目 给定一个数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。 注意&#xff1a;解集不能包含重复的组合。 示例 1:输入: candidates [10,1,2,…

.NET Core + Kubernetes:Helm

Helm[1] 作为 Kubernetes 体系的包管理工具&#xff0c;已经逐渐成为了应用分发标准&#xff0c;在 .NET 开发中&#xff0c;可以理解为与 NuGet 包类似。回顾之前文章中的介绍&#xff0c;Kubernetes 中单个服务的部署有时会涉及到多种资源类型&#xff0c;如&#xff1a;Depl…

vue项目中引入阿里图标iconfont

vue如何在创建好的项目中引入阿里图标iconfont呢&#xff0c;涉及到以下几个步骤&#xff1a; 1、首先先到阿里图标官方网站https://www.iconfont.cn/&#xff0c;先对账户进行登录&#xff0c;登录完成后任意选择几个图标加入购物车 2、加入购物车后&#xff0c;点击页面最右…

78. 子集022(回溯法)

一&#xff1a;题目 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;…

vue项目中使用vue-router进行路由配置及嵌套多级路由

在vue项目中&#xff0c;很多时候我们需要二级路由或者三级路由来跳转页面&#xff0c;但大部分需求下我们都只用到了二级路由&#xff0c;有小伙伴就会发现&#xff0c;用到三级路由的时候&#xff0c;就会突然不知所措&#xff0c;是有新的方法呢&#xff0c;还是跟二级路由配…

解决流氓软件方法(亲测有效)

一:问题描述 本来我想在百度上下载一个API文档&#xff0c;我当然知道是取官网上下载了&#xff0c;但是我想要的是中文版&#xff0c;所以我就搜啊搜&#xff0c;搜到脚本之家 &#xff0c;那里面可以下载&#xff0c;我记得以前在里面下载过东西&#xff0c;以为安全就去下载…

.NET Core:跨平台和开源,让我在框架中脱颖而出

自从 2016 年微软发布了 .NET Core 1.0&#xff0c;至今 4 年的时间里&#xff0c;.NET Core 历经 7 个正式版本和几十个 Preview 版本。.NET Core 作为最通用的框架&#xff0c;和其他软件框架不同的是&#xff0c;它面向 Windows、Linux 和 MacOS 多个平台&#xff0c;在桌面…

vue实现侧边折叠菜单栏手风琴效果

在我们做管理后台亦或是产品流程时&#xff0c;总是需要一个菜单栏或者导航栏来架起我们的产品架构&#xff0c;那么&#xff0c;如何用vue实现侧边折叠导航栏呢&#xff1f;接下来将一一介绍。 请先看效果演示图。 步骤1&#xff1a;先架构整个页面的布局&#xff0c;撰写html…

程序员过关斩将--解决分布式session问题

微信搜一搜架构师修行之路session 说到 session&#xff0c;我相信每个程序员都不陌生&#xff0c;或多或少在项目中使用过。session 这个词&#xff0c;其实是一个抽象的概念&#xff0c;它不像 Cookie 那样有着明确的定义。当大多数程序员谈论 session 的时候&#xff0c;可能…