ElastiCache for Redis 缓存策略

延迟加载

顾名思义,延迟加载 是一种仅在需要时将数据加载到缓存中的缓存策略。它的工作方式如下所述。

Amazon ElastiCache 是一种内存中键-值存储,位于您的应用程序和其访问的数据存储(数据库)之间。当应用程序请求数据时,它会先向 ElastiCache 缓存发出请求。如果数据在缓存中且最新,则 ElastiCache 会将数据返回到应用程序。如果数据不存在于缓存中或已过期,则应用程序会从数据存储中请求数据。然后,数据存储会将数据返回给应用程序。应用程序接下来将从存储收到的数据写入缓存。这样,下次请求该数据时可以更快速地检索它。

当数据在缓存中且未过期时,会发生缓存命中

  1. 应用程序从缓存中请求数据。
  2. 缓存将数据返回给应用程序。

当数据不在缓存中或已过期时,会发生缓存未命中

  1. 应用程序从缓存中请求数据。
  2. 缓存没有请求的数据,因此返回了 null
  3. 应用程序从数据库中请求并接收数据。
  4. 应用程序使用新数据更新缓存。

下图阐明了这两个过程。

延迟加载的优点和缺点

延迟加载的优点如下:

  • 仅对请求的数据进行缓存。

    由于大部分数据从未被请求,因此延迟加载避免了向缓存中填入未请求的数据。

  • 节点故障对于应用程序而言并不致命。

    当某个节点发生故障并由新的空节点替换时,应用程序将继续运行,但延迟会增加。在对新节点发出请求时,每次缓存未命中都会导致对数据库的查询。同时,将数据副本添加到缓存中,以便从缓存中检索后续请求。

延迟加载的缺点如下:

  • 缓存未命中会导致性能损失。每次缓存未命中都会导致三次往返:

    1. 初次从缓存中请求数据
    2. 查询数据库中的数据
    3. 将数据写入缓存

    这些未命中会导致在数据到达应用程序时出现显著延迟。

  • 过时数据。

    如果仅在存在缓存未命中时将数据写入缓存,则缓存中的数据可能变得陈旧。出现此结果是因为在数据库中更改数据时没有对缓存进行更新。要解决此问题,可以使用 直写 和 添加 TTL 策略。

延迟加载伪代码示例

下面是延迟加载逻辑的伪代码示例。

// *****************************************
// function that returns a customer‘s record.
// Attempts to retrieve the record from the cache.
// If it is retrieved, the record is returned to the application.
// If the record is not retrieved from the cache, it is
//    retrieved from the database,
//    added to the cache, and
//    returned to the application
// *****************************************
get_customer(customer_id)

    customer_record = cache.get(customer_id)
    if (customer_record == null)

        customer_record = db.query("SELECT * FROM Customers WHERE id == {0}", customer_id)
        cache.set(customer_id, customer_record)

    return customer_record

对于此示例,获取数据的应用程序代码如下。

customer_record = get_customer(12345)

直写

直写策略会在将数据写入数据库时在缓存中添加或更新数据。

直写的优点和缺点

直写的优点如下:

  • 缓存中的数据永不过时。

    由于每次将数据写入数据库时都会更新缓存中的数据,因此缓存中的数据始终保持最新。

  • 写入性能损失与读取性能损失。

    每次写入都涉及两次往返:

    1. 对缓存进行写入
    2. 对数据库进行写入

    这将增加流程的延迟。即便如此,与检索数据时的延迟相比,最终用户通常更能容忍更新数据时的延迟。有一个内在的意义,即更新的工作量更大,因而花费的时间会更长。

直写的缺点如下:

  • 缺失的数据。

    如果您启动新节点,无论是由于节点故障还是横向扩展,都会存在缺失数据。在数据库上添加或更新数据之前,这些数据一直缺失。您可以通过实施采用直写的延迟加载来最大限度地减少此情况。

  • 缓存扰动。

    大多数数据永远不会被读取,这是浪费资源。通过添加生存时间 (TTL) 值,您可以最大限度地减少浪费的空间。

直写伪代码示例

下面是直写逻辑的伪代码示例。

// *****************************************
// function that saves a customer‘s record.
// *****************************************
save_customer(customer_id, values)

    customer_record = db.query("UPDATE Customers WHERE id = {0}", customer_id, values)
    cache.set(customer_id, customer_record)
    return success

对于此示例,获取数据的应用程序代码如下。

save_customer(12345,{"address":"123 Main"})

添加 TTL

延迟加载允许过时数据,但不会失败并产生空节点。直写可确保数据始终最新,但可能会失败并产生空节点,并且可能向缓存填充过多的数据。通过为每次写入添加生存时间 (TTL) 值,您可以获得每种策略的优点。同时,您可以在很大程度上避免使用额外数据使缓存混乱。

生存时间 (TTL) 是一个整数值,该值指定密钥过期之前的秒数。Redis 可以为此值指定秒数或毫秒数。当应用程序尝试读取过期的密钥时,会将其视为未找到密钥。查询数据库以获取密钥并更新缓存。此方法不保证值不会过时。但它可以确保数据不会变得太陈旧,并且要求不时从数据库刷新缓存中的值。

有关更多信息,请参阅 Redis set 命令 。

TTL 伪代码示例

下面是利用 TTL 的直写逻辑的伪代码示例。

// *****************************************
// function that saves a customer‘s record.
// The TTL value of 300 means that the record expires
//    300 seconds (5 minutes) after the set command
//    and future reads will have to query the database.
// *****************************************
save_customer(customer_id, values)

    customer_record = db.query("UPDATE Customers WHERE id = {0}", customer_id, values)
    cache.set(customer_id, customer_record, 300)

    return success

