马上加入IBC程序猿 各种源码随意下,各种教程随便看! 注册 每日签到 加入编程讨论群

C#教程 ASP.NET教程 C#视频教程程序源码享受不尽 C#技术求助 ASP.NET技术求助

【源码下载】 社群合作 申请版主 程序开发 【远程协助】 每天乐一乐 每日签到 【承接外包项目】 面试-葵花宝典下载

官方一群:

官方二群:

缓存cache(擦车)

[复制链接]
查看2393 | 回复1 | 2019-10-12 10:22:02 | 显示全部楼层 |阅读模式

第一次打仗到Cache的时间,是在WebForm中,第一次打仗,我就再也没能忘记,cache(擦车,的拼音)

客户端欣赏器缓存https://blog.csdn.net/y874961524/article/details/61419716

CDN缓存原理https://www.cnblogs.com/shijingxiang/articles/5179032.html

阿里云CDN开启设置https://jingyan.baidu.com/article/948f5924f1d642d80ff5f980.html

有句话叫做,系统性能优化的第一步,就是使用缓存,所以,缓存真的很重要

缓存:

  实际上是一种结果&目的,就是获取数据点时间,第一次获取之后找个地方存起来,反面直接用,这样一来可以提拔反面每次获取数据的效率。读取设置文件的时间把信息放在静态字段,这个就是缓存。缓存是无处不在的。

102203xc15nz3plcu9zhi1.png

我们来哀求一个网站,打开开辟职员工具

102203cbrzurur6wzarb9a.png

客户端缓存的利益:

  1、紧缩网络路径,加速相应速度

  2、减少哀求,低落服务器压力

欣赏器缓存毕竟是怎么做到的?

  打开一个网页,欣赏器-----哀求---服务器---处理哀求会发相应------欣赏器展示

  Http协议,数据传输的格式(协议,就像是两人交换,都用什么语言)

  信息是否缓存,一定是服务器控制的。ResponseHeader--Cache---Control来指定下缓存计谋,欣赏器看到了这个,就去存储一下。

第一次哀求服务器:

102204okwoubilblbbkmdi.png

再一次哀求服务器

102204bna8gk9wwzigkgaw.png

DNS是互联网的第一跳,DNS缓存就是CDN,内容分发网络,CDN就是加速缓存的

没有效CDN的哀求:

102205htjqa379f2qtt3q7.png

使用了CDN缓存

102205in8z8v6c2bveuktl.png

反向署理:

  1、隔离网络,保护服务器(节省公共IP)

  2、网络加速,反向署理双网卡

  3、负载平衡

  4、缓存(跟CDN,也是辨认一下header,压缩到一个物理路径/内存)

  为什么叫反向署理?因为他就是一个署理,一样平常的署理,是客户端和服务器之间,有一个署理,去做处理的。但是这个署理是安装在服务器端的。

102206nq2766mncr0x6tgk.png

几种缓存套路相同,但是位置不同,影响的范围也不同。

  客户端缓存:只影响当前用户

  CDN缓存:针对一批用户

  反向署理缓存:针对全部用户。

  客户端缓存,存在内存或者硬盘,下次直接用。Cookie,存在内存或者硬盘,欣赏器每次哀求服务器都会带上的信息。

什么时间用缓存?

  1、重复哀求,100人访问首页,每个人其实做的都一样,不就是重复

  2、耗时好资源

  3、结果没变的

下面有一个第三方数据存储和获取的地方:

  1. /// <summary>
  2. /// 第三方数据存储和获取的地方
  3. /// </summary>
  4. public class CustomCache
  5. {
  6. /// <summary>
  7. /// private:私有一下数据容器,安全
  8. /// static:不被GC
  9. /// 字典:读写效率高
  10. /// </summary>
  11. private static Dictionary<string, object> CustomCacheDictionary = new Dictionary<string, object>();
  12. public static void Add(string key, object oVaule)
  13. {
  14. CustomCacheDictionary.Add(key, oVaule);
  15. }
  16. /// <summary>
  17. /// 要求在Get前做Exists检测
  18. /// </summary>
  19. /// <typeparam name="T"></typeparam>
  20. /// <param name="key"></param>
  21. /// <returns></returns>
  22. public static T Get<T>(string key)
  23. {
  24. return (T)CustomCacheDictionary[key];
  25. }
  26. public static bool Exists(string key)
  27. {
  28. return CustomCacheDictionary.ContainsKey(key);
  29. }
  30. public static T GetT<T>(string key, Func<T> func)
  31. {
  32. T t = default(T);
  33. if (!CustomCache.Exists(key))
  34. {
  35. t = func.Invoke();
  36. CustomCache.Add(key, t);
  37. }
  38. else
  39. {
  40. t = CustomCache.Get<T>(key);
  41. }
  42. return t;
  43. }
  44. }
