Java面试——Redis

目录

一、什么是 Redis

二、Redis 与 Memcached 的区别

三、Redis 有哪几种数据淘汰策略

四、Redis 支持哪几种数据类型

五、Redis 集群方案什么情况下会导致整个集群不可用

六、Redis 哈希槽的概念

七、Redis 集群会有写操作丢失吗

八、Redis 集群之间是如何复制的

九、Redis 集群如何选择数据库

十、Redis 中的管道(Pipeline)有什么用

十一、怎么理解 Redis事务

十一、Redis 事务相关的命令有哪几个

十二、Redis key 的过期时间和永久有效分别怎么设置

十三、Redis 如何做内存优化

十四、Redis 回收进程如何工作的

十五、Redis 回收使用的是什么算法

十六、Redis 如何做大量数据插入

十七、为什么要做 Redis分区

十八、你知道有哪些 Redis分区实现方案

十九、Redis 持久化数据和缓存怎么做扩容

二十、分布式 Redis是前期做还是后期规模上来了再做好?为什么?

二十一、Twemproxy 是什么

二十二、Redis 与其他 key-value存储有什么不同

二十三、Redis 的内存占用情况怎么样

二十四、都有哪些办法可以降低Redis的内存使用情况

二十五、查看 Redis使用情况及状态信息用什么命令

二十六、Redis 的内存用完了会发生什么

二十七、Redis 是单线程的,如何提高多核CPU的利用率

二十八、一个 Redis实例最多能存放多少的keys?List、Set、Sorted Set他们最多能存放多少元素

二十九、Redis 常见性能问题和解决方案

三十、Redis 提供了哪几种持久化方式

三十一、如何选择合适的持久化方式

三十二、修改配置不重启 Redis会实时生效吗

三十三、Redis 中的哨兵模式(sentinel) 的作用

三十四、谈谈你对 Redis 集群 Cluster的理解

三十五、Redis 的常用配置有哪些

三十六、Redis 的线程模型

三十七、Redis 分布式锁的理解

三十八、Redis 平常用到的调优

三十九、Scan 命令的使用

四十、怎样防止消息丢失

四十一、Redis 中时间复杂度为 O(n) 的命令


一、什么是 Redis


Redis(Remote Dictionary Server 远程字典服务) 本质上是一个 Key-Value 类型的内存数据库,和 Memcached类似,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)等数据结构。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,Redis 支持各种不同方式的排序。与 Memcached一样,为了保证效率,数据都是缓存在内存中。区别是 Redis 会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了 master-slave 主从同步。因为是纯内存操作,Redis 的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的 Key-Value DB。 Redis 的出色之处不仅仅是性能,Redis 最大的魅力是支持保存多种数据结构,此外单个 value的最大限制是1GB,不像 Memcached只能保存1MB的数据,因此 Redis可以用来实现很多有用的功能,比方说用他的 List来做FIFO双向链表,实现一个轻量级的高性能消息队列服务,用他的 Set可以做高性能的 tag系统等等。另外 Redis也可以对存入的Key-Value设置 expire时间,因此也可以被当作一 个功能加强版的 Memcached来用。 Redis 的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此 Redis适合的场景主要局限在较小数据量的高性能操作和运算上。

二、Redis 与 Memcached 的区别


Redis 与 Memcached 的相似之处:【1】Redis 和 Memcached 都是内存数据存储系统,都用作内存中的键值数据存储;
【2】Redis 和 Memcached 都属于NoSQL系列数据管理解决方案,两者都基于键值数据模型;
【3】Redis 和 Memcached 都将所有数据保存在 RAM 中,这当然使它们作为缓存层非常有用;
Redis 与 Memcached 的区别:【1】Redis 和 Memcached都是将数据存放在内存中,都是内存数据库。不过 Memcached 还可用于缓存其他东西,例如图片、视频等等;
【2】Redis 不仅仅支持简单的 k/v 类型的数据,同时还提供 listsetzsethash等数据结构的存储;
【3】虚拟内存 Redis 当物理内存用完时,可以将一些很久没用到的 value 交换到磁盘
【4】过期策略 Memcached 在 set 时就指定,例如:set key1 0 0,即永不过期。Redis 可以通过例如 expire 设定,例如:expire name 10;
【5】存储数据安全性 Memcached 挂掉后,数据就没了。Redis可以定期保存到磁盘(持久化);
【6】灾难恢复 Memcached 挂掉后,数据不可恢复。Redis 数据丢失后可以通过 rdb 或 aof恢复;
【7】Memcached不支持复制,Redis支持主从复制,允许从属 Redis服务器成为主服务器的精确副本;来自任何 Redis服务器的数据都可以复制到任意数量的从属服务器。
【8】应用场景不一样:Redis 除了作为 NoSQL数据库使用外,还能用做消息队列、数据堆栈和数据缓存等;Memcached适合于缓存SQL语句、数据集、用户临时性数据、延迟查询数据和 session等。
【9】Memcached 的读写速度高于 Redis,因为Redis 是单线程的,而 Memcached 是多线程的
【10】Memcached 单个 key-value大小有限,一个 value最大只支持1MB,而 Redis最大支持512MB;

