前言

是这么一回事:

我正在苦思一个业务逻辑,捋着我还剩不多的秀发,一时陷入冥想中......

突然聊天图标一顿猛闪,打开一看,有同事语音;

大概意思是:同事把项目中Redis部分缓存换成MemoryCache/Memcached,还强调MemoryCache/Memcached的效率是Redis的2~5倍;

当时我想到的是Memcached,听到的似乎也是,心想:怎么可能,就算有性能差,也不至于那么多;

因为当时同事代码还没提交,然后就陷入讨论ing,最后还是没聊通,我就跑到同事那当面沟通(要去打架吗,不不不,文明人);

沟通中.....,好几分钟过去了,突然同事说:他用的是微软的MemoryCache

虽然从读音上我还没区分出来,但一听微软,我就感觉我成笑话啦;

然后赶紧让同事打开代码,我擦,真成笑话啦,还理直气壮的沟通了好几十分钟。

为什么会那么“理直气壮”?

  • Memcached(听错的)性能高于Redis的2~5倍产生重大怀疑,经验告诉我不可能,除非Redis用法有问题;
  • 同事把Redis换成Memcached(听错的),那肯定不行的,前期的技术选型,Memcached不太符合项目应用场景;

最后因为MemoryCache成就了一场笑话,那MemoryCacheMemcached有什么区别呢?

  • MemoryCache不是分布式缓存,是基于程序存储在内存中的;是微软封装好的内存缓存库,合理利用CPU,性能好;由于基于程序分配内存,使用时避免了网络通讯的消耗。
  • Memcached是分布式缓存,是存储在公共机器上的,供不同程序使用的,存在一定的网络传输消耗。

这样比较感觉有点勉强,虽然Memcached是分布式的,但也是基于内存的,在数据存储内存的逻辑还是不同的,不过这里不打算讲解源码,我要说应用,哈哈哈。

附加-为什么Redis让同事感觉性能不好

真实场景是这样的,客户端开启多线程频繁读取Redis数据,当访问比较多时,导致Redis读取数据超过20毫秒,对于Web项目来说其实这还好,20毫秒的响应用户根本无法感知。但对于一个高性能要求的服务程序来说,对通讯要求就比较高,所以简单分析了一下拖慢的原因,大概以下两点:

  • 客户端增多,导致一个常用Key对应的数据变大(其实不大,只是相对大,稍微影响了读取速度,毫秒级别);

    解决方案:同事使用MemoryCache多做一层缓存,将这个常用Key直接存在内存中,提高读取性能;

  • 使用类似于Keys * 的命令频繁获取数据,导致有些命令执行在20毫秒左右(慢日志中可以看到);

    解决方案:改用Scan类似命令获取数据;

  • Redis自身的持久化耗时;

    解决方案:适当调整Redis持久化策略,让持久化频率没那么高;

正文

回归正题,既然说到MemoryCache,就来简单聊聊,主要分享在项目实战中如何使用;

主要依赖包:Microsoft.Extensions.Caching.Memory

MemoryCache的使用很简单,就是在调用方法设置和获取值就对啦;来直接看Demo吧;

1. 控制台Demo

其实有很多程序是基于后台服务运行的,并不都是Web,所以写了一个控制台的Demo,方便小伙伴参考;

1.1 引入相关包,项目中使用了Autofac作为依赖注入和其切面编程,则需要引入相关的依赖包,项目结构和包引入如下图:

1.2 编写示例代码及注册相关服务
  • IUserService就是简单接口;

    接口和方法上标注的Intercept和MyCache特性不是必须的,接下来会说;

  • UserService对接口的实现;

  • MyCacheAttribute自定义特性,用于标识,里面没有任何逻辑处理;

  • MyInterceptor自定义拦截器,面向切面的逻辑代码在这里处理;

    代码完了,就开始使用Autofac注册服务,进行使用啦,如下:

    注:Autofac不是必须的,根据自己需要进行选择使用,这里是为了要使用Autofac的切面编程功能。

1.3 两种方式进行缓存处理