复制代码

存取数据的唯一标识:1 唯一的 2 能重现

  1. for (int i = 0; i < 5; i++)
  2. {
  3. Console.WriteLine($"获取{nameof(DBHelper)} {i}次 {DateTime.Now.ToString("yyyyMMdd HHmmss.fff")}");
  4. //List<Program> programList = DBHelper.Query<Program>(123);
  5. List<Program> programList = null;
  6. string key = $"{nameof(DBHelper)}_Query_{123}";
  7. //存取数据的唯一标识:1 唯一的 2 能重现
  8. //if (!CustomCache.Exists(key))
  9. //{
  10. // programList = DBHelper.Query<Program>(123);
  11. // CustomCache.Add(key, programList);
  12. //}
  13. //else
  14. //{
  15. // programList = CustomCache.Get<List<Program>>(key);
  16. //}
  17. programList = CustomCache.GetT<List<Program>>(key, () => DBHelper.Query<Program>(123));
  18. }
复制代码

  1. /// <summary>
  2. /// 数据库查询
  3. /// </summary>
  4. public class DBHelper
  5. {
  6. /// <summary>
  7. /// 1 耗时耗资源
  8. /// 2 参数固定时,结果稳定
  9. /// </summary>
  10. /// <typeparam name="T"></typeparam>
  11. /// <param name="index"></param>
  12. /// <returns></returns>
  13. public static List<T> Query<T>(int index)
  14. {
  15. Console.WriteLine("This is {0} Query", typeof(DBHelper));
  16. long lResult = 0;
  17. for (int i = index; i < 1000000000; i++)
  18. {
  19. lResult += i;
  20. }
  21. List<T> tList = new List<T>();
  22. for (int i = 0; i < index % 3; i++)
  23. {
  24. tList.Add(default(T));
  25. }
  26. return tList;
  27. }
  28. }
复制代码

  缓存优化性能,焦点就是结果重用,下次哀求照旧上一次的结果。如果数据库中有变化,岂不是用了一个错误的数据?是的,缓存是难免的,缓存难免会有脏数据,固然了,我们也会分门别类的去只管减少脏数据。

  用户--脚色--菜单,用户权限查的多+比力耗资源+相对稳固,非常得当缓存,缓存方式应该是用户id为key,菜单列表作为value。

  1. string name = "bingle";
  2. List<string> menu = new List<string>();
  3. if (!CustomCache.Exists(name))
  4. {
  5. menu = new List<string>() { "123", "125553", "143", "123456" };
  6. CustomCache.Add(name, menu);
  7. }
  8. else
  9. {
  10. menu = CustomCache.Get<List<string>>(name);
  11. }
复制代码

如果bingle的权限变化了,缓存应该失效。数据更新影响单挑缓存,常规做法是Remove而不是更新,因为缓存只是用来提拔效率的,而不是数据生存的,因此不必要更新,只必要删除就好,如果真的下次用上了,到时间再去初始化。

  1. CustomCache类增长删除缓存的方法:<br />
复制代码
  1. public static void Remove(string key)
  2. {
  3. CustomCacheDictionary.Remove(key);
  4. }
复制代码
  1. string name = "bingle";
  2. CustomCache.Remove(name);
  3. List<string> menu = new List<string>();
  4. if (!CustomCache.Exists(name))
  5. {
  6. menu = new List<string>() { "123", "125553", "143" };
  7. CustomCache.Add(name, menu);
  8. }
  9. else
  10. {
  11. menu = CustomCache.Get<List<string>>(name);
  12. }
复制代码

删除了某个菜单,影响了一大批用户。根据菜单--昭觉寺---找用户---每一个拼装key然后去Remove(最准确)。但是这种方式不可,为了缓存增长数据库的任务,最大的问题是数据量的问题,缓存是二八原则,只有20%的热门用户才缓存,这样做的本钱太高。

