<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Cache | Liao Lile</title>
    <link>https://liaolile.com/tag/cache/</link>
      <atom:link href="https://liaolile.com/tag/cache/index.xml" rel="self" type="application/rss+xml" />
    <description>Cache</description>
    <generator>Wowchemy (https://wowchemy.com)</generator><language>zh-Hans</language><lastBuildDate>Mon, 04 Oct 2021 23:23:10 +0000</lastBuildDate>
    <image>
      <url>https://liaolile.com/media/icon_hu0b7a4cb9992c9ac0e91bd28ffd38dd00_9727_512x512_fill_lanczos_center_3.png</url>
      <title>Cache</title>
      <link>https://liaolile.com/tag/cache/</link>
    </image>
    
    <item>
      <title>说说缓存</title>
      <link>https://liaolile.com/post/tech/distributesystem/%E8%AF%B4%E8%AF%B4%E7%BC%93%E5%AD%98/</link>
      <pubDate>Mon, 04 Oct 2021 23:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/distributesystem/%E8%AF%B4%E8%AF%B4%E7%BC%93%E5%AD%98/</guid>
      <description>&lt;p&gt;&lt;strong&gt;缓存使用场景：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;从&lt;strong&gt;硬件的角度&lt;/strong&gt;来说，缓存就是可以进行高速数据交换的存储器。最经典例子就是&lt;code&gt;CPU&lt;/code&gt;层面的多级缓存：性能最高的寄存器、多级缓存L1/L2/L3、主存，外部的机械硬盘。计算机总是优先从读写性能最好的存储器中来读写数据。&lt;/p&gt;
&lt;p&gt;从&lt;strong&gt;中间件的角度&lt;/strong&gt;来看，缓存在&lt;code&gt;数据库&lt;/code&gt;中应用，如Mysql拿到一个查询请求后，先会查询缓存是否命中（key为查询语句，value为查询的结果），如果命中则返回；实际中不建议，对于业务表查询缓存失效的概率极高；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RocketMQ&lt;/code&gt;中的缓存，是在Page Cache机制的预读作用下使得Consumer queue文件的读性能几乎接近内存。Page Cache是操作系统对文件的缓存，使用一部分内存用作Page Cache。对于数据的写入，操作系统会先写入至Cache中，随后异步的方式由&lt;code&gt;pdflush&lt;/code&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;内核线程将Cache内的数据刷盘。对于数据读取，如果未出现命中Page Cache，操作系统从屋里磁盘上访问读取文件同时，会顺序对其相邻块数据文件进行预读取Read Ahead。Page Cache利用的是&lt;em&gt;时间局部性&lt;/em&gt;原理，最近访问的数据接下来再次访问当。预读取数据放入Page Cache利用的是&lt;em&gt;空间局部性&lt;/em&gt;原理，依据数据往往是连续访问。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Elastic Search&lt;/code&gt;中的缓存&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;包括Query Cache/Filter Cache、Request Cache、Field Data Cache。Query Cache就是对一个查询中包含的过滤器执行结果进行缓存；Request Cache模块就是为了缓存这些“分片级”的本地结果集，一个面向请求的缓存，缓存的key是查询DSL字符串。Fielddata是专门针对分词的字段在query-time（查询期间）的数据结构的缓存。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;常见主流的缓存算法&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LRU(Least-Recently-Used): 替换掉最近请求最少的对象，实际中使用最广。cpu缓存淘汰和虚拟内存效果好，web应用欠佳&lt;/li&gt;
&lt;li&gt;LFU(Least-Frequently-Used): 缓存污染问题(一个先前流行的缓存对象会在缓存中驻留很长时间)&lt;/li&gt;
&lt;li&gt;LRU2(Least Recently Used 2): 为什么LRU2优于LRU：当一次访问过来的时候，在缓存系统中找出最少最近使用的对象是一项时间复杂度非常高的运算，这就是为什么LRU2是最好的选择。&lt;/li&gt;
&lt;li&gt;2Q(two queues)。多级缓存&lt;/li&gt;
&lt;li&gt;SIZE：替换占用空间最大的。也会有缓存污染&lt;/li&gt;
&lt;li&gt;LRU-Threashold：不超过某一个size 的，其他与 LRU 相同&lt;/li&gt;
&lt;li&gt;Log(Size) + LRU: 替换 size 最大的对象，当size相同按 LRU 替换&lt;/li&gt;
&lt;li&gt;Hyper-G: LFU 改进版，同时考虑上次访问时间和对象 size&lt;/li&gt;
&lt;li&gt;Pitkow/Recker: 替换最近最少使用对象，除非所有对象都是今天访问过的。如果是，替换调最大的对象&lt;/li&gt;
&lt;li&gt;Lowest-Latency-First: 替换下载时间最少的，最小化平均延迟&lt;/li&gt;
&lt;li&gt;Hybrid Hybrid: 保留效用最低的会被替换掉&lt;/li&gt;
&lt;li&gt;Lowest Relative Value(LRV): 替换保留效用最低的&lt;/li&gt;
&lt;li&gt;Adaptive Replacement Cache(ARC)&lt;/li&gt;
&lt;li&gt;Most Recently Used(MRU)&lt;/li&gt;
&lt;li&gt;First in First out(FIFO)&lt;/li&gt;
&lt;li&gt;Random Cache&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;缓存的应用&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;以web应用为例说明，用户请求到后台，会先从缓存中取数据，如果在缓存中取到数据，就直接返回结果，如果取不到数据就需要查询数据库，从数据库中取数据，从数据库中取到数据后会同步更新到缓存，并返回结果。下一个用户就可以直接从缓存中取值了。那如果在数据库也没有取到，就只能直接返回空结果。在该场景下，缓存主要是为了缓解数据库访问压力，提升请求响应；&lt;/p&gt;
&lt;div class=&#34;mermaid&#34;&gt;flowchart LR
id1[用户请求]
id2{Redis中请求特征Key是否存在}
id3[获取redis中数据]
id4{数据库中请求特征key是否存在}
id5[更新Redis数据]
id6[返回空]
id7[返回Redis数据]
E[结束]

id1[用户请求] --&gt;id2
id2 --&gt;|Yes|id3
id2 --&gt;|No| id4
id3 --&gt; id7
id7 --&gt; E
id4 --&gt; |Yes|id5
id4 --&gt; |No| id6
id5--&gt; id7
id6--&gt; E
 
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;缓存失效或者异常&lt;/strong&gt;，导致访问压力流转到数据库，使得数据库负载过高；归于提升缓存命中率，同时数据库需要限流；&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;缓存穿透:&lt;/p&gt;
&lt;p&gt;外部可以非法请求一个缓存和数据库中必定不存在的数据，让其击穿缓存直接打到数据库，不断的大流量攻击就可以让数据库瘫痪。应对这种情况的发生，使用布隆过滤器进行过滤避免击穿，布隆过滤器存储空间小，可以存储大量的key。但是存在误判：布隆过滤器中没有的元素一定没有，但是布隆过滤器提示有的元素不一定有。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;缓存击穿：&lt;/p&gt;
&lt;p&gt;当缓存数据失效的瞬间，大量的请求打入而没有命中导致直接打入数据库；需要通过互斥锁让线程回写缓存，其他线程等待回写缓存后再读取，这种方案缺点是吞吐量不够；另外可以设置热点数据不过期，或者异步线程基于要过期的数据缓存重构建；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;缓存雪崩：&lt;/p&gt;
&lt;p&gt;缓存中数据大批量到过期时间，而查询数据量大落在数据库上，引起数据库压力大而宕机。缓存击穿是并发查询同一条数据，缓存雪崩是不同数据都过期了，很多数据查不到而查数据库。需要结合业务分析进行缓存预热，针对热key的失效点均衡分布。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;缓存预热异常&lt;/p&gt;
&lt;p&gt;系统上线后，不需要用户访问后才加载缓存数据，而是先查数据库构建好缓存；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;缓存降级异常&lt;/p&gt;
&lt;p&gt;缓存降级是指缓存失效的或者缓存服务器宕机后，不去访问数据库，而是直接返回默认数据或者访问服务的内存数据。降级一般是有损的，需要考虑其对业务的影响；&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://zhuanlan.zhihu.com/p/71217136&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Linux中的Page Cache  - 知乎 (zhihu.com)&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.csdn.net/chennanymy/article/details/52504386&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Elasticsearch2.x 三种缓存介绍：Query Cache、Request Cache、Fielddata Cache_飞奔的代码的博客-CSDN博客_es 缓存&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
  </channel>
</rss>