通常在非Web程序中,有以下两种方式进行缓存处理:

  • 代码嵌入到业务逻辑,在真实业务逻辑处进行缓存获取或设置;

    这样很大一个缺点是每一个缓存的数据都需要手动到指定业务逻辑中添加缓存处理,代码后期不好维护,缓存功能的开启和关闭也不好控制,需要修改代码进行满足。

  • 面向切面编程,无需嵌入多余代码到业务中

    通过面向切面的思想,以动态代理的原理拦截方法,在方法前后进行处理,如下:

    缓存逻辑直接放在拦截器中处理即可,如下:

    注册服务时,开启Autofac的面向切面功能即可

    运行看效果,第二次都是从缓存中获取数据,美美哒:

注:推荐使用面向切面的形式进行处理,这样缓存功能可插拔,代码维护性也好。

2.WebApiDemo(项目名称为:MemoryCacheWebApiDemo)

在WebApi中使用就比较简单啦,关于MemoryCache的依赖包已经集成在框架中,如果需要使用,直接注册服务就可以用啦;通常在WebApi中进行缓存处理的方式有三种:

  • 中间件形式:通过自定义中间件进行缓存逻辑操作;
  • 过滤器形式:使用MVC相关过滤器进行缓存逻辑操作;
  • 业务层面向切面形式:面向切面的方式,在业务层做缓存,集成Autofac即可,和控制台Demo的面向切面一样;

这里就用过滤器的形式进行Demo演示,走起来~~~

2.1 编写过滤器

缓存如果能在最前面处理,就优先在最前面,所以使用的ResourceFilter过滤器;关于过滤器之前写过一篇文章很详细(跟我一起学.NetCore之MVC过滤器,这篇看完走路可以仰着头走),这里就不赘述了。

然后在Startup.cs中注册服务和将自定义过滤器注册即可,如下:

然后启动运行,多次请求调试看看效果(小伙伴自己在过滤器中调试即可);

在WebApi中也可以使用业务层面向切面的方式进行相关业务处理,集成Autofac即可;小伙伴可以参照这篇文章(跟我一起学.NetCore之Asp.NetCore中集成Autofac扩展)。 关于AOP面向切面编程这块,后续单独整理一篇分享;

源码地址:https://github.com/zyq025/DotNetCoreStudyDemo

总结

在一些开发项目中,可能会使用Dictionary进行数据缓存,如果是这样,可以尝试使用MemoryCache,性能合理利用CPU,而且还是线程安全的;另外在高并发场景,可以用其作为多级缓存,因为MemoryCache还能设置过期时间,搭配Redis配合使用,效果杠杠的。

一个被程序搞丑的帅小伙,关注"Code综艺圈",跟我一起学~~~

因MemoryCache闹了个笑话的更多相关文章

  1. AOP(面向切面编程)大概了解一下

    前言 上一篇在聊MemoryCache的时候,用到了Autofac提供的拦截器进行面向切面编程,很明显能体会到其优势,既然涉及到了,那就趁热打铁,一起来探探面向切面编程. 正文 1. 概述 在软件业, ...

  2. Polly-故障处理和弹性应对很有一手

    前言 对于运行中的系统,可以说百分百的小伙伴会经常遇见以下问题: 网络不通,突然又好了: 服务器宕机了: 调用服务接口超时了: 调用接口报错啦: 通讯信息发送失败需要重发: 以上只是列举了一些常遇到的 ...

  3. 使用缓存(Cache)的几种方式,回顾一下~~~

    前言 如今缓存成为了优化网站性能的首要利器,缓存使用的好,不仅能让网站性能提升,让用户体验变好,而且还能节约成本(增加一台缓存服务器可能就节约好几台机器):那平时小伙伴们都使用哪些缓存方式呢?这里就来 ...

  4. 一些对数学领域及数学研究的个人看法(转载自博士论坛wcboy)

    转自:http://www.math.org.cn/forum.php?mod=viewthread&tid=14819&extra=&page=1 原作者: wcboy 现在 ...

  5. 基于Laravel+Swoole开发智能家居后端

    基于Laravel+Swoole开发智能家居后端 在上一篇<Laravel如何优雅的使用Swoole>中我已经大概谈到了Laravel结合Swoole的用法. 今天,我参与的智能家居项目基 ...

  6. PC硬件之我见——CPU篇

    写在最前面:     最近身边很多朋友都购置电脑的想法,往往也会选择性价比较高的DIY攒机方式.不幸的是,并不是所有人都对电脑硬件有一定的了解的,何况在现在这种社会风气下,盲目的相信商家是不明智的.所 ...

  7. 服务器搭建纪录linux+mysql+nginx+php

    新的项目启动 第一版 首先买了阿里云,选好环境镜像包,一键安装. 第一版php打算不用框架,完全手写,主要的功能点 数据交互和图片传输. 后台搭建好后,使用PHP的Laravel, web端还是选定b ...

  8. 《javascript语言精粹》——第4章函数

    函数就是对象 [1].函数字面量即(函数表达式)包括四部分: 第一部分:保留字function: 第二部分:函数名称,可有可无: 第三部分:包围在一对小括号的一组参数,参数用逗号隔开: 第四部分:包围 ...

  9. Spring+SpringMVC+MyBatis+easyUI整合优化篇(六)easyUI与富文本编辑器UEditor整合

    日常啰嗦 本来这一篇和接下来的几篇是打算讲一下JDBC和数据库优化的,但是最近很多朋友加我好友也讨论了一些问题,我发现大家似乎都是拿这个项目作为练手项目,作为脚手架来用的,因此呢,改变了一下思路,JD ...