可以选择加上一个RemoveAll的方法

  1. public static void RemoveAll()
  2. {
  3. CustomCacheDictionary.Clear();
  4. }
复制代码

或者,菜单删除了,能不能只影响一部门的缓存数据呢?

  1、添加缓存时,key带上规则,比如权限包罗_menu_

  2、整理时,就只删除key含_menu_的

  1. /// <summary>
  2. /// 按条件删除
  3. /// </summary>
  4. /// <param name="func"></param>
  5. public static void RemoveCondition(Func<string, bool> func)
  6. {
  7. List<string> keyList = new List<string>();
  8. lock (CustomCache_Lock)
  9. foreach (var key in CustomCacheDictionary.Keys)
  10. {
  11. if (func.Invoke(key))
  12. {
  13. keyList.Add(key);
  14. }
  15. }
  16. keyList.ForEach(s => Remove(s));
  17. }
复制代码

第三方修改了数据,缓存并不知道,这个就没办法了

  a 可以调用接口整理缓存,b系统修改数据,调用c西永通知下缓存更新,b就只能容忍了,容忍脏数据,但是可以加上时间限制,减少影响时间。

时间,逾期计谋:

  永世有效----现在就是

  绝对逾期:

    有个时间点,高出就逾期了

  滑动逾期:

    多久之后逾期,如果期间更新/查询/查抄存在,就再次延长多久。

  1. /// <summary>
  2. /// 自动整理
  3. /// </summary>
  4. static CustomCache()
  5. {
  6. Task.Run(() =>
  7. {
  8. while (true)
  9. {
  10. try
  11. {
  12. List<string> keyList = new List<string>();
  13. lock (CustomCache_Lock)
  14. {
  15. foreach (var key in CustomCacheDictionary.Keys)
  16. {
  17. DataModel model = (DataModel)CustomCacheDictionary[key];
  18. if (model.ObsloteType != ObsloteType.Never && model.DeadLine < DateTime.Now)
  19. {
  20. keyList.Add(key);
  21. }
  22. }
  23. keyList.ForEach(s => Remove(s));
  24. }
  25. Thread.Sleep(1000 * 60 * 10);
  26. }
  27. catch (Exception ex)
  28. {
  29. Console.WriteLine(ex.Message);
  30. continue;
  31. }
  32. }
  33. });
  34. }
复制代码

多线程问题:

  1. List<Task> taskList = new List<Task>();
  2. for (int i = 0; i < 110000; i++)
  3. {
  4. int k = i;
  5. taskList.Add(Task.Run(() => CustomCache.Add($"TestKey_{k}", $"TestValue_{k}", 10)));
  6. }
  7. for (int i = 0; i < 100; i++)
  8. {
  9. int k = i;
  10. taskList.Add(Task.Run(() => CustomCache.Remove($"TestKey_{k}")));
  11. }
  12. for (int i = 0; i < 100; i++)
  13. {
  14. int k = i;
  15. taskList.Add(Task.Run(() => CustomCache.Exists($"TestKey_{k}")));
  16. }
  17. //Thread.Sleep(10*1000);
  18. Task.WaitAll(taskList.ToArray());
复制代码

多线程操作非现场安全的容器,会造成冲突

  1、线程安全容器ConcurrentDictionary

  2、用lock---Add/Remove/遍历,可以解决问题,但是性能呢?

    怎么低落影响,提拔性能呢?多个数据容器,多个锁,容器之间可以并发

为相识决多线程问题,CustomCache 类最终修改成如下:

