zoukankan      html  css  js  c++  java
  • .Net 数据缓存浅析

    目录                                                

    1场景出发

       1.1数据请求

       1.2优化改进

    2缓存

    3缓存进阶

       3.1缓存清除

       3.2有效性

       3.3线程安全

    4适用场景和优劣

       4.1适用场景

       4.2优劣

    5结语

    1场景出发

    1.1数据请求

    小吴开发了一个购物网站,其中涉及到这样一个环节:访客用户请求页面时,会请求数据库获取商品分类信息,然后返回该数据,展示商品的分类

    对于这个环节,他是这样处理的 

     1 /// <summary>
     2     /// 模拟数据库获取数据耗时操作
     3     /// </summary>
     4     public class DataSource
     5     {
     6         /// <summary>
     7         /// 获取商品分类
     8         /// </summary>
     9         /// <returns></returns>
    10         public static string GetCategories()
    11         {
    12             Thread.Sleep(5000);//模拟耗时
    13             return "There are categories"; 
    14         }
    15     }
    DataSource
     1    class Program
     2     {
     3 
     4         static void Main(string[] args)
     5         {
     6             string cats = DataSource.GetCategories();
     7 
     8             Console.WriteLine(cats);
     9 
    10             Console.ReadKey();
    11         }
    12     }
    GetData 

     在初阶阶段,访客用户数量比较少,网站能够很好的运营

     1.2优化改进

    随着访客用户数量的增加,服务器压力越来越大,不少用户开始向客服抱怨,网页响应速度太慢

    小吴不得不开始优化系统,他考虑到商品分类信息请求次数很多,但每次却是请求相同的数据,于是他决定把这部分数据放在常驻内存的静态变量中,然后在数据库直接获取数据上再加一层,来提供数据服务,改进如下:

     1  /// <summary>
     2     /// 模拟数据库获取数据耗时操作
     3     /// </summary>
     4     public class DataSource
     5     {
     6         /// <summary>
     7         /// 获取商品分类
     8         /// </summary>
     9         /// <returns></returns>
    10         public static string GetCategories()
    11         {
    12             Thread.Sleep(5000);//模拟耗时
    13             return "There are categories"; 
    14         }
    15     }
    DataSource
     1   /// <summary>
     2     /// 静态字典缓存数据
     3     /// </summary>
     4     public class MyCache
     5     {
     6         private static Dictionary<string, object> _dictionary = new Dictionary<string, object>();
     7 
     8         public static void Add(string key,object obj)
     9         {
    10             _dictionary.Add(key, obj);
    11         }
    12 
    13         public static bool Exist(string key)
    14         {
    15             return _dictionary.ContainsKey(key);
    16         }
    17 
    18         public static void remove(string key)
    19         {
    20             _dictionary.Remove(key);
    21         }
    22 
    23         public static void removeAll(string key)
    24         {
    25             _dictionary = new Dictionary<string, object>();
    26         }
    27 
    28         public static T Get<T>(string key)
    29         {
    30             return (T)_dictionary[key];
    31         }
    32     }
    MyCache
     1 /// <summary>
     2     /// 数据处理类
     3     /// </summary>
     4     public class DataProxy
     5     {
     6         /// <summary>
     7         /// 获取商品分类
     8         /// </summary>
     9         /// <returns></returns>
    10         public static string GetCategories()
    11         {
    12             if (MyCache.Exist("Categories"))
    13             {
    14                 return MyCache.Get<string>("Categories");
    15             }
    16 
    17             else
    18             {
    19                 MyCache.Add("Categories", DataSource.GetCategories());
    20 
    21                 return DataSource.GetCategories();
    22             }
    23         }
    24     }
    DataProxy
     1     class Program
     2     {
     3 
     4         static void Main(string[] args)
     5         {
     6             string cats,cats1, cats2;
     7 
     8             cats = DataProxy.GetCategories();
     9 
    10             Console.WriteLine(cats);
    11 
    12             cats1 = DataProxy.GetCategories();
    13 
    14             Console.WriteLine(cats1);
    15 
    16             cats2 = DataProxy.GetCategories();
    17 
    18             Console.WriteLine(cats2);
    19 
    20             Console.ReadKey();
    21         }
    22     }
    GetData

     经过这样的优化后,网站响应速度一下子就得到了提升  

    2缓存

    上述场景就是对缓存的一种应用,它是系统性能优化的第一步

    原因是使用缓存,缩短了获取数据的时间

    这里重点讲解的是服务器端数据缓存,它只是缓存的一部分

    下面是http请求过程

     可以看到几乎各个环节都涉及到了缓存

    3缓存进阶

    上述只是数据缓存最简单的例子,在实际的开发过程中,我们还会面对更多的情形,下面我来简单的进阶一下

    3.1缓存清理

    当我们已知一条缓存的数据已经更新,我们该如何做呢?

    上述代码已经解决了这个问题,Remove方法:即去掉这个键值对,然后在数据库获取最新的数据

    那么如果多条缓存被影响,我们该如何做呢?

    上述的RemoveAll方法?当然这是最直接有效的方法,但是这样会造成缓存穿透,在一瞬间丢失所有的缓存,数据库的压力将会骤增

    一个比较有效的方法:我们在添加缓存的时候,把缓存的key值与它的数据义务相联系,即命名更加有意义,这样当某部分受到影响的时候,我们可以直接根据命名来确定是否更改

    3.2缓存有效性

    在使用缓存的过程中,我们遇到更多的情况是:程序根本不知道,数据已经发生变化

    面对这种情况,我们一般采取的措施:给缓存加上有效期

    在有效期内,直接使用缓存,超过有效期,在数据库获取最新数据并缓存起来

    我们也可以同时增加一条线程,来不间断的主动检查缓存有效期,避免只有在使用的时候才检查的被动状态

    代码如下:

     1   /// <summary>
     2     /// 静态字典缓存数据
     3     /// </summary>
     4     public class MyCache
     5     {
     6         /// <summary>
     7         /// 每1个小时主动检查缓存过期项一次
     8         /// </summary>
     9         static MyCache()
    10         {
    11             Task.Run(() =>
    12             {
    13                 Thread.Sleep(3600 * 1000);
    14 
    15                 List<string> keyList = new List<string>(); //过期key集合
    16 
    17                 foreach (var item in _dictionary.Keys)
    18                 {
    19                     if (_dictionary[item].Value < DateTime.Now)
    20                     {
    21                         keyList.Add(item); //已过期
    22                     }
    23                 }
    24 
    25                 keyList.ForEach(p => { _dictionary.Remove(p); });
    26             });
    27         }
    28 
    29         private static Dictionary<string, KeyValuePair<object, DateTime>> _dictionary
    30             = new Dictionary<string, KeyValuePair<object, DateTime>>();
    31 
    32         public static void Add(string key, object obj, int minute = 60)
    33         {
    34             _dictionary.Add(key, new KeyValuePair<object, DateTime>(obj, DateTime.Now.AddMinutes(minute)));
    35         }
    36 
    37         public static bool Exist(string key)
    38         {
    39             return _dictionary.ContainsKey(key);
    40         }
    41 
    42         public static void remove(string key)
    43         {
    44             _dictionary.Remove(key);
    45         }
    46 
    47         public static void removeAll(string key)
    48         {
    49             _dictionary = new Dictionary<string, KeyValuePair<object, DateTime>>();
    50         }
    51 
    52         public static T Get<T>(string key)
    53         {
    54             return (T)_dictionary[key].Key;
    55         }
    56     }
    MyCache

    3.3线程安全

    在单线程下,上述缓存简例,是没有问题的,可是我们往往面对的是多线程迸发,那么上述的例子,就会有线程安全问题

    在键值对添加这里,如果多个线程访问,就会因为添加相同的键值,而导致程序崩溃

    所以我们可以加锁,只允许一个线程先访问,后续的线程进来时判断键值是否已经存在

    代码如下

     1     /// <summary>
     2     /// 静态字典缓存数据
     3     /// </summary>
     4     public class MyCache
     5     {
     6         private static object _lock = new object();
     7         /// <summary>
     8         /// 每1个小时主动检查缓存过期项一次
     9         /// </summary>
    10         static MyCache()
    11         {
    12             Task.Run(() =>
    13             {
    14                 Thread.Sleep(3600 * 1000);
    15 
    16                 List<string> keyList = new List<string>(); //过期key集合
    17 
    18                 foreach (var item in _dictionary.Keys)
    19                 {
    20                     if (_dictionary[item].Value < DateTime.Now)
    21                     {
    22                         keyList.Add(item); //已过期
    23                     }
    24                 }
    25 
    26                 keyList.ForEach(p => { _dictionary.Remove(p); });
    27             });
    28         }
    29 
    30         private static Dictionary<string, KeyValuePair<object, DateTime>> _dictionary
    31             = new Dictionary<string, KeyValuePair<object, DateTime>>();
    32 
    33         public static void Add(string key, object obj, int minute = 60)
    34         {
    35             lock (_lock)
    36             {
    37                 if (_dictionary.ContainsKey(key))
    38                 {
    39                     return;
    40                 }
    41                 else
    42                 {
    43                     _dictionary.Add(key, new KeyValuePair<object, DateTime>(obj, DateTime.Now.AddMinutes(minute)));
    44                 }
    45             }
    46         }
    47 
    48         public static bool Exist(string key)
    49         {
    50             return _dictionary.ContainsKey(key);
    51         }
    52 
    53         public static void remove(string key)
    54         {
    55             _dictionary.Remove(key);
    56         }
    57 
    58         public static void removeAll(string key)
    59         {
    60             _dictionary = new Dictionary<string, KeyValuePair<object, DateTime>>();
    61         }
    62 
    63         public static T Get<T>(string key)
    64         {
    65             return (T)_dictionary[key].Key;
    66         }
    67     }
    MyCache

    4适用场景和优劣

    没有任何技术是完美的,我们所做的只能是具体问题具体分析

    缓存会在够解决一系列问题的同时,带来新的问题,我们所能够做的是扬长避短

    4.1适用场景

    1数据实时性要求不太高:缓存的本质决定了其一定会有脏数据,即使加了有效期,也会有延迟

    2多次请求:如果没有请求多次,那么也没有缓存的必要

    2体积小:因为缓存是在程序进程内存里面的,所以空间有限

    4.2优劣

    优势:能够缩短查询路径,更快的得到响应, 优化系统性能,

    劣势:无法确定数据是否是最新的,有所延迟

    5结语

    至今为止,关于缓存与其他各种技术的相结合和各种关于缓存的框架层出不穷,如果一开始就注其表面,会感到晦涩难以深入,不如透过现象回到本质,以最单纯的想法去理解它,那么反而更容易接近它,只要能够明白这些,那么对于那些立其之上的衍生物,只会是游刃有余

    出自:博客园-半路独行

    原文地址:https://www.cnblogs.com/banluduxing/p/9238838.html

    本文出自于http://www.cnblogs.com/banluduxing 转载请注明出处。

  • 相关阅读:
    Hbase写数据,存数据,读数据的详细过程 分类: B7_HBASE 2015-03-15 20:11 117人阅读 评论(0) 收藏
    机器学习(十四):深度学习梯度优化算法(SGD SGD-M NAG AdaGrad RMSProp Adam )
    机器学习(十三):卷积神经网络(CNN)
    机器学习(十一):FP增长(FP-growth)
    机器学习(十):Apriori算法
    Gulp命令自动生成精灵图
    esLint参数设置
    js 监控iframe URL的变化
    React+Redux学习笔记:React+Redux简易开发步骤
    React组件实现越级传递属性
  • 原文地址:https://www.cnblogs.com/banluduxing/p/9238838.html
Copyright © 2011-2022 走看看