Redis重点及面试常见问题

Redis有哪些数据结构?

String、Hash、List、Set、SortedSet

redis 和 memcached 的区别

对于 redis 和 memcached 的区别有下面四点:

  1. redis支持更丰富的数据类型(支持更复杂的应用场景):Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。memcache支持简单的数据类型,String。
  2. Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而Memecache把数据全部存在内存之中。
  3. 集群模式:memcached没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;但是 redis 目前是原生支持 cluster 模式的.
  4. Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的多路 IO 复用模型。

缓存与数据库不一致问题

不一致分为三种情况:
1、数据库有数据,缓存没有数据;
2、数据库有数据,缓存也有数据,数据不相等;
3、数据库没有数据,缓存有数据。

缓存策略:
首先尝试从缓存读取,读到数据则直接返回;如果读不到,就读数据库,并将数据会写到缓存,并返回。
需要更新数据时,先更新数据库,然后把缓存里对应的数据失效掉(删掉)。

说完缓存策略,再来看不一致情况:
1、对于第一种,在读数据的时候,会自动把数据库的数据写到缓存,因此不一致自动消除
2、对于第二种,数据最终变成了不相等,但他们之前在某一个时间点一定是相等的)。这种不一致,一定是由于你更新数据所引发的。前面我们讲了更新数据的策略,先更新数据库,然后删除缓存。因此,不一致的原因,一定是数据库更新了,但是删除缓存失败了。
3、对于第三种,情况和第二种类似,把数据库的数据删了,但是删除缓存的时候失败了。
因此,最终的结论是,需要解决的不一致,产生的原因是更新数据库成功,但是删除缓存失败。
解决办法是:
1、对删除缓存进行重试,数据的一致性要求越高,我越是重试得快。
2、定期全量更新,简单地说,就是我定期把缓存全部清掉,然后再全量加载。
3、给所有的缓存一个失效期

redis 持久化机制

详细介绍:http://redis.cn/topics/persistence.html

Redis的一种持久化方式叫快照(snapshotting,RDB),另一种方式是只追加文件(append-only file,AOF)

快照(snapshotting)持久化(RDB): Redis可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。Redis创建快照之后,可以对快照进行备份,比较适合用来做灾备,但缺点是快照保存完成之前如果宕机,这段时间的数据将会丢失,另外保存快照时可能导致服务短时间不可用。

快照持久化是Redis默认采用的持久化方式,在redis.conf配置文件中默认有此下配置:

save 3600 1   #如果在3600秒(1小时)内,有一个以上的key被修改,那么就执行持久化操作!

save 300 10  #在300秒(5分钟)之内,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 60 10000 #在60秒(1分钟)之内,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

RDB执行流程:
1、redis 父进程首先判断当前是否在执行bgsave的子进程,如果在执行则bgsave 命令直接返回;
2、父进程执行 fork 操作创建子进程,这个复制过程中父进程是阻塞的,redis不能执行来自客户端的任何命令;
3、父进程 fork 后, bgsave 命令返回”Background saving started”信息并不再阻塞父进程,并可以响应其他命令;
4、子进程创建 RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换( RDB 始终完整);
5、子进程告诉父进程处理完成。

AOF(append-only file)持久化: 与快照持久化相比,AOF持久化 的实时性更好,因此已成为主流的持久化方案。默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:

appendonly yes

开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof。

在Redis的配置文件中存在三种不同的 AOF 持久化方式,它们分别是:

appendfsync always     #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec  #每秒钟同步一次,显示地将多个写命令同步到硬盘
appendfsync no      #让操作系统决定何时进行同步

用户可以考虑 appendfsync everysec选项 ,让Redis每秒同步一次AOF文件,Redis性能几乎没受到任何影响。而且这样即使出现系统崩溃,用户最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候,Redis还会优雅的放慢自己的速度以便适应硬盘的最大写入速度。

AOF执行流程:
1、所有的写入命令会追加到aof_buf中;
2、AOF缓冲区根据对应的策略向硬盘做同步操作;
3、随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的;
4、当Redis服务器重启时,可以加载AOF文件进行数据恢复;

redis 事务

MULTIEXECDISCARDWATCH是 Redis 事务相关的命令。事务可以一次执行多个命令, 并且带有以下两个重要的保证:

  • 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。

MULTI:标记一个事物块的开始;
EXEC:执行所有事物块内的命令;
DISCARD:取消事物,放弃执行事物块内的所有命令;
WATCH key:监视一个或多个key,如果在事务执行之前这些key被其他命令修改,那么事务将被打断;
UNWATCH:取消WATCH命令对所有key的监视。

如果事务中的某个命令执行错误,Redis会怎么处理?

(1)语法错误。语法错误指命令不存在或者命令参数的个数不对。执行EXEC命令后Redis就会直接返回错误,连语法正确的命令也不会执行 。

官网解释:事务在执行 EXEC之前,入队的命令可能会出错。比如说,命令可能会产生语法错误(参数数量错误,参数名错误,等等),或者其他更严重的错误,比如内存不足(如果服务器使用 maxmemory 设置了最大内存限制的话)。

从 Redis 2.6.5 开始,服务器会对命令入队失败的情况进行记录,并在客户端调用 EXEC 命令时,拒绝执行并自动放弃这个事务。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W9eMosnY-1645529903648)(C:\Users\kenslu\Pictures\Typora\语法错误.png)]

(2)运行错误。运行错误指在命令执行时出现的错误,比如使用散列类型的命令操作集合类型的键,这种错误在实际执行之前Redis是无法发现的,所以在事务里这样的命令是会被Redis接受并执行的。如果事务里的一条命令出现了运行错误,事务里其他的命令依然会继续执行(包括出错命令之后的命令),如下图。

官网解释:命令可能在 EXEC 调用之后失败。举个例子,事务中的命令可能处理了错误类型的键,比如将列表命令用在了字符串键上面,诸如此类。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0oGqQAtR-1645529903649)(C:\Users\kenslu\Pictures\Typora\运行错误.png)]

为什么 Redis 不支持回滚(roll back)-- 来自Redis中文官网

如果你有使用关系式数据库的经验, 那么 “Redis 在事务失败时不进行回滚,而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪。

以下是这种做法的优点:

  • Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
  • 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。

有种观点认为 Redis 处理事务的做法会产生 bug , 然而需要注意的是, 在通常情况下, 回滚并不能解决编程错误带来的问题。 举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR, 回滚是没有办法处理这些情况的。

缓存穿透

缓存穿透:key对应的数据在缓存和数据库中都不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,就有可能导致数据库崩溃。

解决方法:

一是:布隆过滤器。将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。

二是:缓存空对象。如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

缓存击穿

缓存击穿:目的性强,一个存在的key,在缓存过期的一刻,此时若有大量并发请求过来,这些请求发现缓存过期就会访问数据库,瞬间导致数据库压力骤增。比如微博服务器宕机!

解决方法:

一是:设置热点数据永不过期。这样避免了热点数据过期的情况,但此种方案会占用空间,如果热点数据多了起来,就会占用大量空间。

二是:使用互斥锁(key_mutex)。在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key,保证同时刻只有一个线程访问。

缓存雪崩

缓存雪崩:大量的key设置了相同的过期时间,导致在同一时刻全部失效,造成瞬时数据库的请求量过大,引起雪崩。

解决方法:简单来说将缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

参考文章:
http://redis.cn
https://www.cnblogs.com/johnsblog/p/6426287.html
https://www.cnblogs.com/iamsach/p/8490387.html
https://segmentfault.com/a/1190000018388385

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值