Redis冷热数据识别与交换怎么实现

背景

Redis混合存储产品是阿里云自主研发的完全兼容Redis协议和特性的混合存储产品。

通过将部分冷数据存储到磁盘,在保证绝大部分访问性能不下降的基础上,大大降低了用户成本并突破了内存对Redis单实例数据量的限制。

Redis如何实现冷热数据识别与交换

其中,对冷热数据的识别和交换是混合存储产品性能的关键因素。

冷热数据定义

在Redis混合存储中,内存和磁盘的比例是用户可以自由选择的:

Redis混合存储实例将所有的Key都认为是热数据,以少量的内存为代价保证所有Key的访问请求的性能是高效且一致的。而对于Value部分,在内存不足的情况下,实例本身会根据最近访问时间,访问频度,Value大小等维度选取出部分value作为冷数据后台异步存储到磁盘上直到内存小于制定阈值为止。

在Redis混合存储实例中,我们将所有的Key都认为是热数据保存在内存中是出于以下两点考虑:

  • Key的访问频度比Value要高很多。

  • 作为KV数据库,通常的访问请求都需要先查找Key确认Key是否存在,而要确认一个key不存在,就需要以某种形式检查所有Key的集合。保留所有键值对于内存中的数据结构来说,能够保证与纯内存数据结构的查找速度完全一致。

  • Key的大小占比很低。

  • 在一般的业务模型中,即使是普通字符串类型,其Value一般比Key大几倍。而对于Set,List,Hash等集合对象,所有成员加起来组成的Value更是比Key大了好几个数量级。

  • 因此,Redis混合存储实例的适用场景主要有以下两种:

  • 数据访问不均匀,存在热点数据;

  • 内存不足以放下所有数据,且Value较大(相对于Key而言)

  • 冷热数据识别

    当内存不足时的情况下,实例会按照最近访问时间,访问频度,value大小等维度计算出value的权重,将权重最低的value存储到磁盘上并从内存中删除。

    伪代码如下:

    在最理想的情况下,我们会希望能够精准地计算出当前最低的值。然而,value的冷热程度根据访问情况动态变化的,每次都重新计算所有value的冷热权重的时间消耗是完全不可接受的。

    Redis本身在内存满的情况下会根据用户设置的淘汰策略淘汰数据,而热数据从内存写到磁盘也可以认为是一种“淘汰”的过程。从性能,准确率以及用户理解程度考虑,我们在冷热数据识别时采用和Redis类似的近似计算方法,支持多种策略, 通过随机采样小部分数据来降低CPU和内存消耗,通过eviction pool利用采样历史信息来辅助提高准确率。

    Redis的近似淘汰算法命中率的示意图在不同版本和不同采样样本数目的配置下被展示。被淘汰的数据点呈浅灰色,未淘汰的数据点呈灰色,而测试过程中新增的数据点则为绿色。

    冷热数据交换

    Redis混合存储在冷热数据交换过程在后台IO线程中完成。

    热数据->
    冷数据

    异步方式:

  • 主线程在内存接近最大值时,生成一系列数据换出任务;

  • 后台线程执行这些数据换出任务,执行完毕之后通知主线程;

  • 主线程更新释放内存中的value,更新内存中数据字典中的value为一个简单的元信息;

  • 同步方式:

  • 当写入的流量过大,异步方式无法及时将数据换出,可能会导致内存超出最大规格。主线程将直接执行数据换出任务,达到变相限流的目的。

    冷数据->
    热数据

    异步方式:

  • 主线程在执行命令前,先判断命令涉及的value是否都在内存中;

  • 如果不是,生成数据加载任务,挂起该客户端,主线程继续处理其他客户端请求;

  • 后台线程执行数据加载任务,执行完毕后通知主线程;

  • 主线程在内存中更新数据字典中的value,唤醒之前挂起的客户端,处理其请求。

  • 同步方式:

  • 在Lua脚本,具体命令执行阶段,如果发现有value存储在磁盘上,主线程将直接执行数据加载任务,保证Lua脚本和命令的语义不变。



    Redis是一款高性能的内存KV存储系统,它支持各种数据结构,如String、Hash、List、Set等。随着业务的增长,Redis中的数据也不断增长,这就会带来问题,如何识别这些数据中哪些是热数据,哪些是冷数据,如何将热数据存储在内存中,而将冷数据存储在磁盘上以节约内存呢?
    一、Redis如何识别数据热度?
    Redis中提供了不少识别数据热度的手段:
    1. TTL:通过设置键的过期时间,从而让 Redis 自动删除过期的键,业务对于键的访问都将会被计入其使用频率,从而得以识别一个键的热度。
    2. 计数器:在适当的时候,扫描 Redis 中所有的键值,并将其访问频率写入一个计数器中,从而得出热点键。
    3. 持久化:通过开启 Redis 定期持久化或者 AOF 持久化功能,将数据持久化到硬盘上。通过分析持久化文件中键的访问频率和时间,可以得到键的热度。
    二、Redis如何实现冷热数据交换?
    由于 Redis 将所有数据存储在内存中,因此内存的容量限制了 Redis 能够存储的数据量。当 Redis 中的数据量超过了内存容量时,就需要将数据从内存中换出,存储到磁盘中以节约内存。
    1. Redis提供了两种方式来实现冷热数据交换
    (1)主动方式:开发人员可以通过 Redis 提供的 API,手动将热数据从内存中换出,放入磁盘中,并将冷数据从磁盘中换入内存中。
    (2)被动方式:当 Redis 内存不足时,Redis 会自动将一部分冷数据换出到磁盘中,将内存腾出来存储热数据。被动交换本质等同于 LRU(Least Recently Used) 算法,其会自动淘汰很久没有被访问的键值,将其转移到磁盘中。
    2. Redis如何判断数据是否热数据?
    为了避免频繁地将冷数据换出到磁盘中,而热数据经常需要被访问,从而需要频繁将热数据从磁盘中换入内存中。因此,Redis 提供了多种方法来判断一个数据是否是热数据,以此决定何时将它从内存中换出。
    (1)TTL:Redis 中 TTL 的操作具有实时性,可以直接计算键值多久没有访问了。
    (2)LRU:LRU 也是 Redis 内部使用的一种算法,用于判断数据的热度。如果我们将 Redis 中某个键值访问的时间戳存储在一个 set 中,那么对于一个键值,我们可以直接通过该键在 set 中最早访问的时间戳判断其热度。
    (3)计数器:使用频率也可以用计数器来判断一个键值是否热点。
    总结
    通过 TTL、计数器、持久化等方式来识别数据热度,并通过换出机制来实现内存和磁盘的数据交换,Redis 可以更好地利用内存和硬盘资源,提升系统的稳定性和性能。在具体的业务场景中,可以结合自身需求来选择合适的冷热数据判断方式,以此来实现更有效的数据存储和管理。