第11章:缓存设计与优化

第11章:缓存设计与优化

缓存的收益与成本

收益

  • 加速读写
  • 降低后端负载:后端服务器通过前端缓存降低负载,比如业务端使用Redis降低后端MySQL负载

成本

  • 数据不一致:缓存层和数据层有时间窗口不一致,和更新策略有关
  • 代码维护成本:多了一层缓存逻辑
  • 运维成本:比如使用了Redis-Cluster

使用场景

  • 降低后端负载:对高消耗的SQL:join结果集/分组统计结果缓存
  • 加速请求响应:利用Redis/Memcache优化IO响应时间
  • 大量写操作合并为批量写:如计数器先在Redis中累加,再批量写入DB中

缓存的更新策略

  • LRU/LFU/FIFO算法剔除:例如maxmemory-policy
  • 超时剔除:例如expire
  • 主动更新:开发者控制生命周期

三种策略对比:

策略 一致性 维护成本
LRU/LIRS算法剔除 最差
超时剔除 较差
主动更新

两条建议

  • 低一致性:最大内存和淘汰策略
  • 高一致性:超时剔除和主动更新结合:最大内存和淘汰策略兜底

缓存粒度控制

到底是缓存所有的字段还是某些重要的字段

从三个角度来考虑:

  • 通用性:全量属性更好
  • 占用空间:部分属性更好
  • 代码维护:表面上全量属性更好

缓存穿透问题——大量请求不命中

简单说就是大量请求的key不在缓存中,导致请求直接到了数据库上,根本没有经过缓存这一层。

产生的原意

  • 业务代码自身问题
  • 恶意攻击、爬虫等

如何发现

业务的响应时间:当穿透现象发生时,
业务本身的问题:
相关指标:总调用数、缓存层命中数、存储层命中数

解决方法1——缓存空对象

代码

两个问题

  • 需要更多的键——设置过期时间来降低这些风险
  • 缓存层和存储层数据“短期”不一致

解决方法2——布隆过滤器拦截

把所有可能的请求放在布隆过滤器中,当用户请求过来,先判断用户发送的请求是否在布隆过滤器中。不存在的话,直接返回请求参数错误信息给客户端。

一个更详细的图

缓存雪崩问题

无底洞问题

无底洞问题描述

2010年,Facebook有3000个Memcache节点。

发现问题:加机器性能没有提升,反而下降了

无底洞问题关键点

  • 更多的机器 != 更高的性能
  • 批量接口需求(mget、mset等)
  • 数据增长与水平扩展需求

优化IO的几种方法

  • 命令本身优化:例如慢查询keys、hgetall bigkey
  • 减少网络通信次数
  • 降低接入成本:例如客户端长连接/连接池、NIO等

四种优化方案

  • 串行mget
  • 串行IO
  • 并行IO
  • hash_tag

优缺点对比

热点key的重建与优化

问题描述:热点key+较长的重建时间

目标

减少重建缓存的次数

数据尽可能一致

减少潜在危险

解决方案

互斥锁

显然,中间的等待时间还是过多

互斥锁伪代码

永远不过期

  • 缓存层面:没有设置过期时间(没有用expire)
  • 功能层面:为每个value添加逻辑过期时间,但发现超过逻辑过期时间之后,会使用单独的线程去构建缓存

两种方案对比

posted @ 2020-05-27 12:59  scnb  阅读(172)  评论(0)    收藏  举报