Redis最新面试题26题(初级、中级Redis面试题)
Redis 1级(入门基础)
1、Redis有哪些数据类型?
string,list,set,sorted set(Zset),hash
高级数据结构分别是bitmap、GEO、Stream、HyperLogLog 其中,最重要的就是bitmap。GEO数据结构可以在Redis中存储地理坐标。
Stream是Redis 5.0版本引入的一个新的数据类型,它以更抽象的方式模拟日志数据结构,但日志仍然是完整的:就像一个日志文件,通常实现为以只附加模式打开的文件,Redis流主要是一个仅附加数据结构。至少从概念上来讲,因为Redis流是一种在内存表示的抽象数据类型,他们实现了更加强大的操作,以此来克服日志文件本身的限制。
Stream是Redis的数据类型中最复杂的,尽管数据类型本身非常简单,它实现了额外的非强制性的特性:提供了一组允许消费者以阻塞的方式等待生产者向Stream中发送的新消息,此外还有一个名为消费者组的概念。
消费者组最早是由名为Kafka(TM)的流行消息系统引入的。Redis用完全不同的术语重新实现了一个相似的概念,但目标是相同的:允许一组客户端相互配合来消费同一个Stream的不同部分的消息。
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
2、集合和列表有什么区别?
列表list是可以从两端推入、推出数据的队列;列表可以存储相同字符;
集合set是无序列表(只能用SADD来添加元素);使用散列(hash)保证存储的字符不相同;集合支持交、并、差等计算(SINTER、SUNION、SDIFF);
3、有序集合zset和散列hash有什么区别?
散列存储键值对;
有序集合使用成员member来存储键,用分值(浮点数)来存储值;可根据分值的顺序来访问元素;
4、在散列中可以用HGETALL命令来获取所有的键值,但在值较大的情况下,我们如何更加稳妥的(避免服务器阻塞)获取全部 or 部分的键值?
获取全部的键值:使用HKEYS获取所有的键,然后使用HGET一个个的获取全部值,从而避免因为一次获取多个大体积的值而导致服务器阻塞。
获取部分的键值:也是使用HKEYS获取所有的键,然后根据条件筛选需要的键,使用HEXISTS检查键是否存在,然后再用HGET获取必要的键
5、讲一讲Redis的常用场景
简单kv字符存储、Session会话记录、Token保持、热点数据存储、网页缓存、数据行缓存、排名、高速队列、分布式锁、计数器、发布订阅……
6、Redis如何设置密码及验证密码?
设置密码:config set requirepass 123456
授权密码:auth 123456
Redis 2级(中级)
1、 Redis集群方案应该怎么做?都有哪些方案?
- 1.twemproxy,大概概念是,它类似于一个代理方式,使用方法和普通redis无任何区别,设置好它下属的多个redis实例后,使用时在本需要连接redis的地方改为连接twemproxy,它会以一个代理的身份接收请求并使用一致性hash算法,将请求转接到具体redis,将结果再返回twemproxy。使用方式简便(相对redis只需修改连接端口),对旧项目扩展的首选。 问题:twemproxy自身单端口实例的压力,使用一致性hash后,对redis节点数量改变时候的计算值的改变,数据无法自动移动到新的节点。
- 2.codis,目前用的最多的集群方案,基本和twemproxy一致的效果,但它支持在 节点数量改变情况下,旧节点数据可恢复到新hash节点。
- 3.redis cluster3.0自带的集群,特点在于他的分布式算法不是一致性hash,而是hash槽的概念,以及自身支持节点设置从节点。具体看官方文档介绍。
- 4.在业务代码层实现,起几个毫无关联的redis实例,在代码层,对key 进行hash计算,然后去对应的redis实例操作数据。 这种方式对hash层代码要求比较高,考虑部分包括,节点失效后的替代算法方案,数据震荡后的自动脚本恢复,实例的监控,等等。
2、MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?
redis内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。
相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。redis 提供 6种数据淘汰策略:
voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据
3、Redis和Redisson有什么关系?
Redisson是一个高级的分布式协调Redis客户端,能帮助用户在分布式环境中轻松实现一些Java的数据结构对象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)
4、Jedis 和Redisson同步异步IO的区别?
Jedis使用阻塞的I/O,且其方法调用都是同步的,程序流需要等到sockets处理完I/O才能执行,不支持异步。Jedis客户端实例不是线程安全的,所以需要通过连接池来使用Jedis。
Redisson使用非阻塞的I/O和基于Netty框架的事件驱动的通信层,其方法调用是异步的。Redisson的API是线程安全的,所以可以操作单个Redisson连接来完成各种操作。
5、Redis集群的主从复制模型是怎样的?
为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有N-1个复制品.
6、Redis集群会有写操作丢失吗?为什么?
Redis并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作。
7、Redis集群之间是如何复制的?
异步复制
8、Redis集群最大节点个数是多少?
16384,即哈希槽的数量
9、Redis哈希槽的概念?
Redis集群没有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。
10、谈谈AOF中appendfsync各个选项的区别?
appendfsync always:每次操作都写入一次aof文件,并完成磁盘同步,强烈不建议使用,会严重降低Redis的写效率,甚至写入放大问题;
appendfsync everysec:默认的选项,每一秒写入aof文件,并显式完成磁盘同步
appendfsync no:写入aof文件,不等待磁盘同步,即由系统来决定写AOF文件,可能会带来数据丢失问题。
11、谈谈如何解决AOF文件越来越膨胀的问题?
使用AOF 自动重写。即当AOF文件增长到一定大小的时候Redis能够调用 BGREWRITEAOF 对日志文件进行重写。它是这样工作的:Redis会记住上次进行写日志后文件的大小(如果从开机以来还没进行过重写,那日志大小在开机的时候确定)
基础大小会同现在的大小进行比较。如果现在的大小比基础大小大制定的百分比(auto-aof-rewrite-percentage),重写功能将启动。同时需要指定一个最小大小(auto-aof-rewrite-min-size)用于AOF重写,这个用于阻止即使文件很小但是增长幅度很大也去重写AOF文件的情况。
如:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
12、如何检查和修复AOF文件
检查:redis-check-aof appendonly.aof
修复:redis-check-aof appendonly.aof --fix
13、如何进行性能测试
redis-benchmark -c 1 –q
14、如何选择合适的持久化方式?
一般来说, 如果想达到足以媲美PostgreSQL的数据安全性, 你应该同时使用两种持久化功能。如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失,那么你可以只使用RDB持久化。
有很多用户都只使用AOF持久化,但并不推荐这种方式:因为定时生成RDB快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比AOF恢复的速度要快。
15、Redis常见性能问题和解决方案?
(1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件
(2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次
(3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内
(4) 尽量避免在压力很大的主库上增加从库
(5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。
(6) 如果是读压力比较大的应用,可以用树型结构,比如1主带2-3从,从再带2-3的二级从...
16、基数估计算法(HyperLogLog)有什么特点和用途?
HyperLogLog 的优点是,即使输入元素的数量或者体积非常非常大,计算基数所需的空间总是固定的、并且是很小的。在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以HyperLogLog 不能像集合那样,返回输入的各个元素。
用途:用于仅仅需要计数(不要求完全精准)的场景。
比如网易音乐歌曲评论的999+之类的场景。还比如统计上亿计的IP、点击等数据,如果用传统的集合需要500GB内存,而用HyperLogLog只需要12kb
17、Redis 的事务中途的命令错误和运行时错误会造成事务回滚吗?
命令错误会,但运行时错误不会。因为Redis的事务没有关系数据库事务提供的回滚(rollback)功能。为此开发者必须在事务执行出错后自己写代码(如事务日志)来处理。
18、写一段Watch实现的线程安全的整形数值自增(加1)的代码
WATCH Somekey
val = GET Somekey
val = val + 1
MULTI
SET Somekey $val
EXEC
19、介绍一下你所知道的分区方式或算法。
1、范围分区
最简单的分区方式是按范围分区,就是映射一定范围的对象到特定的Redis实例。
比如key为:object_ID,ID从0到10000的用户会保存到实例R0,ID从10001到 20000的用户会保存到R1,以此类推。这种方式是可行的,并且在实际中使用,不足就是要有一个区间范围到实例的映射表。这个表要被管理,同时还需要各 种对象的映射表,通常对Redis来说并非是好的方法。
2、哈希分区
另外一种分区方法是hash分区。这对任何key都适用,也无需是object_name:这种形式,像下面描述的一样简单:用一个hash函数将key转换为一个数字,比如使用crc32 hash函数。对key foobar执行crc32(foobar)会输出类似93024922的整数。
对这个整数取模,将其转化为0-3之间的数字,就可以将这个整数映射到4个Redis实例中的一个了。93024922 % 4 = 2,就是说key foobar应该被存到R2实例中。注意:取模操作是取除的余数,通常在多种编程语言中用%操作符实现。
20、如何实现分布式锁?
1、 可以参考这里:https://www.cnblogs.com/linjiqin/p/8003838.html
讲通原则和算法即可。
2、 还可以基于redisson快速实现,见:https://github.com/redisson/redisson/wiki/8.-distributed-locks-and-synchronizers
目前维护的开源产品:https://gitee.com/475660