102206jlroduo32rnt2lln.gif
102206mbmntby4e1s5w1ew.gif
  1. public class CustomCache
  2. {
  3. //ConcurrentDictionary
  4. private static readonly object CustomCache_Lock = new object();
  5. /// <summary>
  6. /// 自动整理
  7. /// </summary>
  8. static CustomCache()
  9. {
  10. Task.Run(() =>
  11. {
  12. while (true)
  13. {
  14. try
  15. {
  16. List<string> keyList = new List<string>();
  17. lock (CustomCache_Lock)
  18. {
  19. foreach (var key in CustomCacheDictionary.Keys)
  20. {
  21. DataModel model = (DataModel)CustomCacheDictionary[key];
  22. if (model.ObsloteType != ObsloteType.Never && model.DeadLine < DateTime.Now)
  23. {
  24. keyList.Add(key);
  25. }
  26. }
  27. keyList.ForEach(s => Remove(s));
  28. }
  29. Thread.Sleep(1000 * 60 * 10);
  30. }
  31. catch (Exception ex)
  32. {
  33. Console.WriteLine(ex.Message);
  34. continue;
  35. }
  36. }
  37. });
  38. }
  39. /// <summary>
  40. /// private:私有一下数据容器,安全
  41. /// static:不被GC
  42. /// 字典:读写效率高
  43. /// </summary>
  44. //private static Dictionary<string, object> CustomCacheDictionary = new Dictionary<string, object>();
  45. private static Dictionary<string, object> CustomCacheDictionary = new Dictionary<string, object>();
  46. public static void Add(string key, object oVaule)
  47. {
  48. lock (CustomCache_Lock)
  49. CustomCacheDictionary.Add(key, new DataModel()
  50. {
  51. Value = oVaule,
  52. ObsloteType = ObsloteType.Never,
  53. });
  54. }
  55. /// <summary>
  56. /// 绝对逾期
  57. /// </summary>
  58. /// <param name="key"></param>
  59. /// <param name="oVaule"></param>
  60. /// <param name="timeOutSecond"></param>
  61. public static void Add(string key, object oVaule, int timeOutSecond)
  62. {
  63. lock (CustomCache_Lock)
  64. CustomCacheDictionary.Add(key, new DataModel()
  65. {
  66. Value = oVaule,
  67. ObsloteType = ObsloteType.Absolutely,
  68. DeadLine = DateTime.Now.AddSeconds(timeOutSecond)
  69. });
  70. }
  71. /// <summary>
  72. /// 相对逾期
  73. /// </summary>
  74. /// <param name="key"></param>
  75. /// <param name="oVaule"></param>
  76. /// <param name="duration"></param>
  77. public static void Add(string key, object oVaule, TimeSpan duration)
  78. {
  79. lock (CustomCache_Lock)
  80. CustomCacheDictionary.Add(key, new DataModel()
  81. {
  82. Value = oVaule,
  83. ObsloteType = ObsloteType.Relative,
  84. DeadLine = DateTime.Now.Add(duration),
  85. Duration = duration
  86. });
  87. }
  88. /// <summary>
  89. /// 要求在Get前做Exists检测
  90. /// </summary>
  91. /// <typeparam name="T"></typeparam>
  92. /// <param name="key"></param>
  93. /// <returns></returns>
  94. public static T Get<T>(string key)
  95. {
  96. return (T)(((DataModel)CustomCacheDictionary[key]).Value);
  97. }
  98. /// <summary>
  99. /// 被动整理,哀求了数据,才能整理
  100. /// </summary>
  101. /// <param name="key"></param>
  102. /// <returns></returns>
  103. public static bool Exists(string key)
  104. {
  105. if (CustomCacheDictionary.ContainsKey(key))
  106. {
  107. DataModel model = (DataModel)CustomCacheDictionary[key];
  108. if (model.ObsloteType == ObsloteType.Never)
  109. {
  110. return true;
  111. }
  112. else if (model.DeadLine < DateTime.Now)//现在已经高出你的末了时间
  113. {
  114. lock (CustomCache_Lock)
  115. CustomCacheDictionary.Remove(key);
  116. return false;
  117. }
  118. else
  119. {
  120. if (model.ObsloteType == ObsloteType.Relative)//没有逾期&是滑动 所以要更新
  121. {
  122. model.DeadLine = DateTime.Now.Add(model.Duration);
  123. }
  124. return true;
  125. }
  126. }
  127. else
  128. {
  129. return false;
  130. }
  131. }
  132. /// <summary>
  133. /// 删除key
  134. /// </summary>
  135. /// <param name="key"></param>
  136. public static void Remove(string key)
  137. {
  138. lock (CustomCache_Lock)
  139. CustomCacheDictionary.Remove(key);
  140. }
  141. public static void RemoveAll()
  142. {
  143. lock (CustomCache_Lock)
  144. CustomCacheDictionary.Clear();
  145. }
  146. /// <summary>
  147. /// 按条件删除
  148. /// </summary>
  149. /// <param name="func"></param>
  150. public static void RemoveCondition(Func<string, bool> func)
  151. {
  152. List<string> keyList = new List<string>();
  153. lock (CustomCache_Lock)
  154. foreach (var key in CustomCacheDictionary.Keys)
  155. {
  156. if (func.Invoke(key))
  157. {
  158. keyList.Add(key);
  159. }
  160. }
  161. keyList.ForEach(s => Remove(s));
  162. }
  163. public static T GetT<T>(string key, Func<T> func)
  164. {
  165. T t = default(T);
  166. if (!CustomCache.Exists(key))
  167. {
  168. t = func.Invoke();
  169. CustomCache.Add(key, t);
  170. }
  171. else
  172. {
  173. t = CustomCache.Get<T>(key);
  174. }
  175. return t;
  176. }
  177. }
  178. /// <summary>
  179. /// 缓存的信息
  180. /// </summary>
  181. internal class DataModel
  182. {
  183. public object Value { get; set; }
  184. public ObsloteType ObsloteType { get; set; }
  185. public DateTime DeadLine { get; set; }
  186. public TimeSpan Duration { get; set; }
  187. //数据整理后出发事件
  188. public event Action DataClearEvent;
  189. }
  190. public enum ObsloteType
  191. {
  192. Never,
  193. Absolutely,
  194. Relative
  195. }
