性能优化-关于缓存的一些思考

本文探讨了缓存引入的原因,介绍了读写性能提升的本地缓存与分布式缓存解决方案,如Guava Cache和Redis。针对缓存Miss,讨论了回收算法与一致性策略,包括cache aside、Read/Write through和Write Back模式,以及它们的适用场景。
摘要由CSDN通过智能技术生成


前言

缓存带来的思考


一、缓存的引入

  • 业务系统初期,数据库可以承担读写压力 应用直接和DB交互
  • 业务量大规模增长,DB查询压力和耗时都在在增长,引入分布式缓存,减少DB压力的同时,提高QPS
  • 分布式缓存 成为性能瓶颈,高频的QPS,缓存驱逐以及网络抖动,都会影响系统稳定性,引入本地缓存 减轻分布式换的压力 减少网络以及序列化开销

二、读写的性能提升

读性能优化:直接命中缓存 通过内存操作 避免磁盘IO 提高吞吐
写性能优化:写操作直接操作内存 让磁盘IO批量处理 顺序落盘

1. 读缓存Cache

  1. 本地缓存
    • Guava:是Google Fuava中的一个内存缓存模块,用于将数据缓存到JVM内存中。
    • Caffeine:高性能的Java缓存库,使用Window TinyLfu清理策略,它提供了接近最佳的命中率。
    • Ehcache:纯Java的进程内缓存框架
    • OHC:全称为 off-heap-cache,即堆外缓存,是一款基于Java 的 key-value 堆外缓存框架。
  2. 分布式缓存
    • Memcached:高性能的服务器内存缓存软件
    • Redis:完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库
  3. 应用
    • 多级缓存:CPU-> 堆 -> 内存

2. 写缓存Buffer

  1. 文件缓存
    - java BufferedWriter:Java语言中的缓冲流。
    - Mysql InnoDB Buffer: Mysql中InnoDB中的缓冲区。
    • Hbase MemStore:Hbase 中的操作缓存区。
  2. 网络缓存
    • SO_RCVBUF , SO_SNDBUF
  3. 应用
    • redis缓冲入账

三丶缓存Miss

缓存需要在有限的容量内 保持热点数据的常住 需要达到性能和成本平衡

1. 回收算法

  1. LRU

    • 如果严格执行LRU 每次遍历全部key 获取最近最少使用的key 去执行淘汰
    • 耗时长 资源消耗大
  2. 近似LRU

    • 通过活跃度 分离出活跃key和待回收key
    • 回收时,关注待回收key既可
    • 回收算法使用链表或者树的结构 使key按空闲时间有序
    • 在缓存读写更新时 辅助回收的数据结构会同步更新 带来存储和计算成本较高
  3. Redis 采用近似LRU实现

    • 随机采样固定key
    • 淘汰掉空闲时间最长的
    • 有一定几率 会淘汰掉最近被访问的key
  4. 避免短期大量失效

    • 避免某个时间节点 大量缓存同时失效 导致流量打到DB 降低系统性能和稳定性
    • 利用随机数 打散缓存失效时间

四丶缓存一致性

1.尽量保证DB和缓存中数据一致性
2.常用 Cache aside 设计模式(更新数据库后,失效缓存)
3.避免使用非常规的缓存设计模式(先更新缓存、后更新DB | 先更新DB、后更新缓存(cache aside是直接失效缓存))

缓存设计模式

1. cache aside

业务系统常用设计模式,优先更新数据库,再失效缓存,缓存中的内容是不做更新操作的,只有写入和删除操作。

缓存污染

  • 过期时间: 设置一个过期时间,短时间内数据不一致。
  • 延迟双删 :主线程失效缓存后,将失效指令放入延时队列,另一个线程轮询队列获取指令并执行。
  • CDC同步:通过canal订阅MySQL binlog的变更,上报给Kafka,系统监听Kafka消息触发缓存失效。
2. Read/Write through

核心策略:以缓存为操作为主,数据存先存在于缓存,缓存的数据是不会过期的。

  • Read Through :先查询缓存中数据是否存在,如果存在则直接返回,如果不存在,则由缓存组件负责从数据库中同步加载数据。
    -Write Through: 先查询要写入的数据在缓存中是否已经存在,如果已经存在,则更新缓存中的数据,并且由缓存组件同步更新到数据库中。如果缓存中数据不存在,我们把这种情况叫做Write Miss(写失效)。
  • Write Miss解决方式
    • Write Allocate(按写分配):做法是写入缓存相应位置,再由缓存组件同步更新到数据库中
    • No- write allocate(不按写分配):做法是不写入缓存中,而是直接更新到数据库中3
适用场景

用于读操作较多.相较于Cache aside而言更适合缓存一致的场景.
使用简单屏蔽了底层数据库的操作,只是操作缓存.
这种方式其实可以以Redis为存储,对数据的持久性要求较低的.

3. Write Back(Write behind)

Write back是相较于Write Through而言的一种异步回写策略,异步写可以减少与物理磁盘存储的交互,也可以进行合并写等优化。

适用场景

用于读少写多的场景
Linux系统的页缓存和MySQL InnoDB 引擎的Cache Pool其实就是使用的WriteBack策略.
相较于Write through 而言拥有更高的写入性能


总结

上述文章记录了一下常用的缓存和缓冲,作为个人见解,不做参考依据,详情请参考官方文档。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值