1、什么是Redis

  Redis是一个高性能的key/value的分布式内存数据库,基于内存运行并支持持久化的NoSQL数据库。

2、redis可以做什么

  内存存储和持久化、发布与订阅、分布式锁等

3、redis数据类型有哪些

string

string是二进制安全的,它可以包含任何数据,最大能存储512MB。

使用场景:常规key-value缓存应用;常规计数:微博数,粉丝数

hash

hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

使用场景:存储部分变更数据,如用户信息等。

list

list列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

使用场景:可作为栈,队列,如获取最新得N个数据操作,消息队列系统。

set

set是string类型的无序集合,通过HashTable实现。

使用场景:交集、并集、差集;获取某段时间所有数据去重值

zset

zset和set一样是string类型元素的集合,且不重复

使用场景:sorted set是自动排序的,可以通过用户额外提供一个优先级score的参数为成员排序,并且插入有序。如排行榜,带权重的消息队列。

4、redis过期策略

定时过期:每个设置过期时间的key,都创建一个定时器,到过期时间就会立即清除

惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则删除

定期过期:每隔一段时间执行删除过期key操作

redis中同时使用了惰性过期和定期过期两种策略

5、redis内存淘汰策略

当内存达到maxmemory极限时,需要使用LRU淘汰算法来决定清理掉哪些数据 LRU算法:也就是默认删除最近最少使用的键

redis提供6种数据淘汰策略

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

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

allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!

4.0版本后增加以下两种:

volatile-lfu:从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰

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

6、redis持久化机制

redis提供了两种方式的数据持久化,一种是RDB,一种是AOF

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,具体过程是: Redis使用fork函数复制一份当前进程的副本 父进程继续接受处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件 当子进程写完写完所有数据后,会用该临时文件替换旧的RDB文件

RDB优点

适合大规模的数据恢复

如果业务对数据完整性和一致性要求不是太高的话,RDB是一个不错的选择

RDB缺点

如果系统在定时持久化之前出现宕机现象,此前还没有来得及写入磁盘的数据将会丢失

由于RDB是通过fork子进程来完成持久化工作的,如果数据集较大时,可能会导致整个服务器停止几百毫秒甚至一秒钟

AOF的出现主要是弥补RDB的不足,即数据不一致性,采用日志的形式记录每个些操作,并追加到文件中。 AOF优点

数据的完整性和一致性较高 当日志过大时,可以自动启用Rewrite机制

AOF缺点:

AOF文件记录内容多,文件会越来越大,数据恢复也会越来越慢 根据同步策略的不同,AOF在运行效率上要慢于RDB

7、redis集群三种方式

主从复制、哨兵模式、集群

主从复制

原理:当一个数据库启动后,会向主数据库发送SYNC命令。同时主数据库接收到SYNC命令后会开始在后台保存快照,并将保存快照期间接收的命令缓存起来。当快照完成后,Redis会将快照文件和所有缓存的命令发送给从数据库。从数据库接收到后,会载入快照文件并执行收到的缓存的命令。复制是初始化结束后,主数据库每接收到写命令时就会将命令同步给从数据库,从而保证主从数据库数据一致。

哨兵模式

监控主从服务器是否正常运行,主服务器故障,自动将从服务器转换为主服务器

集群模式

可以实现redis分布式存储,就是每台redis节点存储不同的内容

8、缓存穿透、缓存击穿、缓存雪崩及解决方式

缓存穿透

缓存穿透是指缓存没有发挥作用,业务系统虽然去缓存中查询数据,但是缓存中没有数据,业务系统需要再次去存储系统中查询数据。

解决方案

当数据库找不到的时候,也将空对象写进缓存,并设置较短的过期时间

对于不合法的请求,可以使用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问到的key,不存在则过滤

布谷鸟过滤器

缓存击穿

在缓存数据过期那一刻,但是DB中存在的时候,大量请求回击穿到DB,导致DB压力过大

解决方案

可以设置热点数据永不过期

可以加一个互斥锁

缓存雪崩

设置缓存时,采用了相同的过期时间,导致某时刻缓存同时失效,请求全部转向DB,DB瞬时压力过大雪崩

Redis宕机,导致客户端的请求流向DB,拖垮DB

解决方案

对于缓存同时失效的情况

可以在原有的过期时间上加上一个随机值

对缓存更新操作进行加锁保护,保证只有一个线程能够进行缓存更新,未获取到锁的线程要么等待锁释放后重新读取缓存,要么就返回空值和默认值

后台更新

(1)定时读取——后台线程定时更新缓存

(2)消息队列通知——业务线程发现缓存失效后,通过消息队列发送一条消息通知后台线程更新缓存

双key策略

key有过期时间,key1没有过期时间,每次缓存读取不到key时,就返回key1的内容,然后触发一个事件。这个事件会同时更新key和key1。

对于“redis挂掉”这种情况

  事前:尽量保证整个 redis 集群的高可用性,发现机器宕机尽快补上。选择合适的内存淘汰策略。

  事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL崩掉

  事后:利用 redis 持久化机制保存的数据尽快恢复缓存

9、为什么redis是单线程的

因为redis采用的是多路I/O复用模型,可以让单个线程处理多个链接请求,而且redis是基于内存操作,操作数据的速度非常快

10、如何使用缓存

对于不同场景设置缓存过期或不过期

维度化缓存与增量缓存:如一个商品,包含了多个维度属性,对商品属性进行维度化并增量更新

大Value缓存: 可以对大value进行拆分;或者拆分成多个小value

热点缓存: 对于访问非常频繁的热点缓存,如果每次都去远程缓存系统中获取,可能会因为访问量过大,导致缓存系统请求过多,负载过高等问题。解决方案是可以挂更多的从缓存,客户端通过负载均衡机制读取从缓存系统数据。

11、Redis分布式锁实现原理

单实例中

基于Redis命令:

set key value NX PX max-lock-time

value要具有唯一性

释放锁时,lua脚本中一定要比较value,防止误解锁是

集群多节点

用官网推荐的Redission实现的分布式锁

12、redis事务

  Redis 通过 MULTI、EXEC、WATCH 等命令来实现事务(transaction)功能。事务提供了一种将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕,然后才去处理其他客户端的命令请求。

13、如何解决Redis的并发竞争key的问题

Redis多线程并发竞争key,也就是多个系统同时对一个key进行操作,但是最后执行的顺序和我们期望的顺序不同,也就导致了结果的不同。

如何解决

使用分布式锁:redis分布式锁/zookeeper分布式锁

14、如何保证缓存和数据库双写时的数据一致性

将读和写串行到一个内存队列中,这样就不会出现不一致了,但是吞吐量就会下降(最好不要做这个方案)

先删除缓存,再更新数据库库