腾讯云Redis混合存储版重磅推出,万字长文助你破解缓存难题!

前言

在 互联网和移动互联网两波浪潮的推动下,存储技术有了飞速发展。 移动互联网用户在过去十年增长了10倍,用户的增长带动了数据量的指数级增长,因为激烈的市场竞争,企业和用户对应用程序的响应性能要求越来越高,在完美应对庞大的用户规模和海量数据集的同时保证优秀的产品体验,是数据库面临的挑战。

在机械硬盘普及的时代,企业需要通过缓存技术加速数据的访问,在SSD存储介质普及后,企业需要缓存技术支撑高并发和大吞吐,通过引入分布式缓存方案,提升应用程序性能,消除数据库热点。

但是 缓存技术的引入增加了业务架构的复杂度,降低了开发效率,同时还面临着缓存一致性、缓存击穿、缓存雪崩等挑战 。腾讯云数据库团队推出的Redis混合存储产品,融合缓存和存储的统一架构,彻底解决了缓存难题,帮助企业的研发人员聚焦业务逻辑,提升生产效率。

缓存的三座大山

1. 缓存一致性

缓存一致性是指业务在引入分布式缓存系统后,业务对数据的更新除了要更新存储以外还需要同时更新缓存,对两个系统进行数据更新就要先解决分布式系统中的隔离性和原子性难题。

目前大多数业务在引入分布式缓存后都是通过牺牲小概率的一致性来保障业务性能,因为要在业务层严格保障数据的一致性,代价非常高,业务引入分布式缓存主要是为了解决性能问题,所以在性能和一致性面前,通常选择牺牲小概率的一致性来保障业务性能。

2. 缓存击穿

缓存击穿是指查询请求没有在缓存层命中而将查询透传到存储DB的问题,当大量的请求发生缓存击穿时,将给存储DB带来极大的访问压力,甚至导致DB过载拒绝服务。 空数据查询(黑客攻击)和缓存污染(网络爬虫)是常见的引发缓存击穿的原因。

什么是空数据查询?空数据查询通常指攻击者伪造大量不存在的数据进行访问(比如不存在的商品信息、用户信息)。

缓存污染通常指在遍历数据等情况下冷数据把热数据驱逐出内存,导致缓存了大量冷数据而热数据被驱逐。缓存污染的场景我们目前还没有发现较好的解决方案,但是在空数据查询问题上我们可以改造业务,通过以下方式防止缓存击穿:

  • 通过bloomfilter记录key是否存在,从而避免无效Key的查询;
  • 在Redis缓存不存在的Key,从而避免无效Key的查询。

3. 缓存雪崩

缓存雪崩是指由于大量的热数据设置了相同或接近的过期时间,导致缓存在某一时刻密集失效,大量请求全部转发到DB,或者是某个冷数据瞬间涌入大量访问,这些查询在缓存MISS后,并发的将请求透传到DB,DB瞬时压力过载从而拒绝服务。

目前常见的预防缓存雪崩的解决方案,主要是通过对key的TTL时间加随机数,打散key的淘汰时间来尽量规避,但是不能彻底规避。

传统分布式缓存方案

在引入分布式缓存后,我们的业务架构由原有两层架构(应用+数据库)变成了三层架构(应用+缓存+存储),缓存层缓存热数据,存储层负责全量数据持久化存储。

存储架构的变化要求业务对数据的存取逻辑进行相应调整,而且这个调整是巨大的。在缓存系统的选择上,常见的缓存数据库包括Memcached、Redis,目前使用最广泛的是Redis,存储数据常见的包括关系型数据库MySQL、PG、Oreacle、SQLServer等,NoSQL数据库MongoDB、Hbase等。

在引入分布式缓存后,业务逻辑需要做三个点的变化,缓存读取、缓存更新、缓存淘汰 。

1. 缓存读取

引入缓存层后,读数据就变得不是那么简单直接了,APP需要先去缓存读取数据,如果缓存MISS(数据没有被缓存),则需要从存储中读取数据,并将数据更新到缓存系统中,整个流程和代码如下所示:

image

<pre language="typescript" code_block="true"># Python
def get_user(user_id):
    # Check the cache
    record = cache.get(user_id)
    if record is None:
        # Run a DB query
        record = db.query("select * from users where id=?",user_id)
        # Populate the cache
        cache.set(user_id, record)
    return record

2. 缓存更新

我们把常见的缓存更新方案总结为两大类,业务层更新和外部组件更新,比较常见的是通过业务更新的方案。

