沃梦达 / 编程技术 / 数据库 / 正文

Redis中一些常见的面试题

前言这里整理了一些关于Redis中常见的面试题,希望可以帮到还在求职路上的你们。1. 什么是Redis?Redis 是一个基于内存的高性能key-value数据库,由C语言编写。引申问题常见nosql数据库分类及区别2. Redis的特...

前言

这里整理了一些关于Redis中常见的面试题,希望可以帮到还在求职路上的你们。

1. 什么是Redis?

Redis 是一个基于内存的高性能key-value数据库,由C语言编写。

引申问题

常见nosql数据库分类及区别

2. Redis的特点

Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单个value的最大限制是1GB,不像memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能,比方说用他的List来做FIFO双向链表,实现一个轻量级的高性能消息队列服务,用他的Set可以做高性能的Tag系统等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一个功能加强版的memcached来用。

Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。

3. Redis持久化的几种方式

快照(snapshots)

缺省情况情况下,Redis把数据快照存放在磁盘上的二进制文件中,文件名为dump.rdb。你可以配置Redis的持久化策略,例如数据集中每N秒钟有超过M次更新,就将数据写入磁盘;或者你可以手工调用命令SAVE或BGSAVE。

工作原理

(1) Redis forks.
(2)子进程开始将数据写到临时RDB文件中。
(3)当子进程完成写RDB文件,用新文件替换老文件。
(4)这种方式可以使Redis使用copy-on-write技术。

AOF

快照模式并不十分健壮,当系统停止,或者无意中Redis被kill掉,最后写入Redis的数据就会丢失。这对某些应用也许不是大问题,但对于要求高可靠性的应用来说,Redis就不是一个合适的选择,Append-only文件模式是另一种选择,你可以在配置文件中打开AOF模式。

虚拟内存方式

当你的key较小而value很大时,使用VM的效果会比较好,因为这样节约的内存比较大。

当你的key较大时,可以考虑使用一些非常方法将很大的key变成很大的value,比如你可以考虑将key,value组合成一个新的value。

vm-max-threads这个参数,可以设置访问swap文件的线程数,设置最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的.可能会造成比较长时间的延迟,但是对数据完整性有很好的保证。

如果数据量很大,可以考虑分布式或者其他数据库。

4. 使用Redis的优势

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

(2) 支持丰富数据类型,支持String,List,Set,Sorted Set,Hash 。

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

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

5. Redis各数据类型底层实现

String

字符串对象的编码可以是int、raw或者embstr。

(1) int 编码:保存的是可以用 long 类型表示的整数值。

(2) raw 编码:保存长度大于44字节的字符串(redis3.2版本之前是39字节,之后是44字节)。

(3) embstr 编码:保存长度小于44字节的字符串(redis3.2版本之前是39字节,之后是44字节)。

int 编码是用来保存整数值,raw编码是用来保存长字符串,而embstr是用来保存短字符串。

普通的字符串有两种,embstr和raw。embstr是Redis 3.0新增的数据结构,在2.8中是没有的。如果字符串对象的长度小于39字节,就用embstr对象。否则用传统的raw对象。

embstr和raw使用的存储结构如图:

embstr的好处有如下几点:

embstr的创建只需分配一次内存,而raw为两次(一次为sds分配对象,另一次为objet分配对象,embstr省去了第一次)。

相对地,释放内存的次数也由两次变为一次。

embstr的objet和sds放在一起,更好地利用缓存带来的优势。

embstr的坏处也很明显,如果字符串的长度增加需要重新分配内存时,整个redisObject和sds都需要重新分配空间,因此redis中的embstr实现为只读。

List

列表对象的编码可以是ziplist(压缩链表)linkedlist(双端链表)。

ziplist是一种压缩链表,它的好处是更能节省内存空间,因为它所存储的内容都是在连续的内存区域当中的。当列表对象元素不大,每个元素也不大的时候,就采用ziplist存储。但当数据量过大时就ziplist就不是那么好用了。因为为了保证他存储内容在内存中的连续性,插入的复杂度是O(N),即每次插入都会重新进行realloc。如下图所示,对象结构中ptr所指向的就是一个ziplist。整个ziplist只需要malloc一次,它们在内存中是一块连续的区域。

linkedlist是一种双向链表。它的结构比较简单,节点中存放pre和next两个指针,还有节点相关的信息。当每增加一个node的时候,就需要重新malloc一块内存。

Hash

哈希对象的编码可以是 ziplist 或者 hashtable。

hashtable 编码的哈希表对象底层使用字典数据结构,哈希对象中的每个键值对都使用一个字典键值对。

Set

集合对象的编码可以是 intset 或者 hashtable。

intset 编码的集合对象使用整数集合作为底层实现,集合对象包含的所有元素都被保存在整数集合中。

SortedSet

有序集合的编码可以是 ziplist 或者 skiplist。

skiplist 编码的有序集合对象使用 zet 结构作为底层实现,一个 zset 结构同时包含一个字典和一个跳跃表:

7. 如何保证Redis中的数据都是热点数据

Redis 内存数据集大小上升到一定大小的时候,就会执行数据淘汰策略(回收策略)。Redis 提供 6种数据淘汰策略:

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

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

(4)allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰。

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

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

8. Redis常见性能问题和解决方案

Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。

Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。

Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。

Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内。

9. 一个字符串类型的值能存储最大容量是多少?

512M

10. Redis集群方案应该怎么做?都有哪些方案?

(1)Codis目前用的最多的集群方案,基本和twemproxy一致的效果,但它支持在节点数量改变情况下,旧节点数据可恢复到新hash节点。

(2)Redis cluster3.0自带的集群,特点在于他的分布式算法不是一致性hash,而是hash槽的概念,以及自身支持节点设置从节点。

(3)在业务代码层实现,启动几个毫无关联的redis实例,在代码层,对key 进行hash计算,然后去对应的Redis实例操作数据。

本文标题为:Redis中一些常见的面试题

基础教程推荐