Redis面试题总结

1、什么是Redis?

Redis是一个基于内存的高性能key-value数据库;Redis是一个用C语言编写的,开源的key-value数据库;和Memcached类似,他支持存储的value类型多,string,list,set,zset,hash;这些数据类型都支持push/pop和add/remove以及交集并集和差集及更丰富的操作,他们都是原子操作;在此基础上,redis支持各种不同方式的排序;与memcached一样,为了保证效率,数据都是缓存在内存里的;区别的是redis会周期的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且再此基础上实现了master-slave(主从)同步;目前,Vmware在资助着redis项目的开发和维护;

2、Redis特点?

(1)Redis本质上是一个key-value内存版的数据库,他会把数据库中的全部数据全都加载到内存中,再进行操作,定期通过异步操作把数据库的数据flush到硬盘上进行保存;

(2)因为Redis是纯内存的数据库,所以性能非常出色,每秒可以处理超过10万的读写操作;

(3)Redis最大的魅力在于可以存储多种不同的数据结构,此外单个value的最大限度是1GB,而memcached只能保存1MB;

(4)用Redis的List做一个FIFO的双向链表,实现一个轻量级的高性能消息队列服务;另外Redis也可以对存入的Key-Value设置expire时间;

3、Redis的优缺点:

优点:

(1)速度快,因为数据在内存里,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)

(2)支持丰富的数据类型,string,list,set,zset,hash;

(3)支持事务,操作都是原子性,所谓原子性,就是对数据的更改要么全部执行,要么全部不执行;

(4)丰富的特性:可用缓存,消息,按key设置过期时间,过期后自动删除;

缺点:

     数据库的容量受到物理内存的限制,不能用于海量数据的高性能读写,因此redis适用于局限在较小数据量的高性能操作和运算上;

4、redis比Memcached有哪些优势?

(1)memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型;

(2)redis速度比memcached快很多;

(3)redis可以支持持久化其数据;

5、Memcached和redis的区别?

(1)memcached将数据全部存储在内存中,断电会挂掉,数据不能超过内存大小;redis能将部分数据放到硬盘上,这样能保证数据持久性;重启后可再次加载进行使用;

(2)memcached对支持的数据类型比较简单,而redis有复杂的数据类型;

(3)Redis支持数据备份,即master-slave模式的数据备份;

(4)memcached是多线程的,非阻塞IO复用的网络模型;Redis使用单线程的IO复用模型;

6、Redis常见的数据结构使用场景:

(1)String

         常用指令:set,get,decr,incr,mget等;

         String数据结构是简单的key-value类型,value不仅是String,也可以是数字;

         常规key-value缓存应用:

         常规计数:微博数,粉丝数等;

(2)hash

         常用指令:hset,hget,hgetall等;

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

         比如我们可以用hash数据结构来存储用户信息,商品信息等;

(3)list

         常用指令:lpush,lpop,rpush,rpop,lrange等;

         list就是链表,Redis list的应用场景比较多,也是redis最重要的数据结构之一;

         比如微博的关注列表,粉丝列表,最新消息排行等;

         list的实现是一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销;

(4)set

         常用指令:sadd,spop,smemberes,sunion等;

         对外提供的功能和list类似,特殊之处在于set可以自动排重;

         当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

         在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis可以非常方便的实现如共同关注、共同喜好、二度好友等功能。

(5)zset

         常用指令:zadd,zrange,zrem,zcard等;

         和set比,sorted set增加了一个权重参数score,使得集合中的元素能够按照score进行有序排序;

         在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息,适合使用Redis中的SortedSet结构进行存储。

7、mysql里有2000w数据,Redis里面只能存20w数据,如何保证Redis中的数据都是热点数据?(redis有哪些数据淘汰策略?)

redis内存集大小上升到一定大小的时候,就会施行数据淘汰策略;redis提供了六种数据淘汰策略:

(1)volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰;

(2)volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰;

(3)allkeys-lru:从数据集中挑选最近最少使用是数据淘汰;

