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 ...
随机推荐
- CentOS-Minimal版本下安装telnet服务和xinetd服务
默认在CentOS-Minimal版本下没有安装telnet和xinetd服务. 1.安装telnet [root@localhost ~]# rpm -qa | grep telnet --检查是 ...
- 初探Margin负值(转)
相对而言,margin 负值的使用机率在布局中似乎很少,但是我相信一旦你开始掌握就会着迷,接下来我们看看关于margin负值的一些资料: 它是一个有效的属性,至少w3c中明确描述如下:”Negativ ...
- 洛谷 P1430 解题报告
P1430 序列取数 题目描述 给定一个长为\(n\)的整数序列\((n<=1000)\),由\(A\)和\(B\)轮流取数(\(A\)先取).每个人可从序列的左端或右端取若干个数(至少一个), ...
- 1、学习笔记之——html
这篇学习笔记是在看一些教学视频学习时所记,可能比较乱,就当是自己以后复习的资料好了. <!doctype html> <html> <head> <meta ...
- Python_排版函数
import textwrap doc='''Beautiful is better than ugly. Explicit is better than implicit. Simple is be ...
- PAT1031:Hello World for U
1031. Hello World for U (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Giv ...
- PHP开发基础知识
PHP的学习 PHP脚本以<?php 开始 ?>结束 <?php //此处写代码 ? > php默认文件扩展名.php php文件通常包含HTML标签以及一些PHP脚本代码 “ ...
- 数据结构 之 并查集(Disjoint Set)
一.并查集的概念: 首先,为了引出并查集,先介绍几个概念: 1.等价关系(Equivalent Relation) 自反性.对称性.传递性. 如果a和b存在等价关系,记 ...
- 使用WordPress搭建的网站如何使URL中不出现”wordpress”
问题描述: 当我们在服务器中安装WordPress时,通常,WordPress默认是将WordPress的文件安装到了一个名为"wordpress"的文件夹里.这样在一般情况下,如 ...
- web优化(二)
上次说到js的阻塞dom渲染可能出现的白屏现象,所以对于js我们需要一些优化.首先我们可以模仿通信中的时分的概念,使用 setTime()来执行一段js代码然后渲染页面然后再执行一段js代码,这样可以 ...