C# Memory Cache 踩坑记录
背景
前些天公司服务器数据库访问量偏高,运维人员收到告警推送,安排我团队小伙伴排查原因.
我们发现原来系统定期会跑一个回归测试,该测运行的任务较多,每处理一条任务都会到数据库中取相关数据,高速地回归测试也带来了高频率的数据库读取.
解决方案1
我们认为每个任务要取的数据大相径庭,因此我们考虑对这个过程进行修改,加入MemoryCache把数据库中读取到的数据进行缓存.
整个修改非常简单,相信对常年混迹在博客园中的各位大佬来说小菜一碟,因此小弟不再叙述添加缓存的步骤细节.
从缓存的添加,代码提交,Teamcity 编译通过,到测试环境,QA环境的安装无比流畅,一切显得如手到擒来.
嗯,优秀是一种习惯, 没有一点办法.
人生如戏,当我们还沉浸在"我加的Cache不可能又BUG"的自信中时,QA传来噩耗,回归测试大量未通过 ....
故障排查
之前习惯了使用Redis缓存,因此,常识告诉我们 --- 在数据库中数据没有改动的前提下,加了缓存后读取的数据的效果和从数据库中读取的效果是一模一样的.
除非 ,,, 除非 这个常识是错误的....
因此我们加了日志,对写入缓存前后读取出来的数据进行了对比,结果出人意料.

该死 MemoryCache 毁我老脸,丢我精度,拿命来!!!!!
从日志中看到,第一行是从数据库中读取的结果,第二行是从cache中读取的,前两条数据完全一致,到了第三条,第四条,第五条,仔细观察发现,在小数点后面,居然有些小数点后比较微小的变化,不管变化的大小但数据确实发生改变了,所以MemoryCache会影响数据精度??这样会改变数据精度的MemoryCache又有何用??
机智的我,似乎早已看穿了一切,这肯定不是MenoryCache的锅!!!
不一样的MemoryCache
我从https://referencesource.microsoft.com 中扒出了MemoryCache的源码一探究竟.