随机推荐

  1. 2020杭电多校 C / HDU 6879 - Mine Sweeper

    题意: t组输入,每组输入一个s 你需要输出一个r行c列的阵列,这个阵列中'X'代表炸弹,'.'表示没有炸弹 对于'.'这些位置都会有一个数值,这个值取决于这个位置附近8个位置,这8个位置一共有几个炸 ...

  2. python给字段名和值都加上引号

    import re c = ''' Accept: application/json, text/javascript, */*; q=0.01 Accept-Encoding: gzip, defl ...

  3. The Balance HDU - 1709 母函数(板子变化)

    题意: 现在你被要求用天平和一些砝码来量一剂药.当然,这并不总是可以做到的.所以你应该找出那些不能从范围[1,S]中测量出来的品质.S是所有重量的总质量. 输入一个n,后面有n个数,表示这n个物品的质 ...

  4. Codeforces Round #660 (Div. 2) C. Uncle Bogdan and Country Happiness (DFS)

    题意:有\(n\)个人,每个人居住在某个节点,所有人都在节点\(1\)上班,下班后沿着最短路径回家,在回家途中心情可能会变差(心情只会变差不会变好),每个节点都有一个开心值,开心值等于所有经过时的好心 ...

  5. sort排序使用以及lower_bound( )和upper_bound( )

    sort()原型: sort(first_pointer,first_pointer+n,cmp) 排序区间是[first_pointer,first_pointer+n)      左闭右开 参数1 ...

  6. 记一次亲身体验的勒索病毒事件 StopV2勒索病毒

    昨天给笔记本装了 windows server 2016 操作系统,配置的差不多之后,想使用注册机激活系统.使用了几个本地以前下载的注册机激活失败后,尝试上网搜索. 于是找到下面这个网站(这个网站下载 ...

  7. Springboot 过滤器和拦截器详解及使用场景

    一.过滤器和拦截器的区别 1.过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的.请求结束返回也是,是在servlet处理完后,返回给前端之前. 2.拦截 ...

  8. keras fit_generator 并行

    虽然已经走在 torch boy 的路上了, 还是把碰到的这个坑给记录一下 数据量较小时,我们可直接把整个数据集 load 到内存里,用 model.fit() 来拟合模型. 当数据集过大比如几十个 ...

  9. 一些CTF题目--20/9/3

    1. 看源码 POST方法.Extract覆盖. 直接url ?参数不行,因为POST参数不在URL上,GET参数才在 Burpsuite抓包,改成  pass=1&thepassword_1 ...

  10. HDU 3920 Clear All of Them I(状压DP)题解

    题意:2n个点,一个起点,开n枪,每枪必须打两个点,花费为起点到其中一点距离加上两点距离.问打完2n个点的最小花费. 思路:很显然应该dp状态,然后枚举i j两个空位置去填,那么复杂度$O(20 * ...