数据的使用

数据性质分类

  • 静态数据
    • 一般不变
    • 类似于字典表
  • 准静态数据
    • 变化频率很低
    • 部门结构、行政区划等
  • 中间态数据
    • 计算的可复用的中间态
    • 配置中心的本地副本
  • 动态数据

    • 实时计算

      使用频率分类

  • 热数据

    • 使用频率高
    • 读写比较大,读的频率 >>> 写的频率
  • 温数据
  • 冷数据
  • 冰数据

    缓存无处不在

  • 内存可以看作CPU和磁盘的缓存

  • CPU里也有L1 L2 L3 cache
  • 网络,数据库引擎里的Buffer/Cache都可以看作是缓存
  • GUI的DoubleBuffer双缓冲是一个经典的性能优化方法

    • Vue的虚拟DOM等

      缓存本质

  • 系统各级处理速度不一致

  • 空间换时间

    缓存加载时机

  • 启动时全量缓存

    • 全局有效
    • 使用简单
    • 服务启动时预热
  • 懒加载

    • 同步
      • 业务先看缓存中是否有数据,如果有则直接返回
      • 如果没有则从数据库读取,读取后缓存起来,然后返回
    • 异步加载
      • 业务直接从缓存中取数据,然后直接返回
      • 缓存更新策略
        • 异步策略,如果业务拿到的是空数据,则发起一个异步请求去更新缓存
        • 解耦策略,不管业务调用,由另外一个服务专门进行缓存的更新

          缓存有效性和数据同步

  • 变动频率大、一致性要求高的数据不适合缓存

    • 一致性要求高,意味只有使用原始数据,甚至加了事务,才是保险的
  • 有效性

    • 读写比
      • N:1
      • 对数据的写操作意味着要维护缓存,有更新成本
    • 命中率
      • 90%+
      • 命中缓存意味着数据被使用,即缓存产生价值

        使用不当的问题

  • 系统预热导致服务启动慢

  • 系统内存资源耗尽

    • 只加入数据,不清理旧数据
    • 旧数据处理不及时,不能有效识别无用数据

      本地缓存

      最简单的缓存

  • 问题

    • 并发问题,HashMap不是线程安全的
    • 容量问题,一直put内存会爆
    • 失效问题,如何管理过期失效

HashMap.png

MyBatis/Hibernate框架的Cache

框架Cache.png

GuavaCache

guavaCache.png

SpringCache

SpringCache.png

本地缓存不足

  • 如果缓存在本地,即部署10个服务,就要缓存10份,缓存的读写被放大
  • 缓存数据一般都在堆内内存,总是会影响GC,每次GC都要扫描,但又不能被回收
  • 缓存数据的调度处理,影响执行业务的线程,抢资源

    远程缓存

    Redis/Memcached缓存中间件

  • REmoteDIctionaryServer

  • Memcached

  • 资源有限

    • 思考系统的设计容量、使用容量、峰值是架构设计的常识

      过期策略

  • FIFO/LRU

  • 固定时间过期
  • 业务加权

    常见问题

    缓存穿透

  • 问题

    • 大量并发查询不存在的KEY,导致都直接将压力透传到数据库
    • 如果系统使用的同步加载缓存,缓存不存在时就去查库则可能被利用,查询大量伪造的KEY,造成DDOS
  • 分析
    • 为什么会多次穿透?因为不存在KEY一直为空
    • 需要注意让缓存能够区分KEY不存在还是值就是空值,避免恶性循环
  • 解决

    • 缓存空值的KEY,业务端判断返回
    • Bloom过滤或RoaringBitmap(更精准)判断KEY是否存在
    • 完全以缓存为准,使用延迟异步加载的策略2(解耦),这样业务前端不会触发更新,只有我们数据更新时后端去主动更新

      缓存击穿

  • 问题

    • 当某个KEY失效时,正好有大量并发请求这个KEY
  • 分析
    • 和前面很像,属于比较偶然
  • 解决

    • KEY的更新操作添加全局互斥锁,后续的更新操作会被阻塞
    • 完全以缓存为准,使用延迟异步加载的策略2(解耦),这样就不会触发更新

      缓存雪崩

  • 问题

    • 某一时刻发生大规模的缓存失效,会有大量的请求直接打到数据库,导致数据库压力过大
    • 服务没有滚动发布、定时任务同时启动去更新数据等都会造成雪崩
  • 分析
    • 一般由于更新策略、数据热点、服务宕机等原因导致大规模不可用
    • 需要更新策略要在时间上合适、数据要均匀分布、缓存服务要多台高可用
  • 解决
    • 更新策略在时间上要比较均匀
    • 使用的热点数据尽量分散到不同的机器
    • 多台机器做主从复制或多副本,实现高可用
    • 实现熔断、限流机制,对系统压力进行负载能力控制