定位到MemoryCache中的AddOrGetExisting方法,我们看到,其实我们把数据存储到该缓存的过程本质是把该对象存到一个名为_entries的 Hashtable 中,同样,取数据也是通过Key到该Hashtable中取出来,整个过程并没有对该对象进行序列化反序列等,也没有对该对象进行clone操作.这就意味着我们之前存入的,和后面取出的(不管我们从MemoryCache中取数据取多少次),永远只取出同一个对象.
这一点,和我之前使用的RedisCache是有很大区别的.我们在Redis中存入数据,是把对象序列化后存到Redis中,取数据是把Redis中的字节数据反序列成对象,意味着前一次存入的,和后一次取出的,已经不是同一个对象了,因此Redis中的数据是安全的.
猜想
我做出了一个大胆的猜想,之前从MemoryCache中取出来的数据之所以变化了,可能是取出对象后,复杂的处理过程中对该对象进行了什么修改操作,所以后期,再次从数据库中读取数据,读出来的已经已经不是最初存入的数据,而是前一次修改之后的数据.带着这个猜想,我对代码进行了修改.
解决方案2
从MenoryCache中取到数据后对结果进行clone(),这样即使程序对取出来的结果进行了修改也不会影响Cache中的数据了.
又是一次提心掉到的提交,编译,安装后, 回归测试顺利通过.
感觉人生到达了高潮 -_-
把踩得坑分享出来,希望后面的小伙伴引以为鉴,
C# Memory Cache 踩坑记录的更多相关文章
- 你真的了解字典(Dictionary)吗? C# Memory Cache 踩坑记录 .net 泛型 结构化CSS设计思维 WinForm POST上传与后台接收 高效实用的.NET开源项目 .net 笔试面试总结(3) .net 笔试面试总结(2) 依赖注入 C# RSA 加密 C#与Java AES 加密解密
你真的了解字典(Dictionary)吗? 从一道亲身经历的面试题说起 半年前,我参加我现在所在公司的面试,面试官给了一道题,说有一个Y形的链表,知道起始节点,找出交叉节点.为了便于描述,我把上面 ...
- manjaro xfce 18.0 踩坑记录
manjaro xfce 18.0 踩坑记录 1 简介1.1 Manjaro Linux1.2 开发桌面环境2 自动打开 NumLock3 系统快照3.1 安装timeshift3.2 使用times ...
- Spark Ignite踩坑记录
Ignite spark 踩坑记录 简述 ignite访问数据有两种模式: Thin Jdbc模式: Jdbc 模式和Ignite client模式: shell客户端输出问题,不能输出全列: 针对上 ...
- unionId突然不能获取的踩坑记录
昨天(2016-2-2日),突然发现系统的一个微信接口使用不了了.后来经查发现,是在网页授权获取用户基本信息的时候,unionid获取失败导致的. 在网页授权获取用户基本信息的介绍中(http://m ...
- CentOS7.4安装MySQL踩坑记录
CentOS7.4安装MySQL踩坑记录 time: 2018.3.19 CentOS7.4安装MySQL时网上的文档虽然多但是不靠谱的也多, 可能因为版本与时间的问题, 所以记录下自己踩坑的过程, ...
- ubuntu 下安装docker 踩坑记录
ubuntu 下安装docker 踩坑记录 # Setp : 移除旧版本Docker sudo apt-get remove docker docker-engine docker.io # Step ...
- SpringBoot + Shiro + shiro.ini 的踩坑记录
0.写在前面的话 好久没写博客了,诶,好多时候偷懒直接就抓网上的资料丢笔记里了,也就没有自己提炼,偷懒偷懒.然后最近参加了一个网络课程,要交作业的那种,为了能方便看下其他同学的作业,就写了个爬虫把作业 ...
- google nmt 实验踩坑记录
最近因为要做一个title压缩的任务,所以调研了一些text summary的方法. text summary 一般分为抽取式和生成式两种.前者一般是从原始的文本中抽取出重要的word o ...
- ABP框架踩坑记录
ABP框架踩坑记录 ASP.NET Boilerplate是一个专用于现代Web应用程序的通用应用程序框架. 它使用了你已经熟悉的工具,并根据它们实现最佳实践. 文章目录 使用MySQL 配置User ...
随机推荐
- flash builder 4.6与myecilpse 10.7集成
一.在flash builder 4.0以后就没有单独提供插件版的flash builder了,因此必须先安装完整版的flash builder,再进行插件集成. 二.集成过程比较简单但也有几个要注意 ...
- Python入门、练手、视频资源汇总,拿走别客气!
摘要:为方便朋友,重新整理汇总,内容包括长期必备.入门教程.练手项目.学习视频. 一.长期必备. 1. StackOverflow,是疑难解答.bug排除必备网站,任何编程问题请第一时间到此网站查找. ...
- 字符串转json以及获取域名的参数
本例将通过location.search来进行字符串拼接成json以及查询域名参数的value console.log(request('id')); function request(obj){ v ...
- [译文]Domain Driven Design Reference(三)—— 模型驱动设计的构建模块
本书是Eric Evans对他自己写的<领域驱动设计-软件核心复杂性应对之道>的一本字典式的参考书,可用于快速查找<领域驱动设计>中的诸多概念及其简明解释. 其它本系列其它文章 ...
- 强大的测试管理工具---TestTrack Pro
我的一篇老文章了,当年可能是第一篇介绍.从CSDN搬来的. 版权声明:本文为博主原创文章,未经博主允许不得转载. 强大的测试管理工具---TestTrack Pro 时间:2004-03-09 简介: ...
- EXCEL解析之终极方法WorkbookFactory
Selenium做自动化测试当然不能避免和Excel打交道. 由于Excel版本的关系,文件扩展名分xls和xlsx, 以往的经验都是使用HSSFWorkbook和XSSFWorkbook来分别处理. ...
- 二十六、Hadoop学习笔记————Hadoop Yarn的简介复习
1. 介绍 YARN(Yet Another Resource Negotiator)是一个通用的资源管理平台,可为各类计算框架提供资源的管理和调度. 之前有提到过,Yarn主要是为了减轻Hadoop ...
- HTTP Strict Transport Security实战详解
HTTP Strict Transport Security (通常简称为HSTS) 是一个安全功能,它告诉浏览器只能通过HTTPS访问当前资源, 禁止HTTP方式. 0×01. Freebuf百科: ...
- Vue 2.0 路由全局守卫
vue2.0 实现导航守卫(路由守卫) 路由跳转前做一些验证,比如登录验证,是网站中的普遍需求. 对此,vue-route 提供的 beforeRouteUpdate 可以方便地实现导航守卫(navi ...
- selenium的一些使用方法
新建实例driver = webdriver.Chrome()1.通过标签属性Id查找元素方法:find_element_by_id(element_id)实例:driver.find_element ...