【redis】-- 缓存(redis作为缓存使用)

时间:2021-11-14 20:19:46

目录

redis有两种使用方式一是作为数据库使用,二是作为缓存使用。

将redis作为缓存,当你新增数据时,让它自动地回收旧数据是件很方便的事情。这个行为在开发者社区非常有名,因为它是流行的memcached系统的默认行为。而redis回收数据LRU是redis唯一支持的回收算法。

1.Maxmemory配置指令
maxmemory配置指令用于配置Redis存储数据时指定限制的内存大小。通过redis.conf可以设置该指令,或者之后使用CONFIG SET命令来进行运行时配置。
例如为了配置内存限制为100mb,以下的指令可以放在redis.conf文件中。
maxmemory 100mb
设置maxmemory为0代表没有内存限制。对于64位的系统这是个默认值,对于32位的系统默认内存限制为3GB。
当指定的内存限制大小达到时,需要选择不同的行为,也就是策略。 Redis可以仅仅对命令返回错误,这将使得内存被使用得更多,或者回收一些旧的数据来使得添加数据时可以避免内存限制。

1.redis的回收策略

当maxmemory限制达到的时候Redis会使用的行为由 Redis的maxmemory-policy配置指令来进行配置。

以下的策略是可用的:

  • noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)
  • allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
  • volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
  • allkeys-random: 回收随机的键使得新添加的数据有空间存放。
  • volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
  • volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。

如果没有键满足回收的前提条件的话,策略volatile-lru, volatile-random以及volatile-ttl就和noeviction 差不多了。

选择正确的回收策略是非常重要的,这取决于你的应用的访问模式,不过你可以在运行时进行相关的策略调整,并且监控缓存命中率和没命中的次数,通过RedisINFO命令输出以便调优。

一般的经验规则:

  • 使用allkeys-lru策略:当你希望你的请求符合一个幂定律分布,也就是说,你希望部分的子集元素将比其它其它元素被访问的更多。如果你不确定选择什么,这是个很好的选择。.
  • 使用allkeys-random:如果你是循环访问,所有的键被连续的扫描,或者你希望请求分布正常(所有元素被访问的概率都差不多)。
  • 使用volatile-ttl:如果你想要通过创建缓存对象时设置TTL值,来决定哪些对象应该被过期。

allkeys-lru 和 volatile-random策略对于当你想要单一的实例实现缓存及持久化一些键时很有用。不过一般运行两个实例是解决这个问题的更好方法。

为了键设置过期时间也是需要消耗内存的,所以使用allkeys-lru这种策略更加高效,因为没有必要为键取设置过期时间当内存有压力时。

redis的LRU回收算法

redis的回收算法并非真正的LRU算法,而是依据redis而改造过的算法。Redis为什么不使用真实的LRU实现是因为这需要太多的内存。不过近似的LRU算法对于应用而言应该是等价的。

LRU算法关于redis的具体实现:http://ifeve.com/redis-lru/

2.关于redis作为缓存时出现的击穿,穿透,雪崩问题

1.击穿

缓存击穿:指的是在高并发的情况下(一定要是高并发情况,不然称不上击穿因为访问量低时,击穿不影响效率),在redis中设置的某一个或少量键因为超时被删除,或被回收算法回收不存在时(总之就是键被删除了),突然涌入大量的请求,请求被删除的键键。此时大量的请求穿过redis缓存,之间服务数据库,对数据库造成压力,导致数据库效率降低,或崩溃的情况

【redis】-- 缓存(redis作为缓存使用)

要解决缓存击穿问题,最主要是有多个线程同时服务一个数据造成了,问题的出现,所以要解决缓存击穿问题最好是加锁,让同一时间只有一个数据来访问从而缓解服务器的压力。

redis实现分布式锁:https://www.cnblogs.com/wf614/p/12275028.html

【redis】-- 缓存(redis作为缓存使用)

2.穿透

缓存穿透是指,大量请求请求数据库中不存在,导致请求越过redis缓存直接访问数据库,通过大量的查询操作,使数据库服务器不能正常提供服务的情况。

要解决缓存穿透的问题,那么就要让这些请求到达不了数据库。所以可以在redis中存储所有数据库中的数据信息,让redis阻挡这些请求。

可以使用布隆过滤器(bloom):

布隆过滤器的原理是,当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。

所以,因为布隆过滤器存储数据占用的空间很小,可以先把数据库中的数据都存入布隆过滤器中,然后每次请求都先判断它请求的数据是否存在,如果存在在提供服务,否则就不提供服务。

【redis】-- 缓存(redis作为缓存使用)

如上图所说,因为布隆过滤器判断条件是根据hash算出来的。所以有可能造成误判,使请求不存在数据的请求到达数据库,不过这样的情况出现的可能性很小(>1%),所以可以使用布隆过滤器对数据进行,过滤。

不过布隆过滤器,不能删除数据,当数据库中某些数据被删除时,布隆过滤器中其对应的键还存在,这是也会出现问题。此时可以选用其他和布隆过滤器类似但可以进行更改的过滤器,如布谷鸟过滤器。

3.缓存雪崩

缓存雪崩:是指在某一个时间段因为大量的key到达过期时间,被删除,间接导致大量请求到达数据库的情况。

缓存雪崩和缓存穿透类似都是,因为某种原因导致key失效。不过而在最大的区别是,它们失效key的数量不一样。故不能通过解决穿透的方法来解决缓存雪崩。

要解决缓存雪崩问题,要分为两种情况:

1.失效的数据是时点型数据(时点型数据是指到没有数据的这些数据会失效,而我们不能预测新的数据是什么,即我们知道某些数据会在某个时间点被改变,而我们不知道数据被改变后的具体是什么,而被改变后存在redis缓存中的数据就成了无效数据的情况):这种情况我们可以在业务层添加计时器,到要过期的时间点时延时,在延时的时间里同步数据。

2.失效的不是时点数据而是热数据:我们可以给这些数据设置随机超时时间,使大量数据不在同时过期。

【redis】-- 缓存(redis作为缓存使用)