缓存的理解和使用


=Start=

缘由:

缘于最近看到了一篇不错的文章《如何优雅的使用缓存?》,再加上之前也收藏了一些和缓存介绍相关的文章,所以在此想做个整理,方便以后快速复习、参考。

正文:

参考解答:
# 1. 确认是否需要缓存?
  • 业务逻辑;
  • 实现方式;
  • 性能瓶颈;
# 2. 选择合适的缓存
## 2.1 进程内缓存
ConcurrentHashMap
LRUMap
Guava Cache
## 2.2 分布式缓存
Redis
Memcache
Tair
# 3. 多级缓存
# 3.1 使用进程内缓存
根据 数据量+更新频率 来确定选型
# 3.2 使用Redis做二级缓存
# 4. 缓存更新
# 4.1 先删除缓存,再更新数据库
# 4.2 先更新数据库,再删除缓存(推荐)
# 5. 使用缓存中可能会存在的一些问题
# 5.1 缓存穿透
# 5.2 缓存击穿
# 5.3 缓存雪崩
# X. 缓存的监控
很多人对于缓存的监控也比较忽略,基本上线之后如果不报错然后就默认他就生效了。但是存在这个问题,很多人由于经验不足,有可能设置了不恰当的过期时间,或者不恰当的缓存大小导致缓存命中率不高,让缓存就成为了代码中的一个装饰品。所以对于缓存各种指标的监控,也比较重要,通过其不同的指标数据,我们可以对缓存的参数进行优化,从而让缓存达到最优化。
参考链接:

=END=

,