(4)allkeys-ttl:从数据集中挑选将要过期的数据淘汰;

(5)no-enviction(驱逐):禁止驱逐数据

8、Redis的并发竞争问题如何解决?

Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问。Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争关系,但是在Jedis客户端对Redis进行并发访问时会发生连接超时,数转换错误,阻塞,客户端关闭连接等问题,这些问题是由于客户端连接混乱造成的;对此有两种解决方法:

(1)客户端角度,为每个客户端间正常有序与Redis进行通信,对连接池进行池化,同时对客户端读写Redis操作采用内部锁synchronized;

(2)服务器角度,利用setnx实现锁;

         setnx实现分布式锁,多个进程执行Redis命令:setnx  lock.foo  <current  Unix  time  +  lock  timeout  +  1>

         如果setnx返回1,说明该进程获得锁,setnx将键lock.foo的值设置为锁的超时时间(当前时间+锁的有效时间)

         如果setnx返回0,说明其他进程已经获得了锁,进程不能再进入临界区;进程可以在一个循环中不断尝试setnx,已获得锁;

9、Redis回收进程是如何工作的?Redis回收使用的是什么算法?

Redis的回收算法:LRU算法;(最近最久未被使用)

在操作系统中,LRU算法淘汰的不是内存对象,是页,当内存中数据不足的时候,通过LRU算法,选择一页(4KB)将其交换到虚拟机内存区(swap区);

LRU的实现:HashMap+Double LinkedList,时间复杂度O(1),

10、Redis大量数据插入?

使用Luke协议;使用管道(pipelining)是一种可行的方法,但是在大量插入数据的同时又需要执行其他新命令时,这时读取数据的同时需要确保请可能快的的写入数据。

从Redis 2.6开始,redis-cli支持一种新的被称之为pipe mode的新模式用于执行大量数据插入工作;

将产生如下的输出:

使用redis-cli将有效的确保错误输出到Redis实例的标准输出里面;

pipe mode的工作原理:难点是保证redis-cli在pipe mode模式下执行和netcat一样快的同时,如何能理解服务器发送的最后一个回复;通过以下方式获得:

  • redis-cli –pipe试着尽可能快的发送数据到服务器。
  • 读取数据的同时,解析它。
  • 一旦没有更多的数据输入,它就会发送一个特殊的ECHO命令,后面跟着20个随机的字符。我们相信可以通过匹配回复相同的20个字符是同一个命令的行为。
  • 一旦这个特殊命令发出,收到的答复就开始匹配这20个字符,当匹配时,就可以成功退出了。

同时,在分析回复的时候,我们会采用计数器的方法计数,以便在最后能够告诉我们大量插入数据的数据量。

11、Redis分区的优势,不足以及分区类型?

分区:分割数据到多个Redis实例的处理过程,因此每个实例只保存key的一个子集;

优势:(1)通过利用多台计算机的内存和值,构造更大的数据库;

           (2)通过多核和多态计算机,允许我们扩展计算能力;通过多态计算机和网络配置器,允许我们扩展网络带宽;

不足:(1)涉及多个key的操作通常不被支持的;举例来说,当两个set映射到不同的redis实例上时,你就不能对这两个set执行交集操作。

          (2)涉及多个key的redis事务不能使用;

          (3)增加或删除容量也比较复杂;

类型:两种,范围分区和哈希分区; 假设有4个Redis实例 R0,R1,R2,R3,和类似user:1,user:2这样的表示用户的多个key,对既定的key有多种不同方式来选择这个key存放在哪个实例中。也就是说,有不同的系统来映射某个key到某个Redis服务。

         (1)范围分区:映射一定范围的对象到特定的Redis实例;

比如,ID从0到10000的用户会保存到实例R0,ID从10001到 20000的用户会保存到R1,以此类推。