下面是利用 TTL 的延迟加载逻辑的伪代码示例。

// *****************************************
// function that returns a customer‘s record.
// Attempts to retrieve the record from the cache.
// If it is retrieved, the record is returned to the application.
// If the record is not retrieved from the cache, it is
//    retrieved from the database,
//    added to the cache, and
//    returned to the application.
// The TTL value of 300 means that the record expires
//    300 seconds (5 minutes) after the set command
//    and subsequent reads will have to query the database.
// *****************************************
get_customer(customer_id)

    customer_record = cache.get(customer_id)

    if (customer_record != null)
        if (customer_record.TTL < 300)
            return customer_record        // return the record and exit function

    // do this only if the record did not exist in the cache OR
    //    the TTL was >= 300, i.e., the record in the cache had expired.
    customer_record = db.query("SELECT * FROM Customers WHERE id = {0}", customer_id)
    cache.set(customer_id, customer_record, 300)  // update the cache
    return customer_record                // return the newly retrieved record and exit function

对于此示例,获取数据的应用程序代码如下。

save_customer(12345,{"address":"123 Main"})
customer_record = get_customer(12345)

原文地址:https://www.cnblogs.com/cloudrivers/p/11634883.html

时间: 2024-07-30 18:59:51

ElastiCache for Redis 缓存策略的相关文章

redis缓存淘汰策略

缓存淘汰策略 介绍 当 Redis 内存超出物理内存限制时,内存的数据会开始和磁盘产生频繁的交换 (swap).交换会让 Redis 的性能急剧下降,对于访问量比较频繁的 Redis 来说,这样龟速的存取效率基本上等于不可用. 在生产环境中我们是不允许 Redis 出现交换行为的,为了限制最大使用内存,Redis 提供了配置参数 maxmemory 来限制内存超出期望大小. 当实际内存超出 maxmemory 时,Redis 提供了几种可选策略 (maxmemory-policy) 来让用户自己

Redis缓存失效策略

一.背景 线上你写代码的时候,想当然的认为写进 redis 的数据就一定会存在,后面导致系统各种 bug,谁来负责? 常见的有两个问题: 往 redis 写入的数据怎么没了? 可能有同学会遇到,在生产环境的 redis 经常会丢掉一些数据,写进去了,过一会儿可能就没了.我的天,同学,你问这个问题就说明 redis 你就没用对啊.redis 是缓存,你给当存储了是吧? 啥叫缓存?用内存当缓存.内存是无限的吗,内存是很宝贵而且是有限的,磁盘是廉价而且是大量的.可能一台机器就几十个 G 的内存,但是可

Redis 缓存 + Spring 的集成示例(转载)

1. 依赖包安装 pom.xml 加入: <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.6.0.RELEASE</version> </dependency> <dependency> <groupId>redis

redis缓存的穿透和雪崩

最近写项目 用到redis,想要把其中的主要问题和大家分享一下: 首先是  穿透 个人的理解因为查询一个不存的数据是,因为第一次查询是到数据库,所以要查询这个不存的数据时会越过redis 直接去数据库查询,所以才会形成穿透: 解决办法: 最常见的是布隆过滤器,将所有的数据哈希到一个足够大的bitmap中,不存在的数据会被bitmap掉, 还有一种方法就是将查询结果不论是不是空都存入缓存,不过将为空的缓存时间减短,不超过5分钟.. 雪崩 是和穿透有很大联系的,在缓存失效的这段时间,发生大量的穿透,

Linux之搭建redis缓存服务器

Linux之搭建redis缓存服务器(nginx+tomcat+redis+mysql实现session会话共享) 一.redis介绍 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set --有序集合)和hash(哈希类型).与memcached一样,为了保证效率,数据都是缓存在内存中.区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写

redis持久化策略梳理及主从环境下的策略调整记录

redis是一个内存数据库,它的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为"半持久化模式"):也可以把每一次数据变化都写入到一个Append Only File(AOF)里面(这称为"完全持久化模式").redis提供了两种不同级别的持久化方式:一种是默认的RDB(filesnapshotting快照)持久化,一种是AOF持久化,这两种持久化方式都可以将内存中的数据库状态保存到磁盘上,但是原理非常不同,区别很明显! 1.RDB持久化可以在

redis缓存mysql

Redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合)和zset(有序集合).这些数据类型都支持push/pop.add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的.在此基础上,redis支持各种不同方式的排序.与memcached一样,为了保证效率,数据都是缓存在内存中.区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且

redis缓存服务器(Nginx+Tomcat+redis+MySQL实现session会话共享)

一.redis介绍 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set --有序集合)和hash(哈希类型).与memcached一样,为了保证效率,数据都是缓存在内存中.区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现master-slave(主从)同步. Redis是一个高性能的key-valu

本地应用缓存算法和缓存策略的介绍

特别声明:该文章是 本人在网上搜索到的一些资料,稍作整理而成的,还望大家不要误会,具体出自于那本人也已经忘记.还请大家不要误会!!!   通过设计良好的数据分块.预取.替换.更新等算法来提高对缓存内容的命中率和一致性. 1)数据分块      Memcached默认情况下采用了名为Slab Allocator的机制分配.管理内存.在该机制出现以前,内存的分配是通过对所有记录简单地进行malloc和free来进行的.但是,这种方式会导致内存碎片,加重操作系统内存管理器的负担,最坏的情况下,会导致操