三、Redis 有哪几种数据淘汰策略


Redis 检查内存使用情况,如果已使用的内存大于 maxmemory的值则开始根据用户配置的不同淘汰策略来淘汰内存(key),从而换取一定的内存。maxmemory=0 的时候表示我们对 Redis的内存使用没有限制。淘汰策略如下:
【1】noeviction:返回错误。当内存使用达到阈值的时候,所有引起申请内存的命令会报错。
【2】allkeys-lru:在主键空间中,优先移除最近未使用的key。
【3】volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key。
【4】allkeys-random:回收随机的键使得新添加的数据有空间存放。
【5】volatile-random:回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
【6】volatile-ttl:回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。

四、Redis 支持哪几种数据类型


Reids 支持7中数据结构,最常用的是 StringListSetSorted SetHash 其内部结构及使用参照博客链接

五、Redis 集群方案什么情况下会导致整个集群不可用


假如有A,B,C三个节点的集群,在没有主从复制模型的情况下,其中一个节点挂掉,那么整个集群就会缺少某个范围的槽而不可用。所以从节点很重要。

六、Redis 哈希槽的概念


Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有 16384个哈希槽,每个 key通过 CRC16校验后对16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash槽。

七、Redis 集群会有写操作丢失吗


Redis 并不能保证数据的强一致性,这意味这在实际生产中集群在特定的条件下可能会丢失写操作。

八、Redis 集群之间是如何复制的


博客连接】:链接

九、Redis 集群如何选择数据库


Redis 集群目前无法做数据库选择,默认在0数据库。

十、Redis 中的管道(Pipeline)有什么用


客户端将请求传送给服务器,服务器处理完毕后,再将响应回复给客户端。这要花费一个网络数据包来回的时间。如果连续执行多条指令,那么就会花费多个网络数据包来回的时间(多条指令,一条一条发送给服务器)。
管道的本质是:将多个连续的读写操作合并后总共花费一次网络来回。就好像连续的写操作合并了,连续的读操作也合并了一样。服务器根本没有任何区别对待,还是走着收着一条消息、执行一条消息、回复一条消息的正常流程。Redis 自带了管道的压力测试工具 redis-benchmark,使用此工具可以进行管道测试:

redis-benchmark -t set -q
SET: 54938.05 requests per second

# -P 表示管道内并行的请求数量。  当P=2 时,QPS 达到 9W/s  
# 当P达到一定值时,会下降,因为单线程CPU消耗已经达到 100%,所以无法上升
redis-benchmark -t set -P 2 -q
SET: 93238.15 requests per second

将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。这就是管道(pipelining),是一种几十年来广泛使用的技术。例如许多 POP3协议已经实现支持这个功能,大大加快了从服务器下载新邮件的过程。

十一、怎么理解 Redis事务


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

十一、Redis 事务相关的命令有哪几个


MULTI、EXEC、DISCARD、WATCH、UNWATCH

十二、Redis key 的过期时间和永久有效分别怎么设置


EXPIRE 和 PERSIST命令。

十三、Redis 如何做内存优化


尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的 web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面。

十四、Redis 回收进程如何工作的


【1】一个客户端运行了新的命令,添加了新的数据。
【2】Redis 检查内存使用情况,如果大于 maxmemory的限制, 则根据设定好的策略进行回收。
【3】一个新的命令被执行,等等。
【4】所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收回到边界以下。

如果一个命令的结果导致大量内存被使用(例如很大的集合的交集保存到一个新的键),不用多久内存限制就会被这个内存使用量超越。

十五、Redis 回收使用的是什么算法


Redis 中采用两种算法进行内存回收,引用计数算法以及 LRU算法(最近最久未使用算法)。

十六、Redis 如何做大量数据插入


Redis2.6 开始 redis-cli 支持一种新的被称之为 pipe mode 的新模式用于执行大量数据插入工作。

十七、为什么要做 Redis分区


分区可以让 Redis管理更大的内存,Redis 将可以使用所有机器的内存。如果没有分区,你最多只能使用一台机器的内存。分区使 Redis的计算能力通过简单地增加计算机得到成倍提升,Redis 的网络带宽也会随着计算机和网卡的增加而成倍增长。

十八、你知道有哪些 Redis分区实现方案


