.Net 数据缓存浅析
目录
1场景出发
1.1数据请求
1.2优化改进
2缓存
3缓存进阶
3.1缓存清除
3.2有效性
3.3线程安全
4适用场景和优劣
4.1适用场景
4.2优劣
5结语
1场景出发
1.1数据请求
小吴开发了一个购物网站,其中涉及到这样一个环节:访客用户请求页面时,会请求数据库获取商品分类信息,然后返回该数据,展示商品的分类
对于这个环节,他是这样处理的
/// <summary>
/// 模拟数据库获取数据耗时操作
/// </summary>
public class DataSource
{
/// <summary>
/// 获取商品分类
/// </summary>
/// <returns></returns>
public static string GetCategories()
{
Thread.Sleep();//模拟耗时
return "There are categories";
}
}
DataSource
class Program
{ static void Main(string[] args)
{
string cats = DataSource.GetCategories(); Console.WriteLine(cats); Console.ReadKey();
}
}
GetData
在初阶阶段,访客用户数量比较少,网站能够很好的运营
1.2优化改进
随着访客用户数量的增加,服务器压力越来越大,不少用户开始向客服抱怨,网页响应速度太慢
小吴不得不开始优化系统,他考虑到商品分类信息请求次数很多,但每次却是请求相同的数据,于是他决定把这部分数据放在常驻内存的静态变量中,然后在数据库直接获取数据上再加一层,来提供数据服务,改进如下:
/// <summary>
/// 模拟数据库获取数据耗时操作
/// </summary>
public class DataSource
{
/// <summary>
/// 获取商品分类
/// </summary>
/// <returns></returns>
public static string GetCategories()
{
Thread.Sleep();//模拟耗时
return "There are categories";
}
}
DataSource
/// <summary>
/// 静态字典缓存数据
/// </summary>
public class MyCache
{
private static Dictionary<string, object> _dictionary = new Dictionary<string, object>(); public static void Add(string key,object obj)
{
_dictionary.Add(key, obj);
} public static bool Exist(string key)
{
return _dictionary.ContainsKey(key);
} public static void remove(string key)
{
_dictionary.Remove(key);
} public static void removeAll(string key)
{
_dictionary = new Dictionary<string, object>();
} public static T Get<T>(string key)
{
return (T)_dictionary[key];
}
}
MyCache
/// <summary>
/// 数据处理类
/// </summary>
public class DataProxy
{
/// <summary>
/// 获取商品分类
/// </summary>
/// <returns></returns>
public static string GetCategories()
{
if (MyCache.Exist("Categories"))
{
return MyCache.Get<string>("Categories");
} else
{
MyCache.Add("Categories", DataSource.GetCategories()); return DataSource.GetCategories();
}
}
}
DataProxy
class Program
{ static void Main(string[] args)
{
string cats,cats1, cats2; cats = DataProxy.GetCategories(); Console.WriteLine(cats); cats1 = DataProxy.GetCategories(); Console.WriteLine(cats1); cats2 = DataProxy.GetCategories(); Console.WriteLine(cats2); Console.ReadKey();
}
}
GetData
经过这样的优化后,网站响应速度一下子就得到了提升
2缓存
上述场景就是对缓存的一种应用,它是系统性能优化的第一步
原因是使用缓存,缩短了获取数据的时间
这里重点讲解的是服务器端数据缓存,它只是缓存的一部分
下面是http请求过程
可以看到几乎各个环节都涉及到了缓存
3缓存进阶
上述只是数据缓存最简单的例子,在实际的开发过程中,我们还会面对更多的情形,下面我来简单的进阶一下
3.1缓存清理
当我们已知一条缓存的数据已经更新,我们该如何做呢?
上述代码已经解决了这个问题,Remove方法:即去掉这个键值对,然后在数据库获取最新的数据
那么如果多条缓存被影响,我们该如何做呢?
上述的RemoveAll方法?当然这是最直接有效的方法,但是这样会造成缓存穿透,在一瞬间丢失所有的缓存,数据库的压力将会骤增
一个比较有效的方法:我们在添加缓存的时候,把缓存的key值与它的数据义务相联系,即命名更加有意义,这样当某部分受到影响的时候,我们可以直接根据命名来确定是否更改
3.2缓存有效性
在使用缓存的过程中,我们遇到更多的情况是:程序根本不知道,数据已经发生变化
面对这种情况,我们一般采取的措施:给缓存加上有效期
在有效期内,直接使用缓存,超过有效期,在数据库获取最新数据并缓存起来
我们也可以同时增加一条线程,来不间断的主动检查缓存有效期,避免只有在使用的时候才检查的被动状态
代码如下:
/// <summary>
/// 静态字典缓存数据
/// </summary>
public class MyCache
{
/// <summary>
/// 每1个小时主动检查缓存过期项一次
/// </summary>
static MyCache()
{
Task.Run(() =>
{
Thread.Sleep( * ); List<string> keyList = new List<string>(); //过期key集合 foreach (var item in _dictionary.Keys)
{
if (_dictionary[item].Value < DateTime.Now)
{
keyList.Add(item); //已过期
}
} keyList.ForEach(p => { _dictionary.Remove(p); });
});
} private static Dictionary<string, KeyValuePair<object, DateTime>> _dictionary
= new Dictionary<string, KeyValuePair<object, DateTime>>(); public static void Add(string key, object obj, int minute = )
{
_dictionary.Add(key, new KeyValuePair<object, DateTime>(obj, DateTime.Now.AddMinutes(minute)));
} public static bool Exist(string key)
{
return _dictionary.ContainsKey(key);
} public static void remove(string key)
{
_dictionary.Remove(key);
} public static void removeAll(string key)
{
_dictionary = new Dictionary<string, KeyValuePair<object, DateTime>>();
} public static T Get<T>(string key)
{
return (T)_dictionary[key].Key;
}
}
MyCache
3.3线程安全
在单线程下,上述缓存简例,是没有问题的,可是我们往往面对的是多线程迸发,那么上述的例子,就会有线程安全问题
在键值对添加这里,如果多个线程访问,就会因为添加相同的键值,而导致程序崩溃
所以我们可以加锁,只允许一个线程先访问,后续的线程进来时判断键值是否已经存在
代码如下
/// <summary>
/// 静态字典缓存数据
/// </summary>
public class MyCache
{
private static object _lock = new object();
/// <summary>
/// 每1个小时主动检查缓存过期项一次
/// </summary>
static MyCache()
{
Task.Run(() =>
{
Thread.Sleep( * ); List<string> keyList = new List<string>(); //过期key集合 foreach (var item in _dictionary.Keys)
{
if (_dictionary[item].Value < DateTime.Now)
{
keyList.Add(item); //已过期
}
} keyList.ForEach(p => { _dictionary.Remove(p); });
});
} private static Dictionary<string, KeyValuePair<object, DateTime>> _dictionary
= new Dictionary<string, KeyValuePair<object, DateTime>>(); public static void Add(string key, object obj, int minute = )
{
lock (_lock)
{
if (_dictionary.ContainsKey(key))
{
return;
}
else
{
_dictionary.Add(key, new KeyValuePair<object, DateTime>(obj, DateTime.Now.AddMinutes(minute)));
}
}
} public static bool Exist(string key)
{
return _dictionary.ContainsKey(key);
} public static void remove(string key)
{
_dictionary.Remove(key);
} public static void removeAll(string key)
{
_dictionary = new Dictionary<string, KeyValuePair<object, DateTime>>();
} public static T Get<T>(string key)
{
return (T)_dictionary[key].Key;
}
}
MyCache
4适用场景和优劣
没有任何技术是完美的,我们所做的只能是具体问题具体分析
缓存会在够解决一系列问题的同时,带来新的问题,我们所能够做的是扬长避短
4.1适用场景
1数据实时性要求不太高:缓存的本质决定了其一定会有脏数据,即使加了有效期,也会有延迟
2多次请求:如果没有请求多次,那么也没有缓存的必要
2体积小:因为缓存是在程序进程内存里面的,所以空间有限
4.2优劣
优势:能够缩短查询路径,更快的得到响应, 优化系统性能,
劣势:无法确定数据是否是最新的,有所延迟
5结语
至今为止,关于缓存与其他各种技术的相结合和各种关于缓存的框架层出不穷,如果一开始就注其表面,会感到晦涩难以深入,不如透过现象回到本质,以最单纯的想法去理解它,那么反而更容易接近它,只要能够明白这些,那么对于那些立其之上的衍生物,只会是游刃有余
出自:博客园-半路独行
原文地址:https://www.cnblogs.com/banluduxing/p/9238838.html
本文出自于http://www.cnblogs.com/banluduxing 转载请注明出处。
.Net 数据缓存浅析的更多相关文章
- http缓存策略以及强缓存和协商缓存浅析
http缓存策略以及强缓存和协商缓存浅析 本地缓存-强缓存 本地缓存,也就是我们常说的强缓存:是指当浏览器请求资源时,如果请求服务端的资源命中了浏览器本地的缓存资源,那么浏览器就不会发送真正请求给服务 ...
- Servlet数据缓存
缓存是提高数据访问能力,降低服务器压力的一种必要的方式,今天我要说的数据缓存方式有两种,1-->session对单个数据访问接口页面的数据进行缓存,2-->单例模式对整个servlet页面 ...
- 面localStorage用作数据缓存的简易封装
面localStorage用作数据缓存的简易封装 最近做了一些前端控件的封装,需要用到数据本地存储,开始采用cookie,发现很容易就超过了cookie的容量限制,于是改用localStorage,但 ...
- jQuery数据缓存方案详解:$.data()的使用
我们经常使用隐藏控件或者是js全局变量来临时存储数据,全局变量容易导致命名污染,隐藏控件导致经常读写dom浪费性能.jQuery提供了自己的数据缓存方案,能够达到和隐藏控件.全局变量相同的效果,但是j ...
- jQuery 2.0.3 源码分析 数据缓存
历史背景: jQuery从1.2.3版本引入数据缓存系统,主要的原因就是早期的事件系统 Dean Edwards 的 ddEvent.js代码 带来的问题: 没有一个系统的缓存机制,它把事件的回调都放 ...
- SQL Server 数据缓存
引言 SQL Server通过一些工具来监控数据,其中之一的方法就是动态管理管理视图(DMV). 常规动态服务器管理对象 dm_db_*:数据库和数据库对象 dm_exec_*:执行用户代码和关联的连 ...
- iOS开发网络篇—数据缓存
iOS开发网络篇—数据缓存 一.关于同一个URL的多次请求 有时候,对同一个URL请求多次,返回的数据可能都是一样的,比如服务器上的某张图片,无论下载多少次,返回的数据都是一样的. 上面的情况会造 ...
- Memcache,Redis,MongoDB(数据缓存系统)方案对比与分析
mongodb和memcached不是一个范畴内的东西.mongodb是文档型的非关系型数据库,其优势在于查询功能比较强大,能存储海量数据.mongodb和memcached不存在谁替换谁的问题. 和 ...
- 微信小程序-数据缓存
每个微信小程序都可以有自己的本地缓存,可以通过 wx.setStorage(wx.setStorageSync).wx.getStorage(wx.getStorageSync).wx.clearSt ...
随机推荐
- 使用protocol buffer时关闭警告
在生成的文件头尾添加屏蔽警告的代码. 头部: #pragma warning(push, 2) // --------------------------------------------- 尾部: ...
- ImportError: Couldn't import Django.或者提示Django 模块不存在
ImportError: Couldn't import Django. 或者 多版本的python引起的,执行以下命令 即可解决问题 python3是新的版本的python python3 -m ...
- 跟我学算法- tensorflow 实现RNN操作
对一张图片实现rnn操作,主要是通过先得到一个整体,然后进行切分,得到的最后input结果输出*_w[‘out’] + _b['out'] = 最终输出结果 第一步: 数据载入 import ten ...
- Java里的堆(heap)栈(stack)和方法区(method)
基础数据类型直接在栈空间分配, 方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收. 引用数据类型,需要用new来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量 . 方法 ...
- Python Geoip 获取IP地址经度、纬度
简介: 除了一些免费的 API 接口,例如 http://ipinfo.io/223.155.166.172 可以得到一些信息外,还可以通过 python-geoip 库来解决这个问题. shell ...
- node.js和npm离线安装
离线安装node.js和npm 1.下载官方安装包并拷贝到离线机器上. 官方下载地址:https://nodejs.org/en/download/ 2.解压文件: tar-xJf node-v8.9 ...
- 基于注解的方式管理Bean
--------------------siwuxie095 基于注解的方式管理 Bean (一)准备 ...
- ADF控件ID变化引发JS无法定位控件的解决方法
原文地址:ADF控件ID变化引发JS无法定位控件的解决方法作者:Nicholas JSFF定义的控件ID到了客户端时往往会改变.例如在JSFF中的一个的ID为"ot1",但是当这个 ...
- Golang之匿名函数和闭包
Go语言支持匿名函数,即函数可以像普通变量一样被传递或使用. 使用方法如下: main.go package main import ( "fmt" ) func main() { ...
- Cook-Torrence Illumination Model 的一些数学说明
Cook-Torrence 光照模型如下: 这个Io就是计算后最终的光强,主要是用来计算镜面反射光,漫反射和环境光的计算和Phong模型一致. F:Fresnel反射系数.主要用来说明反射光强度占入射 ...