(1)业务层更新缓存

a. 缓存更新的难点

刚开始接触缓存方案的同学可能会纠结几个点,先更新缓存还是先更新存储,缓存的处理是通过删除来实现还是通过更新来实现。

这里我们面临的问题本质上是一个数据库的分布式事务的问题,需要处理数据可靠性的挑战,并发更新带来的隔离性挑战,和数据更新原子性的挑战。

数据可靠性: 如果要保证数据的可靠性,在业务逻辑成功之前,必须保障有一份数据落地,我们有以下两个选择:

  • 先更新成功存储,再更新缓存;
  • 先更新成功缓存,再更新存储,如果存储更新失败,删除缓存。

操作隔离性: 一条数据的更新涉及到存储和缓存两套系统,如果多个线程同时操作一条数据,并且没有方案保证多个操作之间的有序执行,就可能会发生更新顺序错乱导致数据不一致的问题。

更新原子性: 引 入缓存后,我们需要保证缓存和存储要么同时更新成功,要么同时更新失败,否则部分更新成功就会导致缓存和存储数据不一致的问题。

b. 业务层缓存更新方案

我们看到大多数的常见是选择以下方案,保障数据可靠性,尽量减少数据不一致的出现,通过TTL超时机制在一定时间段后自动解决数据不一致现象。

Step1 :更新存储,保证数据可靠性;

Step2 :更新缓存,2个策略怎么选:

  • 惰性更新:删除缓存,等待下次读MISS再缓存(推荐方案);
  • 积极更新:将最新的值更新到缓存(不推荐)。

积极更新策略,缓存数据实时性更高,但是在缓存侧带来了更多的更新操作,这会提高更新冲突导致脏数据概率 。

(2)外部组件更新缓存

a. 缓存MISS处理方案

在通过第三方组件更新的方案中,为了保障数据的一致性,避免对单条数据的并行更新,缓存的所有更新操作都需要交给同步组件,因此缓存MISS场景下的逻辑

image

b. 缓存更新方案

先更新存储,由第三方组件异步更新缓存。 该方案投入较大,只适合特定的场景,并且有以下3个难点:

  • 需要监控存储的日志,或者通过Triger来监控存储数据的变更,需要对存储系统非常熟悉;
  • 需要对更新进行过滤,我们的目的是缓存热数据,但是像DDL、批量更新这一系列的操作是不需要更新缓存的,要把非业务更新操作过滤;
  • 同步组件需要理解数据,不通用。

image

c. 其他缓存更新方案

在实际的生产中,我们还会看到很多先更新缓存,然后通过第三方组件更新存储的场景,但是这个方案也会面临数据一致性和数据可靠性的挑战,虽然不推荐,但是确实还是能看到有在使用这个方案的,我们拿出来探讨下。

  • 这个场景数据可靠性,不及先更新存储的方案,但是写入性能高,延迟低;
  • 这个方案APP和第三方组件都会更新Cache,会存在数据一致性的问题,因为很难保障两个组件更新的时序。

image

3. 缓存淘汰

缓存的作用是将热点数据缓存到内存实现加速,内存的成本要远高于磁盘,因此我们通常仅仅缓存热数据在内存,冷数据需要定期的从内存淘汰,数据的淘汰通常有两种方案:

主动淘汰 :这是推荐的方式,我们通过对Key设置TTL的方式来让Key定期淘汰,以保障冷数据不会长久的占有内存。TTL的策略可以保证冷数据一定被淘汰,但是没有办法保障热数据始终在内存,这个我们在后面会展开;

被动淘汰 :这个是保底方案,并不推荐,Redis提供了一系列的Maxmemory策略来对数据进行驱逐,触发的前提是内存要到达maxmemory(内存使用率100%),在maxmemory的场景下缓存的质量是不可控的,因为每次缓存一个Key都可能需要去淘汰一个Key。

腾讯云Redis混合产品介绍

1. 产品简介

腾讯云Redis混合存储版基于腾讯游戏线上运营多年的Tendis引擎打造。数据自动降冷,落盘压缩,最大可降低成本85%,100% 兼容Redis协议,可助力企业大幅提升生产效率,降低运营成本。

2. 产品特性

(1)研发效率+++

a. 混合存储解决方案

  • 同样的三层架构,业务仅需要访问统一的Redis接口,让企业重新聚焦业务逻辑;
  • 一套系统支撑,避免维护多套系统。

