Redis缓存的学习

Redis缓存的学习

每日思考问题

1、redis是内存数据库,如果内存满了如何处理?

2、redis是否是线程安全的数据库?
	
3、redis的哈希槽,你是如何理解的?(redis的数据是如何存储的?)

4、redis缓存穿透、redis缓存击穿、redis缓存雪崩如何理解?

1、redis是内存数据库,如果内存满了如何处理?

解决方案:
	方案一:集群--增加服务器
	分析:
		① 一定程度上可以解决内存不够的情况
		② 但随着网站用户的人数不断提升,用户产生数据也会不断增加
		③  成本问题 服务器越多并不意味着性能的提升
	方案二:内存淘汰策略----最近不使用的数据从内存中淘汰
	分析:redis.conf配置内存淘汰策略
		① maxmemory 0 		表示使用所有内存
		② maxmemory-policy allkeys-lru		优先移除最近没有使用的key
------------------------------------------------------------------------------
Redis的内存淘汰策略
	Redis内存淘汰指的是用户存储的一些键被可以被Redis主动地从实例中删除,
	从而产生读miss的情况,那么Redis为什么要有这种功能?			
		Redis最常见的两种应用场景为缓存和持久存储,
		首先要明确的一个问题是内存淘汰策略更适合于那种场景?是持久存储还是缓存?	
	内存的淘汰机制的初衷是为了更好地使用内存,用一定的缓存miss来换取内存的使用效率。
	
作为Redis用户,我如何使用Redis提供的这个特性呢?看看下面配置
	# maxmemory <bytes>
	我们可以通过配置redis.conf中的maxmemory这个值来开启内存淘汰功能,
	至于这个值有什么意义,我们可以通过了解内存淘汰的过程来理解它的意义:
	1. 客户端发起了需要申请更多内存的命令(如set)。

	2. Redis检查内存使用情况,如果已使用的内存大于maxmemory则开始根据用户配置的不同淘汰策略来淘汰内存(key),从而换取一定的内存。
 
	3.  如果上面都没问题,则这个命令执行成功。
 
		maxmemory为0的时候表示我们对Redis的内存使用没有限制。
 
Redis提供了下面几种淘汰策略供用户选择,其中默认的策略为noeviction策略:
 
·         noeviction:当内存使用达到阈值的时候,所有引起申请内存的命令会报错。
 
·         allkeys-lru:在主键空间中,优先移除最近未使用的key。
 
·         volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key。
 
·         allkeys-random:在主键空间中,随机移除某个key。
 
·         volatile-random:在设置了过期时间的键空间中,随机移除某个key。
 
·         volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。
 
这里补充一下主键空间和设置了过期时间的键空间,
举个例子,假设我们有一批键存储在Redis中,则有那么一个哈希表用于存储这批键及其值,如果这批键中有一部分设置了过期时间,那么这批键还会被存储到另外一个哈希表中,这个哈希表中的值对应的是键被设置的过期时间。设置了过期时间的键空间为主键空间的子集。

我们了解了Redis大概提供了这么几种淘汰策略,那么如何选择呢?淘汰策略的选择可以通过下面的配置指定:
 
	# maxmemory-policy noeviction
 
	但是这个值填什么呢?
	为解决这个问题,我们需要了解我们的应用请求对于Redis中存储的数据集的访问方式以及我们的诉求是什么。
	同时Redis也支持Runtime修改淘汰策略,这使得我们不需要重启Redis实例而实时的调整内存淘汰策略。
 
下面看看几种策略的适用场景:
 
·         allkeys-lru:如果我们的应用对缓存的访问符合幂律分布(也就是存在相对热点数据),或者我们不太清楚我们应用的缓存访问分布状况,我们可以选择allkeys-lru策略。
 
·         allkeys-random:如果我们的应用对于缓存key的访问概率相等,则可以使用这个策略。
 
·         volatile-ttl:这种策略使得我们可以向Redis提示哪些key更适合被eviction。
 
另外,volatile-lru策略和volatile-random策略适合我们将一个Redis实例既应用于缓存和又应用于持久化存储的时候,然而我们也可以通过使用两个Redis实例来达到相同的效果,值得一提的是将key设置过期时间实际上会消耗更多的内存,因此我们建议使用allkeys-lru策略从而更有效率的使用内存。

2、redis是否是线程安全的数据库?

在这里插入图片描述

3、redis的哈希槽,你是如何理解的?(redis的数据是如何存储的?)

在这里插入图片描述

4、redis缓存穿透、redis缓存击穿、redis缓存雪崩如何理解?

①缓存穿透:
	查询一个在缓存中不存在的数据,同时数据库也不存在.
问题:
	这个数据库访问量瞬间增大,数据库可能发生io阻塞,雪崩.
解决:
	如果发现数据库没有数据,放一个空字符串,并且设置过期时间.
补存:
	缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,
	并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。
	在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。
解决方案
	有很多种方法可以有效地解决缓存穿透问题,
	最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
	另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。
--------------------------------------------------------------------------------------
②缓存击穿
	缓存中一个key值过期了,恰好这个key值面临高并发查询,此时缓存中没有数据,
问题:
	并发压力瞬间转移到数据库,造成数据库雪崩.
解决:
	redis缓存加锁进行控制,当第一次访问没有值,查询数据库放入
补存:
	缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。
解决方案
	缓存失效时的雪崩效应对底层系统的冲击非常可怕。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线 程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。
	这里分享一个简单方案就时讲缓存失效时间分散开,
	比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
-----------------------------------------------------------------------------------------
③缓存雪崩
	缓存中很多key值同时过期,恰好此时这些key值面临高并发查询,发现缓存中数据消失
问题:
	并发压力瞬间转移到数据库中,数据库面临非常严重的高并发压力,发生雪崩.
解决:
	让redis的key值不同时过期
	让redis缓存时间5分钟过期+随机数(5分钟)
补充:
	对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里针对某一key缓存,前者则是很多key。
	缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,
	这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
解决方案
	使用互斥锁(mutex key)
	业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),
	不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,
	当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。	

猜你喜欢

转载自blog.csdn.net/qq_43690918/article/details/85047454