复制代码
View Code
102207lvotmf9gotmppglx.gif
102207chl11h1hgadu26m4.gif
  1. public class CustomCacheNew
  2. {
  3. //动态初始化多个容器和多个锁
  4. private static int CPUNumer = 0;//获取系统的CPU数
  5. private static List<Dictionary<string, object>> DictionaryList = new List<Dictionary<string, object>>();
  6. private static List<object> LockList = new List<object>();
  7. static CustomCacheNew()
  8. {
  9. CPUNumer = 4;
  10. for (int i = 0; i < CPUNumer; i++)
  11. {
  12. DictionaryList.Add(new Dictionary<string, object>());
  13. LockList.Add(new object());
  14. }
  15. Task.Run(() =>
  16. {
  17. while (true)
  18. {
  19. Thread.Sleep(1000 * 60 * 10);
  20. try
  21. {
  22. for (int i = 0; i < CPUNumer; i++)
  23. {
  24. List<string> keyList = new List<string>();
  25. lock (LockList[i])//减少锁的影响范围
  26. {
  27. foreach (var key in DictionaryList[i].Keys)
  28. {
  29. DataModel model = (DataModel)DictionaryList[i][key];
  30. if (model.ObsloteType != ObsloteType.Never && model.DeadLine < DateTime.Now)
  31. {
  32. keyList.Add(key);
  33. }
  34. }
  35. keyList.ForEach(s => DictionaryList[i].Remove(s));
  36. }
  37. }
  38. }
  39. catch (Exception ex)
  40. {
  41. Console.WriteLine(ex.Message);
  42. continue;
  43. }
  44. }
  45. });
  46. }
复制代码
View Code

缓存毕竟那里用?满足哪些特点得当用缓存?

  1、访问频仍

  2、耗时耗资源

  3、相对稳固

  4、体积不那么大的

  不是说严酷满足,详细的还要看情况,存一次能查三次,就值得缓存(大型想换标准)

  下面应该用缓存

    1、字典数据

    2、省市区
    3、设置文件
    4、网站公告信息
    5、部门权限,菜单权限
    6、热搜
    7、种别列表/产物列表
    8、用户,其实Session也是缓存的一种表现

  股票信息代价/彩票开奖信息,这些不能用缓存,即时性要求很高。图片/视频,这些也不可,太大了。商品评论,这个可以用缓存的,虽然评论汇编,但是这个不重要,我们不一定非要看到最新的,而且第一页一样平常稳定。

  可以测试下CustomCache的性能,十万/百万/万万 插入/获取/删除的性能。

  1. <br /><br />
复制代码







来源:https://www.cnblogs.com/taotaozhuanyong/p/11565162.html
C#论坛 www.ibcibc.com IBC编程社区
C#
C#论坛
IBC编程社区
*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则