江苏营销型网站公司,网站制作公司网站建设网站,网站维护员,美工详情页设计一般多少钱最近在狂补优化方面的知识#xff0c;缓存也是优化的一大方向。之前关于缓存只是知道它的功能#xff0c;再多不知道了#xff0c;这里整理缓存相关的知识#xff0c;算是优化入门吧。 相关概念缓存 是“存贮使用频繁的数据的临时地方#xff0c;因为取原始数据的代价太大… 最近在狂补优化方面的知识缓存也是优化的一大方向。之前关于缓存只是知道它的功能再多不知道了这里整理缓存相关的知识算是优化入门吧。 相关概念缓存 是“存贮使用频繁的数据的临时地方因为取原始数据的代价太大了所以我可以取得快一些。” 缓存可以认为是数据的池这些数据是从数据库里的真实数据复制出来的并且为了能别取回被标上了标签键 ID。 缓存分类 硬件缓存 它指的是一块芯片可以被集成到硬盘或者是CPU上。它的作用就是充当硬盘CPU与外界接口通常是内存之间的暂存器。利用缓存可以减轻系统的负荷同时提高数据的传输速率如硬盘缓存和CPU缓存。 客户端缓存 某些应用如浏览器手机淘宝等为了实现能够快速响应用户的请求会把用户之前浏览的东西如图片等存在本地。在下次访问时如果本地的缓存里有请求的内容那么就直接展示出来不用再次向服务器请求。 服务端缓存 它与客户端缓存目的相同只不过是站在服务器这边考虑的。如果每次接到客户端请求都要连接一次数据库当用户请求多的时候负载过大。这时可以把一些经常被请求的数据存放在内存中当有请求时直接返回不用经过数据库。这样就可以减轻数据库的负担。 缓存的工作原理 当客户端向服务器请求一个资源时服务器首先在缓存中找如果在缓存中那么直接返回不需要连接数据库如果请求的资源不在缓存中这时再去数据库中找找到后返回给客户端并将这个资源加入缓存中。 命中HIT 当客户发端起一个请求如果被请求的资源在缓存中这个资源就会被使用我们就叫它缓存命中。 未命中MISS 当客户端发起一个请求如果没有在缓存中找到我们称这种情况为缓存未命中。这时就需要查询数据库并且将查询结果加入缓存中。 存储成本 当未命中时我们会从数据库取出数据然后加入缓存。把这个数据放入缓存所需要的时间和空间就是存储成本。 失效 当缓存中的数据需要更新时就意味着缓存中的这个数据失效了。 一种是数据库中的数据发生了变化那么如果这个数据在缓存相应的缓存数据也要同步更新。例如原来 id1 的编程语言叫 Java结果管理员修改成了 PHP那么缓存里面的 id1 的值就要同步成最新的值。 另一种情况是该缓存过了失效时间。因为缓存会占用内存太多的缓存是不合理的我们可以通过设置失效时间的方式让缓存定时过期失效。 失效策略缓存算法 如果缓存满了而当前请求又没有命中缓存那么就会按照某一种策略把缓存中的某个旧资源剔除而把新的资源加入缓存。这些决定应该剔除哪个旧资源的策略统称为失效策略。 替代策略 当缓存没有命中时并且缓存容量已经满了就需要在缓存中踢出一个老的条目加入一条新的条目而到底应该踢出什么条目就由替代策略决定。 最优替代策略 最优的替代策略就是想把缓存中最没用的条目给踢出去但是未来是不能够被预知的所以这种策略是不可能实现的。但是有很多策略都是朝着这个目前去努力。 缓存算法原则上失效策略需要考虑到以下这几点 成本 如果缓存对象有不同的存储成本应该把那些难以获得的对象保存下来 容量 如果缓存对象有不同的大小应该把那些大的缓存对象清除让更多的小缓存对象进来了 时间 一些缓存设定有过期时间应该在到时间之后将它们失效。 应该根据缓存对象的性质选择合适的失效策略常见的失效策略有这么几种 关于常见的缓存算法见博客缓存那些事–常用的缓存失效策略 缓存中存在的问题在缓存中存在缓存击穿、缓存雪崩、缓存并发等问题 缓存击穿问题描述 缓存穿透是指查询一个一定不存在的数据此时缓存是不被把命中的那么就需要查数据库来获取这个值并写入缓存后返回但是由于在数据库中也没有这个值所以结果也不会写入缓存中。这将导致这个存在的数据每次请求都要到存储层去查询失去了缓存的意义。 在流量大的时候可能数据库就崩溃了。另外要是有人利用不存在的 key 频繁请求数据库这就是系统的漏洞。 解决方法常见的有两种过滤器和设定指定值。 1过滤器 最常见的是采用布隆过滤器将所有可能存在的数据哈希到一个足够大的 bitmap 中一个一定不存在的数据会被这个 bitmap 拦截掉从而避免了对底层存储系统的查询压力。 2设定指定值 这种方法比较巧妙如果一个查询返回的数据为空可能由于数据不存在也可能是系统故障我们仍然把这个空结果进行缓存缓存的值设定为一个指定值同时设置它的过期时间很短最长不超过五分钟。因为缓存会占用内存长时间缓存一个不存在的值比较耗资源。在这五分钟内这个值可能由于写入操作从而不再是一个不存在的值这是就要更新缓存用真实值替代指定值。 比如设定不存在的值缓存为 也就是 “key” “”。当返回这个 值的时候就可以认为这是不存在的 key然后决定是继续等待访问还是放弃掉这次操作。如果继续等待访问那么经过一个时间轮询点后再次请求这个 key如果取到的值不再是 则可以认为这时候 key 有值了从而避免了透传到数据库从而把大量的类似请求挡在了缓存之中。 缓存雪崩问题描述 缓存雪崩指的是在某一个时刻大量缓存同时失效请求全部转到了数据库导致数据库压力过大。 引起这个问题的主要原因还是高并发。平时我们设定一个缓存的过期时间时可能有一些会设置1分钟后或5分钟后。当并发很高时会出在某一个时间同时生成了很多的缓存并且过期时间都一样这个时候就可能引发一当过期时间到后这些缓存同时失效请求全部转发到 DB DB 可能会压力过重。 当发生大量的缓存穿透例如对某个失效的缓存的高并发访问也会造成缓存雪崩。 解决方法 缓存失效时的雪崩效应对底层系统的冲击非常可怕。遗憾的是这个问题目前并没有很完美的解决方案。 一种常用的方法是用加锁或者队列的方式保证缓存的单线程进程写从而避免失效时大量的并发请求落到底层存储系统上。 另一种方法是合理设计的缓存过期时间将数据失效时间均匀地分布在时间轴上一定程度上能够避免缓存同时失效带来的雪崩效应。例如可以在原有的失效时间基础上增加一个随机值比如1-5分钟随机这样每一个缓存的过期时间的重复率就会降低就很难引发集体失效的事件。 缓存并发问题描述 有时候如果网站并发访问高一个缓存如果失效可能出现多个进程同时查询 DB同时设置缓存的情况如果并发确实很大这也可能造成 DB 压力过大还有缓存频繁更新的问题。 解决方法 常用的解决方法是对缓存查询加锁如果 KEY 不存在就加锁然后查 DB 后写入缓存然后解锁其他进程如果发现有锁就等待然后等解锁后返回数据或者进入 DB 查询。 这种解决方式会造成部分请求等待。 缓存算法缓存算法是指令的一个明细表用于决定缓存系统中哪些数据应该被删去。 缓存需要被清理时比如空间占用已经接近临界值了需要使用某种淘汰算法来决定清理掉哪些数据。常用的淘汰算法有下面几种 FIFOFirst In First Out先进先出。判断被存储的时间离目前最远的数据优先被淘汰。LRULeast Recently Used最近最少使用。判断最近被使用的时间目前最远的数据优先被淘汰。LFULeast Frequently Used最不经常使用。在一段时间内数据被使用次数最少的优先被淘汰。ARC自适应缓存替换算法(ARC) 在IBM Almaden研究中心开发这个缓存算法同时跟踪记录LFU和LRU以及驱逐缓存条目来获得可用缓存的最佳使用。 MRUMost Recently Used最近最常使用算法和 LRU 正好相反。它会移除最近最多被使用的对象。LRU类算法对比由于不同的访问模型导致命中率变化较大此处对比仅基于理论定性分析不做定量分析 对比点对比命中率LRU-2 MQ(2) 2Q LRU复杂度LRU-2 MQ(2) 2Q LRU代价LRU-2 MQ(2) 2Q LRULRULRULeast recently used最近最少使用算法根据数据的历史访问记录来进行淘汰数据其核心思想是“如果数据最近被访问过那么将来被访问的几率也更高”。 实现最常见的实现是使用一个链表保存缓存数据详细算法实现如下 新数据插入到链表头部每当缓存命中即缓存数据被访问则将数据移到链表头部当链表满的时候将链表尾部的数据丢弃。命中率当存在热点数据时LRU的效率很好但偶发性的、周期性的批量操作会导致LRU命中率急剧下降缓存污染情况比较严重。 复杂度实现简单。 代价命中时需要遍历链表找到命中的数据块索引然后需要将数据移到头部。 MySQL的InnoDB引擎设置有索引及数据缓存池其中用到的LRU算法来维持缓存的命中率 LRU-K原理 LRU-K中的K代表最近使用的次数因此LRU可以认为是LRU-1。LRU-K的主要目的是为了解决LRU算法“缓存污染”的问题其核心思想是将“最近使用过1次”的判断标准扩展为“最近使用过K次”。 实现 相比LRULRU-K需要多维护一个队列用于记录所有缓存数据被访问的历史。只有当数据的访问次数达到K次的时候才将数据放入缓存。当需要淘汰数据时LRU-K会淘汰第K次访问时间距当前时间最大的数据。详细实现如下 数据第一次被访问加入到访问历史列表如果数据在访问历史列表里后没有达到K次访问则按照一定规则FIFOLRU淘汰当访问历史队列中的数据访问次数达到K次后将数据索引从历史队列删除将数据移到缓存队列中并缓存此数据缓存队列重新按照时间排序缓存数据队列中被再次访问后重新排序需要淘汰数据时淘汰缓存队列中排在末尾的数据即淘汰“倒数第K次访问离现在最久”的数据。LRU-K具有LRU的优点同时能够避免LRU的缺点实际应用中LRU-2是综合各种因素后最优的选择LRU-3或者更大的K值命中率会高但适应性差需要大量的数据访问才能将历史访问记录清除掉。 命中率LRU-K降低了“缓存污染”带来的问题命中率比LRU要高。 复杂度LRU-K队列是一个优先级队列算法复杂度和代价比较高。 代价由于LRU-K还需要记录那些被访问过、但还没有放入缓存的对象因此内存消耗会比LRU要多当数据量很大的时候内存消耗会比较可观。 LRU-K需要基于时间进行排序可以需要淘汰时再排序也可以即时排序CPU消耗比LRU要高。 参考: 缓存那些事–什么是缓存为什么要用缓存缓存那些事–缓存中常见的问题缓存那些事–分布式缓存缓存、缓存算法和缓存框架简介缓存淘汰算法–LRU算法缓存那些事–常用的缓存失效策略