【1】客户端分区:就是在客户端就已经决定数据会被存储到哪个 Redis节点或者从哪个 Redis节点读取。大多数客户端已经实现了客户端分区。
【2】代理分区:意味着客户端将请求发送给代理,然后代理决定去哪个节点写数据或者读数据。代理根据分区规则决定请求哪些 Redis实例,然后根据 Redis的响应结果返回给客户端。Redis 和 memcached 的一种代理实现就是 Twemproxy。
【3】查询路由(Query routing) :意思是客户端随机地请求任意一个 Redis实例,然后由 Redis将请求转发给正确的 Redis节点。Redis Cluster 实现了一种混合形式的查询路由,但并不是直接将请求从一个 Redis节点转发到另一个 Redis节点,而是在客户端的帮助下直接 Redirected到正确的 Redis节点。

十九、Redis 持久化数据和缓存怎么做扩容


【1】如果 Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。
【2】如果 Redis被当做一个持久化存储使用,必须使用固定的 keys-to-nodes 映射关系,节点的数量一旦确定不能变化。否则的话(即 Redis节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis集群可以做到这样。

二十、分布式 Redis是前期做还是后期规模上来了再做好?为什么?


既然 Redis是如此的轻量(单实例只使用1M内存),为防止以后的扩容,最好的办法就是一开始就启动较多实例。即便你只有一台服务器,你也可以一开始就让 Redis以分布式的方式运行,使用分区,在同一台服务器上启动多个实例。
一开始就多设置几个Redis实例,例如 32或者 64个实例,对大多数用户来说这操作起来可能比较麻烦,但是从长久来看做这点牺牲是值得的。
这样的话,当你的数据不断增长,需要更多的 Redis服务器时,你需要做的就是仅仅将 Redis实例从一台服务迁移到另外一台服务器而已(而不用考虑重新分区的问题)。一旦你添加了另一台服务器,你需要将你一半的 Redis实例从第一台机器迁移到第二台机器。

二十一、Twemproxy 是什么


Twemproxy 是 Twitter 维护的(缓存)代理系统,代理 Memcached 的 ASCII协议和 Redis协议。它是单线程程序,使用c语言编写,运行起来非常快。它是采用 Apache 2.0 license的开源软件。 Twemproxy 支持自动分区,如果其代理的其中一个 Redis节点不可用时,会自动将该节点排除(这将改变原来的 keys-instances的映射关系,所以你应该仅在把 Redis当缓存时使用Twemproxy)。 Twemproxy 本身不存在单点问题,因为你可以启动多个 Twemproxy实例,然后让你的客户端去连接任意一个Twemproxy 实例。 Twemproxy 是 Redis客户端和服务器端的一个中间层,由它来处理分区功能应该不算复杂,并且应该算比较可靠的。

二十二、Redis 与其他 key-value存储有什么不同


【1】Redis 有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis 的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。
【2】Redis 运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,应为数据量不能大于硬件内存。在内存数据库方面的另一个优点是, 相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。 同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。

二十三、Redis 的内存占用情况怎么样


给你举个例子: 100万个键值对(键是0到999999值是字符串“hello world”)在我的 32位的Mac笔记本上用了100MB。同样的数据放到一个 key里只需要16MB, 这是因为键值有一个很大的开销。 在 Memcached上执行也是类似的结果,但是相对 Redis的开销要小一点点,因为 Redis会记录类型信息引用计数等等。当然,大键值对时两者的比例要好很多。64位的系统比32位的需要更多的内存开销,尤其是键值对都较小时,这是因为 64位的系统里指针占用了8个字节。 但是,当然,64位系统支持更大的内存,所以为了运行大型的 Redis服务器或多或少的需要使用 64位的系统。

二十四、都有哪些办法可以降低Redis的内存使用情况


如果你使用的是 32位的 Redis实例,可以好好利用 Hash、list、sorted set、set等集合类型数据,因为通常情况下很多小的 Key-Value 可以用更紧凑的方式存放到一起。

二十五、查看 Redis使用情况及状态信息用什么命令


【博客连接】:链接

二十六、Redis 的内存用完了会发生什么


如果达到设置的上限,Redis 的写命令会返回错误信息(但是读命令还可以正常返回。)或者你可以将 Redis当缓存来使用配置淘汰机制,当 Redis达到内存上限时会冲刷掉旧的内容。

二十七、Redis 是单线程的,如何提高多核CPU的利用率


可以在同一个服务器部署多个 Redis的实例,并把他们当作不同的服务器来使用,在某些时候,无论如何一个服务器是不够的, 所以,如果你想使用多个 CPU,你可以考虑一下分片(shard)。

二十八、一个 Redis实例最多能存放多少的keys?List、Set、Sorted Set他们最多能存放多少元素


【1】理论上 Redis可以处理多达 232的 keys,并且在实际中进行了测试,每个实例至少存放了 2亿5千万的 keys。我们正在测试一些较大的值。
【2】任何 list、set、和 sorted set都可以放 232个元素。换句话说,Redis 的存储极限是系统中的可用内存值。

二十九、Redis 常见性能问题和解决方案


【1】Master 最好不要做任何持久化工作,如 RDB内存快照和 AOF日志文件;
【2】如果数据比较重要,某个 Slave 开启 AOF备份数据,策略设置为每秒同步一次;
【3】为了主从复制的速度和连接的稳定性,Master 和 Slave最好在同一个局域网内;
【4】尽量避免在压力很大的主库上增加从库;
【5】主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...

这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1 做 Master,其他不变。

三十、Redis 提供了哪几种持久化方式


【1】RDB 持久化方式能够在指定的时间间隔能对你的数据进行快照存储;
【2】AOF 持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据。AOF命令以redis协议追加保存每次写的操作到文件末尾。Redis 还能对 AOF文件进行后台重写,使得AOF文件的体积不至于过大。
【3】如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。
【4】你也可以同时开启两种持久化方式,在这种情况下,当 Redis 重启的时候会优先载入 AOF文件来恢复原始的数据,因为在通常情况下 AOF文件保存的数据集要比 RDB文件保存的数据集要完整。
【5】最重要的事情是了解 RDB和 AOF持久化方式的不同,让我们以RDB持久化方式开始。

三十一、如何选择合适的持久化方式


一般来说, 如果想达到足以媲美 PostgreSQL的数据安全性, 你应该同时使用两种持久化功能。如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失,那么你可以只使用 RDB持久化。有很多用户都只使用 AOF持久化,但并不推荐这种方式:因为定时生成RDB快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF恢复的速度要快,除此之外, 使用 RDB还可以避免之前提到的 AOF 程序的 bug。

三十二、修改配置不重启 Redis会实时生效吗


针对运行实例,有许多配置选项可以通过 CONFIG SET 命令进行修改,而无需执行任何形式的重启。 从 Redis 2.2 开始,可以从 AOF 切换到 RDB 的快照持久性或其他方式而不需要重启 Redis。检索 ‘CONFIG GET *’ 命令获取更多信息。但偶尔重新启动是必须的,如为升级 Redis 程序到新的版本,或者当你需要修改某些目前 CONFIG 命令还不支持的配置参数的时候。

三十三、Redis 中的哨兵模式(sentinel) 的作用


典型的问题就是,当主节点宕机后,sentinel 是如何进行主从切换的。【博客链接

三十四、谈谈你对 Redis 集群 Cluster的理解


博客连接】:链接

三十五、Redis 的常用配置有哪些


博客连接】:链接

三十六、Redis 的线程模型


博客连接】:链接

三十七、Redis 分布式锁的理解


博客连接】:链接

三十八、Redis 平常用到的调优


博客连接】:链接​​​​​​​

三十九、Scan 命令的使用


scan 提供了三个参数,第一个是 cursor 整数值,第二个是 key 的正则模式,第三个是遍历的 limit hint。第一次遍历时,cursor 值为 0,然后将返回结果中第一个整数值作为下一次遍历的 cursor,一直遍历到返回的 cursor 值为 0时结束。举个栗子:

127.0.0.1:6379> scan 0 match key99* count 1000
1) "13976"
2)  1) "key9933"
    2) 此处省略9个