这种方式是可行的,并且在实际中使用,不足就是要有一个区间范围到实例的映射表。这个表要被管理,同时还需要各 种对象的映射表,通常对Redis来说并非是好的方法。

          (2)哈希分区:对任意的key都适用,也无需是object_name这种形式;

用一个hash函数将key转换为一个数字,比如使用crc32 hash函数。对key foobar执行crc32(foobar)会输出类似93024922的整数。

对这个整数取模,将其转化为0-3之间的数字,就可以将这个整数映射到4个Redis实例中的一个了。93024922 % 4 = 2,就是说key foobar应该被存到R2实例中。注意:取模操作是取除的余数,通常在多种编程语言中用%操作符实现。

12、Redis持久化数据和缓存怎么扩容?

redis支持两种持久化方式,一种是Snapshotting(快照)也是默认方式,另一种方式是Append-only  file(aof);

(1)snapshotting:快照是默认的持久化方式;将内存中数据以快照的方式写入到二进制文件中,默认的问价名是dump.rdb;可以通过配置设置自动做快照持久化方式;我们可以配置redis在n秒内如果超过m个key被修改了就自动做快照;

  • save 900 1 #900 秒内如果超过 1 个 key 被修改,则发起快照保存
  • save 300 10 #300 秒内容如超过 10 个 key 被修改,则发起快照保存

下面介绍详细的快照保存过程:

        1.redis 调用 fork,现在有了子进程和父进程。

        2. 父进程继续处理 client 请求,子进程负责将内存内容写入到临时文件。由于 os 的实时复制机制( copy on write)父子进程会共享相同的物理页面,当父进程处理写请求时 os 会为父进程要修改的页面创建副本,而不是写共享的页面。所以子进程地址空间内的数据是 fork时刻整个数据库的一个快照。

        3.当子进程将快照写入临时文件完毕后,用临时文件替换原来的快照文件,然后子进程退出。client 也可以使用 save 或者 bgsave 命令通知 redis 做一次快照持久化。 save 操作是在主线程中保存快照的,由于 redis 是用一个主线程来处理所有 client 的请求,这种方式会阻塞所有client 请求。所以不推荐使用。另一点需要注意的是,每次快照持久化都是将内存数据完整写入到磁盘一次,并不是增量的只同步变更数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘 io 操作,可能会严重影响性能。

(2)aof方式

       由于快照方式是在一定间隔时间做一次的,所以如果 redis 意外 down 掉的话,就会丢失最后一次快照后的所有修改。如果应用要求不能丢失任何修改的话,可以采用 aof 持久化方式。下面介绍 Append-only file:aof 比快照方式有更好的持久化性,是由于在使用 aof 持久化方式时,redis 会将每一个收到的写命令都通过 write 函数追加到文件中(默认是 appendonly.aof)。当 redis 重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。当然由于 os 会在内核中缓存 write 做的修改,所以可能不是立即写到磁盘上。这样 aof 方式的持久化也还是有可能会丢失部分修改。不过我们可以通过配置文件告诉 redis 我们想要通过 fsync 函数强制 os 写入到磁盘的时机。有三种方式如下(默认是:每秒 fsync 一次)

 

  • appendonly yes //启用 aof 持久化方式
  • # appendfsync always //收到写命令就立即写入磁盘,最慢,但是保证完全的持久化
  • appendfsync everysec //每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中
  • # appendfsync no //完全依赖 os,性能最好,持久化没保证

        aof 的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用 incr test命令 100 次,文件中必须保存全部的 100 条命令,其实有 99 条都是多余的。因为要恢复数据库的状态其实文件中保存一条 set test 100 就够了。为了压缩 aof 的持久化文件。 redis 提供了 bgrewriteaof 命令。收到此命令 redis 将使用与快照类似的方式将内存中的数据以命令的方式保存到临时文件中,最后替换原来的文件。

13、Redis常见性能问题和解决方案:

(1)Master最好不要做任何的持久化工作,如RDB内存快照和AOF日志文件;

(2)如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次;

(3)为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内;

(4)尽量避免在压力很大的主库上增加从库;

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值