{"componentChunkName":"component---src-templates-blog-post-js","path":"/blog/2020-06-29-cache/","result":{"data":{"markdownRemark":{"id":"7d9d225a-049b-500f-a96e-5aab11596152","html":"<h1>缓存（Cache）</h1>\n<p>存储在计算机上的一个原始数据复制集，以便于访问。</p>\n<p>缓存是介于数据访问者和数据源之间的一种高速、临时存储，当数据需要<code>多次读取</code>的时候，用于加快读取的速度。</p>\n<h2>1 缓冲（Buffer）是什么</h2>\n<p>也是一种高速存储，解决两个设备读取数据速度不匹配问题。</p>\n<h2>2 缓存应用场景</h2>\n<ul>\n<li>CPU 缓存</li>\n<li>操作系统缓存</li>\n<li>数据库缓存</li>\n<li>语言编译缓存</li>\n<li>CDN 缓存</li>\n<li>代理和反向代理缓存</li>\n<li>前端缓存 - 移动端、浏览器缓存</li>\n<li>应用程序缓存 - 本地缓存、页面静态化</li>\n<li>分布式对象缓存</li>\n</ul>\n<p><img src=\"/static/img/cache/QQ20200703-223735@2x.png\"></p>\n<h2>3 缓存数据存储</h2>\n<h3>3.1 Hash 表</h3>\n<p>数据已 key value 形式存储在<code>数组</code>中，计算 key 值 hashcode ，计算 hashcode 对应 hash 表索引。</p>\n<p>hashcode 求模计算 hash 表索引</p>\n<h3>3.2 树</h3>\n<h2>4 缓存的关键指标 - 缓存命中率</h2>\n<p>缓存是否有效依赖于能多少次重用同一个缓存相应业务请求，这个度量指标被称为缓存命中率。</p>\n<h3>4.1 影响缓存命中率的主要指标</h3>\n<h4>4.1.1 缓存键集合大小</h4>\n<p>缓存中使用键来唯一标识一个对象。例如， 商品 ID、IP 地址、国家名称等。键数量越少，数据被缓存的可能性越高，缓存的效率越高。</p>\n<h4>4.1.2 缓存可使用物理空间</h4>\n<p>缓存物理资源是有限的，不能无限扩展。缓存资源不足时，需要删除部分已缓存数据（LRU）。缓存物理空间越大能缓存的数据越多，缓存命中率越高。</p>\n<h4>4.1.3 缓存对象生存时间</h4>\n<p>TTL（Time To Live）。使用缓存面临的一个问题是数据一致性，为了保证一定程度上的一致性，需要对缓存设置有效时间或者在数据更新时通知删除。业务是变动可能性越小、有效时间越长的缓存命中率越高。</p>\n<h2>5 缓存分类</h2>\n<h3>5.1 代理缓存</h3>\n<p>PC 用户端自建网络代理服务器，代理缓存网络访问。</p>\n<h3>5.2 反向代理缓存</h3>\n<p>服务端网络访问反向代理服务器。</p>\n<h3>5.3 内容分发网络（CDN）</h3>\n<p>网络运营商托管反向代理服务器，主要面向视频、图片等流量需求大的网站。</p>\n<h3>5.4 前端缓存</h3>\n<p>浏览器、App 等用户端本地缓存。</p>\n<h3>5.5 服务端缓存</h3>\n<p>后端应用本地缓存。</p>\n<ul>\n<li>缓存在当前函数中</li>\n<li>缓存在共享内存中</li>\n</ul>\n<h4>5.5.1 常见工具</h4>\n<h5>5.5.1.1 Map</h5>\n<h5>5.5.1.2 OSCache</h5>\n<h5>5.5.1.3 Ecache</h5>\n<h5>5.5.1.4 JBoss 缓存</h5>\n<h5>5.5.1.5 Guava Cache</h5>\n<h3>5.6 远程分布式集中缓存</h3>\n<h4>5.6.1 Memcached</h4>\n<p>share nothing</p>\n<p><img src=\"/static/img/cache/products-grid3.png\" alt=\"memcached\"></p>\n<h5>Memcached 客户端集群路由</h5>\n<ul>\n<li>hash 表</li>\n<li>一致性 hash</li>\n</ul>\n<h4>5.6.2 Redis</h4>\n<p>6.x 版本一下单线程，多路复用。</p>\n<p>支持常用数据结构</p>\n<h6>5.6.2.1 集群</h6>\n<ul>\n<li>Redis 集群预分好 16384 个桶，当需要在 Redis 集群中放置一个 key-value 时，根据 CRC16(key) mod 16385 的值，决定将一个  key 放到哪个桶中</li>\n<li>redis-cluster 把所有的物理节点映射到[0-16384] slot 上（不一定是平均分配）， cluster 负责维护 slot 与服务器的映射关系。</li>\n<li>客户端与 Redis 节点直连，客户端不需要链接集群所有节点，连接集群中任何一个可用节点即可。</li>\n<li>所有 Redis 节点彼此互联。</li>\n</ul>\n<h2>6 缓存类型</h2>\n<h3>6.1 通读缓存</h3>\n<p>缓存服务代理所有流量，客户端只和缓存交互。</p>\n<h3>6.2 旁路缓存</h3>\n<p>客户端可以访问数据源，决定是否读取缓存。</p>\n<h2>7 合理使用缓存</h2>\n<ul>\n<li>避免缓存频繁修改的数据</li>\n<li>避免缓存非热点数据</li>\n<li>数据不一致与脏读</li>\n<li>缓存雪崩 - 缓存服务崩溃，引必服务器压力大从而不可用</li>\n<li>缓存预热</li>\n<li>缓存穿透 - 访问的缓存在数据源中不存在，每次请求都会落库。对不存在的 key 值存储为 null，设置失效时间</li>\n</ul>\n<h2>8 缓存的高可用要求</h2>\n<p>当把缓存服务器充当一个数据库时，需要保证其可用性。如，使用 Redis 存储用户 Session。</p>","frontmatter":{"date":"June 29, 2020","title":"缓存","description":"","tags":null}}},"pageContext":{"id":"7d9d225a-049b-500f-a96e-5aab11596152"}}}