从上面的过程中可以看出,虽然提供的 limit 是 1000,但是返回的结果却只有 10个左右。因为这个 limit 不是限定返回结果的数量,而是限定服务器单次遍历的字典槽数量(约等于)。返回的值是游标,目前游标的值不为零,意味着遍历还没有结束。

四十、怎样防止消息丢失


Redis 主从采用异步复制,意味着当主节点挂掉时,从节点可能没有收到全部的同步消息,这部分未同步的消息就丢失了。如果主从延迟特别大,那么丢失的数据就可能会特别多。Sentinel 无法保证消息完全不丢失,但是也能尽量保证消息少丢失。它有两个选项可以限制主从延迟过大:

min_slave_to_write 1
min_slave_max_lag 10

第一个参数表示主节点至少保证有一个从节点在正常复制,否则就停止对外写服务,丧失可用性;
何为正常复制,何为异常复制:由第二个参数控制,它的单位是秒(s),表示如果在 10s 内没有收到从节点反馈,就意味着从节点同步不正常,要么是网络断开了,要么是一直没有给反馈。

四十一、Redis 中时间复杂度为 O(n) 的命令


List: lindex、lset、linsert;
Hash: hgetall、hkeys、hvals;
Set: smembers、sunion、sunionstore、sinter、sinterstore、sdiff、sdiffstore;
Sorted Set: zrange、zrevrange、zrangebyscore、zrevrangebyscore、zremrangebyrank、zremrangebyscore;                                                                                            

----如果喜欢,点个  红心♡  支持以下,谢谢----

发布了229 篇原创文章 · 获赞 317 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/zhengzhaoyang122/article/details/103589880
今日推荐