精华内容
下载资源
问答
  • Redis 缓存更新策略

    2020-03-30 18:19:19
    Redis缓存设计 一、缓存的收益与成本 1.1 收益 加速读写:因为缓存通常都是全内存的(例如Redis、Memcache),而存储层通常读写性能不够强悍(例如MySQL),内存读写的速度远远高于磁盘I/O。通过缓存的使用可以...

    Redis缓存设计

    一、缓存的收益与成本

    1.1 收益

    • 加速读写:因为缓存通常都是全内存的(例如Redis、Memcache),而存储层通常读写性能不够强悍(例如MySQL),内存读写的速度远远高于磁盘I/O。通过缓存的使用可以有效地加速读写,优化用户体验。

    • 降低后端负载:帮助后端减少访问量(Mysql设置有最大连接数,如果大量的访问同时达到数据库,而磁盘I/O的速度又很慢,很容易造成最大连接数被使用完,但Redis 理论最大)和复杂计算(例如很复杂的SQL语句),在很大程度降低了后端的负载。

    1.2 成本

    • 数据不一致性:缓存层和存储层的数据存在着一定时间窗口的不一致性,时间窗口跟更新策略有关。

    • 代码维护成本:加入缓存后,需要同时处理缓存层和存储层的逻辑,增大了开发者维护代码的成本。

    • 运维成本:以Redis Cluster为例,加入后无形中增加了运维成本。

    1.3 使用场景

    • 开销大的复杂计算:以MySQL为例子,一些复杂的操作或者计算(例如大量联表操作、一些分组计算),如果不加缓存,不但无法满足高并发量,同时也会给MySQL带来巨大的负担。

    • 加速请求响应:即使查询单条后端数据足够快,那么依然可以使用缓存,以Redis为例子,每秒可以完成数万次读写,并且提供的批量操作可以优化整个IO链的响应时间

    二、缓存更新策略

    2.1 内存溢出淘汰策略

    思考:在生产环境的 redis 经常会丢掉一些数据,写进去了,过一会儿可能就没了。是什么原因?

            Redis 缓存通常都是全内存,内存是很宝贵而且是有限的,磁盘是廉价而且是大量的。可能一台机器就几十个 G 的内存,但是可以有几个 T 的硬盘空间。Redis 主要是基于内存来进行高性能、高并发的读写操作。那既然内存是有限,比如 redis 就只能用 10G,你要是往里面写了 20G 的数据,会咋办?当然会干掉 10G 的数据,然后就保留 10G 的数据了。那干掉哪些数据?保留哪些数据?当然是干掉不常用的数据,保留常用的数据了。数据明明过期了,怎么还占用着内存?这是由 redis 的过期策略来决定。

            在Redis中,当所用内存达到maxmemory上限(used_memory>maxmemory)时会触发相应的溢出控制策略。具体策略受maxmemory-policy参数控制。

    Redis支持6种策略:

    • noeviction:默认策略,不会删除任何数据,拒绝所有写入操作并返回客户端错误信息(error)OOM command not allowed when used memory,此时Redis只响应读操作
    • volatile-lru:根据LRU算法删除设置了超时属性(expire)的键,直到腾出足够空间为止。如果没有可删除的键对象,回退到noeviction策略
    • volatile-random:随机删除过期键,直到腾出足够空间为止
    • allkeys-lru:根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止
    • allkeys-random:随机删除所有键,直到腾出足够空间为止(不推荐)
    • volatile-ttl:根据键值对象的ttl(剩余时间(time to live,TTL) )属性,删除最近将要过期数据。如果没有,回退到noeviction策略

            LRU :Least Recently Used ,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。       

            内存溢出控制策略可以采用config set maxmemory-policy{policy}动态配置。写命令导致当内存溢出时会频繁执行回收内存成本很高,在主从复制架构中,回收内存操作对应的删除命令会同步到从节点来,来保障主从节点数据一致性,从而导致写放大的问题。

    2.2 过期策略

    Redis 服务端采用的 过期策略是 : 惰性删除 + 定期删除

    惰性删除: 

           Redis的每个库都有一个过期字典,过期字典中保存所有key的过期时间。当客户端读取一个key时会先到过期字典内查询key是否已经过期,如果key已经超过,会执行删除操作并返回空。这种策略是出于节省CPU成本考虑,但是单独用这种方式存在内存泄露的问题,当过期键一直没有访问将无法得到及时删除,从而导致内存不能及时释放。

    定时删除:

            Redis内部维护一个定时任务,默认每秒运行10次过期扫描(通过 redis.conf 中通过 hz 配置 修改运行次数),扫描并不是遍历过期字典中的所有键,而是采用了自适应算法,根据键的过期比例、使用快慢两种速率模式回收键:

    1. 从过期字典中随机取出 20 个键
    2. 删除这 20 个键中过期的键
    3. 如果过期键的比例超过 25% ,重复步骤 1 和 2

           为了保证扫描不会出现循环过度,一直在执行定时删除定时任务无法对外提供服务,导致线程卡死现象,还增加了扫描时间的上限,默认是 25 毫秒(即默认在慢模式下,25毫秒还未执行完,切换为块模式,模式下超时时间为1毫秒且2秒内只能运行1次,当慢模式执行完毕正常退出,会重新切回快模式)

    三、应用方更新

    1. 应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。
    2. 先删除缓存,再更新数据库:这个操作有一个比较大的问题,更新数据的请求在对缓存删除完之后,又收到一个读请求,这个时候由于缓存被删除所以直接会读库,读操作的数据是老的并且会被加载进入缓存当中,后续读请求全部访问的老数据。
    3. 先更新数据库,再删除缓存(推荐)为什么不是写完数据库后更新缓存?主要是怕两个并发的写操作导致脏数据。

    四、缓存粒度

    1  通用性

           缓存全部数据比部分数据更加通用,但从实际经验看,很长时间内应用只需要几个重要的属性。

    2 占用空间

          缓存全部数据要比部分数据占用更多的空间,存在以下问题:

    • 全部数据会造成内存的浪费。
    • 全部数据可能每次传输产生的网络流量会比较大,耗时相对较大,在极端情况下会阻塞网络。
    • 全部数据的序列化和反序列化的CPU开销更大。

    3 代码维护

        全部数据的优势更加明显,而部分数据一旦要加新字段需要修改业务代码,而且修改后通常还需要刷新缓存数据。

    展开全文
  • redis缓存更新策略

    2020-03-04 18:47:34
    Redis缓存设计原则 只应将热数据放到缓存中 所有缓存信息都应设置过期时间 缓存过期时间应当分散以避免集中过期 缓存key应具备可读性 应避免不同业务出现同名缓存key 可对key进行适当的缩写以节省内存空间 ...
    Redis的缓存设计原则
    只应将热数据放到缓存中
    所有缓存信息都应设置过期时间
    缓存过期时间应当分散以避免集中过期
    缓存key应具备可读性
    应避免不同业务出现同名缓存key
    可对key进行适当的缩写以节省内存空间
    选择合适的数据结构
    确保写入缓存中的数据是完整且正确的
    避免使用耗时较长的操作命令,Redis默认配置中操作耗时超过10ms即视为慢查询
    一个key对应的数据不应过大:对于string类型,一个key对应的value大小应控制在10K以内,1K左右更优;hash类型,不应超过5000行
    数据库中未查询到的数据,可在Redis中设置特殊标识,以避免因缓存中无数据而导致每次请求均达到数据库
    缓存应有降级处理方案,缓存出了问题要能回源到数据库进行处理
    对于上线后可能会有大量读请求的应用,在上线之前可预先将数据写入缓存中
    读的顺序是先缓存,后数据库;写的顺序是先数据库,后缓存
    数据源发生变更时可能导致缓存中数据与数据源中数据不一致,应根据实际业务需求来选择适当的缓存更新策略:
        主动更新:在数据源发生变更时同步更新缓存数据或将缓存数据过期。一致性高,维护成本较高。
        被动删除:根据缓存设置的过期时间有Redis负责数据的过期删除。一致性较低,维护成本较低。
     

     

    key过期清除(超时剔除)策略
    惰性过期(类比懒加载,这是懒过期):只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。

     

    定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。

     

    (expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。)

     

    问:比如这么个场景,我设计了很多key,过期时间是5分钟,当前内存占用率是50%。但是5分钟到了,内存占用率还是很高,请问为什么?

     

    Redis中同时使用了惰性过期和定期过期两种过期策略,即使过期时间到了,但是有部分并没有真正删除,等待惰性删除。

     

    为什么有定期还要有惰性呢?比如10万个key就要过期了,Redis默认是100ms检查一波。如果他检查出10万个即将要清除,那他接下来的时间基本都是在干这些清空内存的事了,那肯定影响性能,所以他只会部分删除,剩下的等惰性删除
     
    Redis的内存淘汰策略
      Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据。

     

      noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。

     

      allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。

     

      allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。

     

      volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。

     

      volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。

     

      volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
    展开全文
  • Redis缓存更新策略

    2020-10-30 23:26:25
    注意,我们的更新是先更新数据库,成功后,让缓存失效。那么,这种方式是否可以没有文章前面提到过的那个问题呢?我们可以脑补一下。 一个是查询操作,一个是更新操作的并发,首先,没有了删除cache

    一、Cache Aside Pattern

    这是最常用最常用的pattern了。其具体逻辑如下: (推荐学习:Redis视频教程)

    失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。

    命中:应用程序从cache中取数据,取到后返回。

    更新:先把数据存到数据库中,成功后,再让缓存失效。
    注意,我们的更新是先更新数据库,成功后,让缓存失效。那么,这种方式是否可以没有文章前面提到过的那个问题呢?我们可以脑补一下。

    一个是查询操作,一个是更新操作的并发,首先,没有了删除cache数据的操作了,而是先更新了数据库中的数据,此时,缓存依然有效,所以,并发的查询操作拿的是没有更新的数据。

    但是,更新操作马上让缓存的失效了,后续的查询操作再把数据从数据库中拉出来。而不会像文章开头的那个逻辑产生的问题,后续的查询操作一直都在取老的数据。

    转载自:
    https://www.php.cn/redis/436675.html
    图1

    二、

    转载:Redis使用总结(二、缓存和数据库双写一致性问题)
    https://blog.csdn.net/hukaijun/article/details/81010475

    展开全文
  • redis缓存更新策略先删除缓存,后修改数据库先修改数据库,后删除缓存延迟双删内存队列第三方队列 先删除缓存,后修改数据库 这个方案显然是有问题的,不推荐使用。 两个并发的读写操作: 一个写的操作先进来,把...

    先删除缓存,后修改数据库

    这个方案显然是有问题的,不推荐使用。
    两个并发的读写操作:

    1. 一个写的操作先进来,把缓存删除了;
    2. 在写操作还没有更新数据库的时候,一个读的请求又进来了,发现没有命中缓存,就去数据库把老数据取出来了;
    3. 写操作更新了数据库;
    4. 读操作把老数据放在了缓存中。

    这样,数据库中的数据和缓存中的数据就不一致了

    在这里插入图片描述
    这个方案显然不行,在此场景下能保持数据一致?
    让我们设想下这样的场景:一个写的请求进来,删除缓存,这个时候,Redis服务器突然出问题了,或者网络突然出问题了,导致删除缓存失败,抛出了一个异常,导致程序没有继续执行修改数据库的操作。从数据库、缓存一致性的角度来说,这里很好的保证了数据库、缓存的一致性,两者保存的数据是一样的,尽管保存的都是老数据。

    先修改数据库,后删除缓存

    (推荐使用)
    在没有缓存的情况下,两个并发的读写操作:

    1. 读操作先进来,发现没有缓存,去数据库中读数据,这个时候因为某种原因卡了,没有及时把数据放入缓存;
    2. 写的操作进来了,修改了数据库,删除了缓存;
    3. 读操作恢复,把老数据写进了缓存。

    在这里插入图片描述
    这样就造成了数据库、缓存不一致,不过,这个概率出现的非常低,因为这需要在没有缓存的情况下,有读写的并发操作,在一般情况下,写数据库的操作要比读数据库操作慢得多,在这种情况下,还要保证读操作写缓存晚于写操作删除缓存才会出现这个问题,所以这个问题应该可以忽略不计。

    说了这么多,并没有看到先修改数据库,后删除缓存的致命问题啊,别急,让我们继续设想这样的场景:一个写的操作进来,修改了数据库,但是删除缓存的时候 ,由于Redis服务器出现问题了,或者网络出现问题了,导致删除缓存失败,这样数据库保存的是新数据,但是缓存里面的数据还是老数据,妥妥的数据库、缓存不一致啊。

    延迟双删

    可以看到修改数据库,后删除缓存有两个问题,虽然两个问题都是低概率的,所以第三种方案出现了:延迟双删。
    延迟双删就是先删除缓存,后修改数据库,最后延迟一定时间,再次删除缓存。
    在这里插入图片描述
    这么做就可以在一定程度上缓解上述两个问题,第一次删除缓存相当于检测下缓存服务是否可用,网络是否有问题,第二次延迟一定时间,再次删除缓存,是因为要保证读的请求在写的请求之前完成。
    但是这么做,还是有一定问题,比如第一次删除缓存是成功的,第二次删除缓存才失败,又该怎么办?

    内存队列

    上面三种方式,都有一定的问题:

    • 修改数据库、删除缓存这两个操作耦合在了一起,没有很好的做到单一职责;
    • 如果写操作比较频繁,可能会对Redis造成一定的压力;
    • 如果删除缓存失败,该怎么办?

    为了解决上面三个问题,第四种方式出现了:内存队列删除缓存:写操作只是修改数据库,然后把数据的Id放在内存队列里面,后台会有一个线程消费内存队列里面的数据,删除缓存,如果缓存删除失败,可以重试多次。

    在这里插入图片描述

    这样,就把修改数据库和删除缓存两个操作解耦了,如果删除缓存失败,也可以多次尝试。由于后台有一个线程去消费内存队列去删除缓存,不是直接删除缓存,所以修改数据库和删除缓存之间产生了一定的延迟,这延迟应该可以保证读操作已经执行完毕了。
    但是这么做也有不好的地方:

    • 程序复杂度成倍上升,需要维护线程、队列以及消费者;
    • 如果写操作非常频繁,队列的数据比较多,可能消费会比较慢,修改数据库后,间隔了一定的时间,缓存才被删除。

    第三方队列

    如RabbitMQ,Kafka

    方案一:
    在这里插入图片描述
    流程如下所示:
    (1)更新数据库数据;
    (2)缓存因为种种问题删除失败
    (3)将需要删除的key发送至消息队列
    (4)自己消费消息,获得需要删除的key
    (5)继续重试删除操作,直到成功

    该方案有一个缺点,对业务线代码造成大量的侵入。于是有了方案二,在方案二中,启动一个订阅程序去订阅数据库的binlog,获得需要操作的数据。在应用程序中,另起一段程序,获得这个订阅程序传来的信息,进行删除缓存操作。
    在这里插入图片描述
    流程如下图所示:
    (1)更新数据库数据
    (2)数据库会将操作信息写入binlog日志当中
    (3)订阅程序提取出所需要的数据以及key
    (4)另起一段非业务代码,获得该信息
    (5)尝试删除缓存操作,发现删除失败
    (6)将这些信息发送至消息队列
    (7)重新从消息队列中获得该数据,重试操作。

    备注说明:上述的订阅binlog程序在mysql中有现成的中间件叫canal,可以完成订阅binlog日志的功能。另外,重试机制,采用的是消息队列的方式。如果对一致性要求不是很高,直接在程序中另起一个线程,每隔一段时间去重试即可。

    展开全文
  • 目录1、缓存的优势2、缓存更新的Pattern3、缓存的有效性 首先声明,我不一定能讲好这个章节,所以本章节仅供你的参考。缓存是一个微服务设计时必须涉及的领域,然而我自己的微服务涉及的缓存封装比较低级,因此造成...
  • redis缓存更新分为:内存溢出淘汰策略、过期删除策略、应用方更新 一、内存溢出淘汰策略 当redis所用内存达到maxmemory时(use_memory>maxmemory),会触发相应的溢出控制策略,具体策略可配 根据LRU算法删除...
  • 首先下载redis_fdw,这里要注意下载的版本。(https://github.com/pg-redis-fdw/redis_fdw) 一开始,我下载了REL9_4_STABLE_pre2.8版本,安装成功后只能进行查询,不能增删改,联系上德哥后才知道未开发写接口,...
  • redis缓存更新、过期策略

    千次阅读 2019-06-02 10:55:46
    缓存过期策略redis是单线程,收割时间也会占用线程处理时间,如果收割过于频繁,会导致读写出现卡顿 1、主库过期策略: 1.1、定时扫描 首先将每个设置了过期时间的key放到一个独立的hash中,默认每秒定时遍历这个...
  • Redis更新缓存策略

    万次阅读 2017-12-08 09:27:38
    1、缓存【失效】:客户端请求数据先从缓存中查询,如果没有再查询数据库,最后将数据放入缓存 ...4、为什么不采取更新后删除缓存策略?  防止并发写操作导致脏数据 5、为什么不删除缓存后再更新数据库?  
  • Redis缓存过期,更新策略

    千次阅读 2018-04-08 21:56:49
    Redis缓存过期,更新策略 这是Redis系列第三篇,前两篇分别是 1. Linux(Ubuntu16.04)下redis的安装,helloworld及读懂配置文件 https://blog.csdn.net/qq_36521579/article/details/796850974 2. Redis集群...
  • Redis缓存更新策略

    2020-01-21 23:51:07
    使用场景: 超时剔除通过给缓存数据设置过期时间, 让其在过期时间后自动删除, 例如Redis提供的expire命令。 如果业务可以容忍一段时间内, 缓存层数据和存储层数据不一致, 那么可以为其设置过期时间。 在数据...
  • 使用redis 缓存策略

    2020-12-28 16:08:11
    更新数据时:先更新数据库,再删除redis中数据。 //使用redis 缓存 //1.优先从缓冲中取值 public User getCache(int userId){ String redisKey = RedisKeyUtils.getUserKey(userId); User user = (User) ...
  • redis 缓存更新机制

    千次阅读 2020-04-05 14:11:53
    也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存。因此,接下来讨论的思路不依赖于给缓存设置过期时间这个方案。 在这里,我们讨论三种更新...
  • Redis 缓存更新一致性

    2020-05-14 10:08:46
    在设计更新策略时,我们需要考虑多个方面的问题: 对系统吞吐量的影响:比如更新缓存策略产生的数据库负载小于删除缓存策略的负载 并发安全性:并发读写时某些异常操作顺序可能造成数据不一致,如缓存中长期...
  • redis 缓存更新一致性

    2020-05-14 13:10:01
    在设计更新策略时,我们需要考虑多个方面的问题: 对系统吞吐量的影响:比如更新缓存策略产生的数据库负载小于删除缓存策略的负载 并发安全性:并发读写时某些异常操作顺序可能造成数据不一致,如缓存中长期保存过时...
  • 缓存背景 对于大面积的QPS请求 ,传统的数据库的读写分离已经无法满足。当数据库的最大连接数 都达到峰值,这时候如果只是一味的加数据的DB机器 也许可以缓解一下DB压力。但是数据库机器一般都比较贵,从经济成本...
  • 下面会介绍缓存使用技巧和设计方案,包含如下内容:缓存的收益和成本分析、缓存更新策略的选择和使用场景、缓存粒度控制法、穿透问题优化、无底洞问题优化、雪崩问题优化、热点key重建优化。 缓存的收益和成本分析 ...
  • redis缓存策略小结

    2019-01-04 09:48:27
    比较常用的缓存策略,同样这也是facebook的缓存策略:  1. 读:应用程序从cache中取数据,取到后返回。  2. 读:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后...比如(1)“先更新redis,然后...
  • 每当系统数据更新时,保持缓存和数据源(如 MySQL 数据库)同步至关重要,当然,这也取决于系统本身的要求,看系统是否允许一定的数据延迟。 最常见的几种缓存策略、它们的优缺点以及使用场景,分别是: Cache-...
  • 文章目录1、缓存的收益与成本1.1、受益1.2、成本1.3、使用场景2、缓存更新策略3、双写一致性(redis和mysql数据同步方案)4、缓存粒度控制5、缓存穿透,缓存击穿,缓存雪崩 1、缓存的收益与成本 1.1、受益 1、加速读写...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 526
精华内容 210
关键字:

redis缓存更新策略

redis 订阅