b. 解决缓存三大难题

  • 一致性:通过内聚的涉及,保障缓存和存储一致性
  • 缓存击穿:All Keys In Memory设计,避免缓存击穿;
  • 缓存击穿:动态TTL设计,热数据即持久缓存。

c. 100%兼容Redis协议

  • 100%兼容Redis协议,业务可顺畅接入。

d. 超高读写性能

  • 高写入:为Redis定制的Rcoksdb存储引擎,支持100万并发写入;
  • 高读取:智能热数据缓存方案,提供1000万并发读取。

i

(2)运营成本-85%

a. 数据自动自动降冷

  • 全量数据落盘,热数据缓存内存,相对全内存方案成本-85%;
  • 数据自动降冷,成本可控。

b. 精准缓存

  • 动态TTL淘汰方案,精准缓存热数据,有效避免缓存雪崩;
  • 可控的冷数据缓存策略,快速解决缓存污染问题。

c. 数据压缩

  • Rocksdb独有的数据结构,保障性能和压缩效果平衡;
  • 提供高达3~N倍(统计值)的数据压缩率 。

(3)突破内存限制

a. PB级KV存储解决方案

  • 全量数据存储在磁盘,突破内存的容量限制;
  • 计算&存储分离的存储架构,突破单机磁盘限制。

b. 高扩展性

  • 水平扩展:支持水平扩展分片;
  • 垂直扩展:秒级的垂直扩展存储;
  • 读写分离:缓存层热点数据读写分离。

image

产品架构

Redis混合存储版架构核心组件由Proxy、缓存Redis、存储Tendis组成,其中每个组件的功能介绍如下:

Proxy组件 :负责对客户端请求进行路由分发,将不同的Key的命令分发到正确的分片,同时Proxy还负责了部分监控数据的采集,以及高危命令在线禁用等功能。

缓存Redis :缓存Redis组件源自于Redis 4.0 Cluster,为了支持冷数据自动降冷,我们对Redis进行了Value淘汰、写入数据同步Tendis、冷数据访问、主备热数据同步、按时间淘汰Value等核心功能的改造,改造后的混合存储版100%兼容Redis Cluster命令。

存储Tendis :Tendis是腾讯自研的KV存储引擎,一个兼容Redis协议的Rocksdb存储引擎,该引擎已经在腾讯集团内部运营多年,性能和稳定性得到了充分的验证。在混合存储系统中主要负责全量数据的存储和读取,以及数据备份,增量日志备份等功能。

混合存储带你翻越缓存三座大山

1. 一致性解决方案

(1)并行更新(隔离性)

  • 串行更新:单Key串行更新,保证时序;
  • 并行更新:Slot维度并行更新,提升性能。

(2)部分成功(原子性)

  • 系统联动:缓存&存储实时同步更新状态,通过revision同步状态;
  • 部分成功:缓存更新成功,存储更新失败,触发HA,保障写入成功(日志幂等)。

(3)读一致性

  • revision:每个Key都带有一个revision,通过revision识别数据新旧;
  • 淘汰控制:Redis不淘汰存储未更新的数据(Redis不淘汰revision <4的 数据),保证Redis不缓存旧版本数据。

image

2. 缓存击穿解决方案

(1)空数据查询

缓存所有Key 和 热数据Value,在缓存层拦截空数据查询,避免无效查询透传;

(2)缓存污染

可控的冷数据缓存策略,提供可配置的了冷数据缓存配置,例如业务可以配置在5分钟内访问次数超过3次才缓存在内存,可以有效防御缓存污染。

  • value-cache-policy-period(缓存策略时间窗);
  • value-cache-policy-threhold(value-cache-policy-period 时间窗内触发缓存的访问频率)。

3. 缓存雪崩解决方案

前面介绍到,缓存雪崩主要在两种情况会触发:

第一 :大量热Key同时被淘汰,其中的原因是TTL设置时间接近。Redis混合存储版支持动态TTL,每次对Key的访问都会触发TTL更新,保障热数据持久缓存,有效规避缓存密集淘汰,我们通过两个参数配置来实现动态TTL:

  • value-eviction-policy:设置为time-to-eviction,启用全局动态TTL;
  • value-time-to-eviction:设施动态TTL的时长,取值范围[1h-180d]。

第二 :一个冷Key瞬间产生大量的访问,由于缓存MISS导致大量请求透传到存储层,Redis混合存储版通过合并冷数据缓存的请求,同一个key的请求只访问一次存储层(Ten第三),可以将对存储层的访问降到最低,从而避免存储层过载。

猜你喜欢

转载自blog.csdn.net/weixin_47082274/article/details/106843682