《 “缓存的理解和使用” 》 有 5 条评论

  1. 缓存的架构设计要点
    https://mp.weixin.qq.com/s/FtPG5das9mV_JLdULNWv7Q
    `
    一、缓存的典型应用场景
    下面的2种情况下,优化存储系统是无法有效提升性能的。

    1. 需要经过复杂运算得出的数据
    例如需要展示有多少用户在线,如果使用数据库,每次都要执行 count 操作,展示量很大的话就对数据库造成了极大压力。

    2. 读多写少的数据
    例如一个明星发布一条微博,可能有几千万人浏览,如果每次浏览都 select 一次的话,几千万的请求对数据库的压力非常大。

    缓存就是为了减轻存储系统的压力,将可重复使用的数据放到内存中,一次生成、多次使用。

    二、设计要点
    缓存虽然为存储系统减负了,但给架构设计带来了复杂性,下面3点需要重点关注:
    1、缓存穿透
    2、缓存雪崩
    3、缓存热点
    `

  2. 爱奇艺实用数据库选型树:不同场景如何快速选择数据库?
    https://asktug.com/t/topic/1396
    `
    作者:郭磊涛,爱奇艺数据库和中间件负责人,TiDB User Group Ambassador。本文系 TUG 北京区 9 月线下活动 “不同业务场景下的数据库技术选型思路” 分享实录。

    我们做选型的时候首先要问:

    谁选型?是负责采购的同学、 DBA 还是业务研发?

    如果选型的是采购的同学,他们更注重成本,包括存储方式、网络需求等。

    如果选型的是 DBA 同学,他们关心的:
    首先是运维成本,包括监控告警是否完善、是否有备份恢复机制、升级和迁移的成本是否高、社区是否稳定、是否方便调优、排障是否简易等;
    其次DBA会关注稳定性,包括是否支持数据多副本、服务高可用、多写多活等;
    第三是性能,包括延迟、QPS 以及是否支持更高级的分级存储功能等;
    第四是扩展性,如果业务的需求不确定,是否容易横向扩展和纵向扩容;最后是安全,需要符合审计要求,不容易出现 SQL 注入或拖库情况。
    除了采购和 DBA之外,后台应用研发的同学同样会关注稳定性、性能、扩展性等问题,同时也非常关注数据库接口是否便于开发,是否便于修改数据库 schema 等问题。

    接下来我们来看一下爱奇艺使用的数据库类型。
    · MySQL, 互联网业务必备系统;
    · TiDB;爱奇艺的 TiDB 实践会有另外的具体介绍;
    · Redis, KV 数据库,互联网公司标配;
    · Couchbase,这个在爱奇艺用的比较多,但国内互联网公司用的比较少,接下来的部分会详细说明;
    · 其他,比如 MongoDB、图数据库、自研 KV 数据库 HiKV 等;
    · 大数据分析相关系统,比如 Hive、Impala 等等。
    `

  3. 响应速度不给力?解锁正确缓存姿势
    https://mp.weixin.qq.com/s/QidAD9OuVdEXFqxRMPx5lQ
    `
    在合理应用缓存前,需要了解缓存领域里相关的几个常用术语:

    1)缓存命中:表示数据能够从缓存中获取,不需要回源;

    2)Cache miss:表示没有命中缓存,如果缓存内存中还有内存空间的话,会将数据加入到缓存中;

    3)存储成本:当没有命中缓存时,回源获取后会将数据放置到存储中,整个将数据放置到存储空间所需要的时间以及空间称之为存储成本;

    4)缓存失效:当源数据发生变更后,意味着缓存中的数据失效;

    5)缓存污染:将不经常访问的数据放置到缓存存储空间中,以至于高频访问的数据无法放置到缓存中;

    6)替代策略:当数据放置到缓存空间时,由于空间不足时,就需要从缓存空间中去除已有的数据,选择去除哪些数据就是由替代策略决定的。常见的替代策略有如下这些:
    Least-Recently-Used(LRU)
    Least-Frequently-Used(LFU)
    SIZE
    First in First Out(FIFO)

    由于存储空间有限,替代策略要解决的核心问题是尽量保留高频访问的缓存数据,降低缓存污染以提升缓存命中率和整体的缓存效率,难点在于,需要基于数据历史访问情况,以一种合适的对未来访问情况的预估才能找到更佳的策略。

    2. 访问缓存场景分析
    使用缓存通常的操作是,请求先访问缓存数据,如果缓存中不存在的话,就会回源到数据库中然后将数据写入到缓存中;如果存在的话就直接返回数据。从整个过程来看,缓存层就处于数据访问的前置环节,分担数据库在高并发容易出现系统故障的风险,所以在使用过程中需要对缓存层很谨慎的进行分析。在访问缓存数据时,有常见的三大场景:缓存穿透、缓存击穿以及缓存雪崩。

    8. 总结
    为了追求高性能,每个开发者最先使用的就是缓存,也在潜意识里将缓存作为了系统性能瓶颈的一剂良药,经过系统化的总结和分析缓存后,就可以发现缓存如果使用不当真的就会事与愿违,成为毒药,并不会系统迭代出那个局部最优解。如果贸然的使用缓存,需要考虑的地方真的很多稍有不注意,反而会让系统投入更多的维护成本,陡增更高的复杂度。那是不是就不使用缓存呢?也不是,缓存在高并发的情况下通过IO高速的缓存获取数据能使得每个请求能够快速响应,并且能够大大提升系统吞吐量以及支撑更高的并发用户数,在现有的高并发大流量的互联网应用中应用缓存的例子太多了,也足以证明缓存在优化系统整体性能是一种行之有效的方案。

    作为开发者不是每个人都有机会和机遇去挑战高并发的互联网架构以及高量级的访问流量和应用规模的,那是不是就意味着这些通用的技术方案就不用深刻分析呢?很显然不是,单从缓存使用中就会发现在高并发下读写带来的数据不一致性分析下来就会有很多并发场景,单线程下都是正常的,但在并发下就会出现很多意想不到的case,而这些分析的思路是最核心的,也是开发者逐渐形成自己的方法论的有效训练途径。在系统化学习每一种技术组件时,业界的通用解决方案都是经过历史经验慢慢沉淀下来的智慧,如同品酒,是需要静下心来好好去品的。

    技术最终是服务于业务价值,而业务规模扩张会反哺技术的创新,要设计出一套适应于业务的合理的技术方案,需要很深的内功,需要既懂技术又要对业务理解十分深刻才行,懂业务而不懂技术,很难知道每种技术方案的局限性,也就是经常所说的PPT架构师,PPT很炫酷,一顿操作猛如虎但是并不是最适合业务的那个解,反而就像是跳梁小丑一样自嗨或者带着功利心去急于变现,只有业务与技术结合能够得到最大价值的那个解就是最合适的方案,需要在优与劣的trade-off上做出权衡。如果很懂技术,但是不懂业务,同样的就是废铜烂铁没办法发挥出功力。在不同的职业生涯阶段,每个人的精力有限,投入技术以及业务的精力分配也是不同的,专注的点会有所不同,就像业务与技术一样,在人生的赛道中在不同阶段也需要迭代出那个最合适的局部最优解,至于什么最合适,答案在每个人心中!
    `

  4. 美团点评万亿级 KV 存储架构演进
    https://mp.weixin.qq.com/s/7K6FYyQiyQUGjHTyjMMgWw
    `
    KV 存储作为美团点评一项重要的在线存储服务,承载了在线服务每天万亿级的请求量,并且保持着 5 个 9 的服务可用性。美团点评高级技术专家齐泽斌在 QCon 全球软件开发大会(上海站)2019 分享了《美团点评万亿级 KV 存储架构与实践》,本文为演讲整理,主要分为四个部分:第一部分是美团点评 KV 存储发展历程;第二部分是内存 KV Squirrel 架构和实践;第三部分是持久化 KV Cellar 架构和实践;最后是关于发展规划和业界新趋势的介绍。

    1. 美团点评 KV 存储发展历程
    2. 内存 KV Squirrel 架构和实践
    3. 持久化 KV Cellar 架构和实践
    4. 发展规划和业界趋势

    最后,一起来看看我们项目的规划和业界的技术趋势。这块我会按照服务、系统、硬件三层来阐述。
    服务层,主要有三点:
    第一,Redis Gossip 协议优化。大家都知道 Gossip 协议在集群的规模变大之后,消息量会剧增,它的 Failover 时间也会变得越来越长。所以当集群规模达到 TB 级后,集群的可用性会受到很大影响,所以我们后面会重点在这方面做一些优化;
    第二,我们已经在 Cellar 存储节点的数据副本间做了 Raft 复制,可以保证数据强一致,后面我们会在 Cellar 的中心点内部也做一个 Raft 复制,这样就不用依赖于 ZooKeeper 做分布式仲裁、元数据存储了,我们的架构也会变得更加简单、可靠;
    第三,Squirrel 和 Cellar 虽然都是 KV 存储,但是因为他们是基于不同的开源项目研发的,所以他们的 API 和访问协议是不同的,我们之后会考虑将 Squirrel 和 Cellar 在 SDK 层做整合,虽然后端会有不同的存储集群,但业务侧是用一套 SDK 访问。

    系统层面,我们正在调研并去落地一些 Kernel Bypass 技术,像 DPDK、SPDK 这种网络和硬盘的用户态 IO 技术。它可以绕过内核,通过轮询机制访问这些设备,可以极大提升系统的 IO 能力。存储作为 IO 密集型服务,性能会获得大幅提升。

    硬件层面,像支持 RDMA 的智能网卡能大幅降低网络延迟和提升吞吐;还有像 3D XPoint 的闪存技术,比如英特尔新发布的 AEP 存储,其访问延迟已经比较接近内存了,以后闪存跟内存之间的界限也会越来越模糊;最后看一下计算型硬件,比如通过在闪存上加 FPGA 卡,把原本应该 CPU 做的工作,像数据压缩、解压等,下沉到卡上执行,这种硬件能在解放 CPU 的同时,还可以降低服务的响应延迟。
    `

  5. 浅谈缓存最终一致性的解决方案
    https://mp.weixin.qq.com/s/Y9S89MT0uAobzRKgYVrI9Q
    `
    根据 CAP 原理,分布式系统在可用性、一致性和分区容错性上无法兼得,通常由于分区容错无法避免,所以一致性和可用性难以同时成立。对于缓存系统来说,如何保证其数据一致性是一个在应用缓存的同时不得不解决的问题。

    需要明确的是,缓存系统的数据一致性通常包括持久化层和缓存层的一致性、以及多级缓存之间的一致性,这里我们仅讨论前者。持久化层和缓存层的一致性问题也通常被称为双写一致性问题,“双写”意为数据既在数据库中保存一份,也在缓存中保存一份。对于一致性来说,包含强一致性和弱一致性,强一致性保证写入后立即可以读取,弱一致性则不保证立即可以读取写入后的值,而是尽可能的保证在经过一定时间后可以读取到,在弱一致性中应用最为广泛的模型则是最终一致性模型,即保证在一定时间之后写入和读取达到一致的状态。对于应用缓存的大部分场景来说,追求的则是最终一致性,少部分对数据一致性要求极高的场景则会追求强一致性。

    2 保证最终一致性的策略( Cache Policy )
    为了达到最终一致性,针对不同的场景,业界逐步形成了下面这几种应用缓存的策略。

    2.1 Cache-Aside
    2.1.1 为什么删除缓存,而不是更新缓存?
    2.1.2 为什么先更新数据库,而不是先删除缓存?
    2.1.3 如果选择先删除缓存,再更新数据库,那如何解决一致性问题呢?
    2.1.4 那么 Cache-Aside 存在数据不一致的可能吗?

    2.2 补偿机制
    2.2.1 删除重试机制
    2.2.2 基于数据库日志( MySQL binlog )增量解析、订阅和消费
    2.2.3 数据传输服务 DTS

    2.3 Read-Through
    Read-Through 意为读穿透模式,它的流程和 Cache-Aside 类似,不同点在于 Read-Through 中多了一个访问控制层,读请求只和该访问控制层进行交互,而背后缓存命中与否的逻辑则由访问控制层与数据源进行交互,业务层的实现会更加简洁,并且对于缓存层及持久化层交互的封装程度更高,更易于移植。

    2.4 Write-Through
    Write-Through 意为直写模式,对于 Write-Through 直写模式来说,它也增加了访问控制层来提供更高程度的封装。不同于 Cache-Aside 的是,Write-Through 直写模式在写请求更新数据库之后,并不会删除缓存,而是更新缓存。

    2.5 Write-Behind
    Write behind 意为异步回写模式,它也具有类似 Read-Through/Write-Through 的访问控制层,不同的是,Write behind 在处理写请求时,只更新缓存而不更新数据库,对于数据库的更新,则是通过批量异步更新的方式进行的,批量写入的时间点可以选在数据库负载较低的时间进行。

    2.6 Write-Around
    如果一些非核心业务,对一致性的要求较弱,可以选择在 cache aside 读模式下增加一个缓存过期时间,在写请求中仅仅更新数据库,不做任何删除或更新缓存的操作,这样,缓存仅能通过过期时间失效。这种方案实现简单,但缓存中的数据和数据库数据一致性较差,往往会造成用户的体验较差,应慎重选择。

    # 总结
    在解决缓存一致性的过程中,有多种途径可以保证缓存的最终一致性,应该根据场景来设计合适的方案,读多写少的场景下,可以选择采用“Cache-Aside 结合消费数据库日志做补偿”的方案,写多的场景下,可以选择采用“ Write-Through 结合分布式锁”的方案 ,写多的极端场景下,可以选择采用“ Write-Behind ” 的方案。
    `

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注