缓存
缓存 https://xie.infoq.cn/article/0134f29b0c0895df548dd929b?utm_source=rss&utm_medium=article 缓存的存在,是为了调和差异。 差异有多种,比如处理器和存储之间的速度差异、用户对产品的使用体验和服务处理效率的差异等等。 CPU 缓存[2]。为了调和 CPU 和内存之间巨大的速度差异,设置了 L1/L2/L3 三级缓存,离 CPU 越近,速度越快。 Ehcache[3]。是最流行了 Java 缓存框架之一。因为其开源属性,在 spring/Hibernate 等框架上被广泛使用。支持磁盘持久化和堆外内存。缓存功能齐全。 Guava cache。灵感来源于 ConcurrentHashMap,但具有更丰富的元素失效策略,功能没有 ehcache 齐全,如只支持 jvm 内存,但比较轻量简洁。 memcached。[5] memcached 是一个高效的分布式内存 cache,搭建与操作使用都比较简单,整个缓存都是基于内存的,因此响应时间很快,但是没有持久化的能力。 Redis 以优秀的性能和丰富的数据结构,以及稳定性和数据一致性的支持,被业内越来越普遍的使用。 缓存预热 缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候, 先查询数据库, 然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据! 解决思路: 直接写个缓存刷新页面,上线时手工操作下; 数据量不大,可以在项目启动的时候自动进行加载; 定时刷新缓存; 缓存更新 除了缓存服务器自带的缓存失效策略之外 (Redis默认的有6中策略可供选择) ,我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种: 定时去清理过期的缓存; 当有用户请求过来时, 再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。 两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方案,大家可以根据自己的应用场景来权衡。 缓存穿透 Cache Penetration 穿透形象一点就是: 请求过来了 转了一圈 一无所获 就像穿过透明地带一样。 在高并发系统中缓存穿透,如果一个 req 需要请求的 key 在缓存中没有,这时业务线程就会访问磁盘数据库系统,然而磁盘数据库也没有这个 key,无奈业务线程只能返回 null,白白处理一圈。 查询的是数据库中不存在的数据,没有命中缓存而数据库查询为空,也不会更新缓存。导致每次都查库,如果不加处理,遇到恶意攻击,会导致数据库承受巨大压力,直至崩溃。 解决方案 接口层防护(第一道防线) API 限流、防 DDoS 网关黑名单、用户鉴权 参数合法性校验(如 ID 必须 > 0) 缓存空对象 如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),仍然把这个空结果进行缓存,但它的过期时间会很短,不超过 5 分钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓存中获取就有值了,而不会继续访问数据库。当修改或者新增该 key 的数据信息的时候,需要删除或者更新 null 缓存值。 ...