Redis面试题-持续更新

1、什么是Redis?

Redis是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
Redis与其他key-value缓存产品有一下三个特点:

  • redis支持数据的持久化

可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。

  • Redis支持丰富的数据类型

Redis不仅支持简单的key-value类型的数据,同时还提供list、set、zset、hash等数据结构的存储。

  • Redis支持数据的备份

即master-slave模式的数据备份。
Redis优势

  • 性能极高

redis能读的速度是110000次/s,写的速度是81000次/s。

  • 丰富的数据类型

redis支持二进制案例的Strings、Lists、Hashs、Sets及及OrderedSets等数据类型操作。

  • 原子性

Redis的所有操作都是原子性的,意思是要么全部成功,要么失败不执行。单个操作是原子的,多个操作也支持事务,即原子性。通过MULTI 和 EXEC 指令包起来。

  • 丰富的特性

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

2、Redis的数据类型

Redis支持五种数据类型:String、List、Set、Hash、zSet(有序集合)。
  我们实际项目常用的是String和Hash。我们还可以加上下面几种数据结构:
HyperLogLog:是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
Geo:主要用于存储地理位置信息,并对存储的信息进行操作。

geoadd:添加地理位置的坐标。
geopos:获取地理位置的坐标。
geodist:计算两个位置之间的距离。
georadius:根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。
georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。
geohash:返回一个或多个位置对象的 geohash 值。

发布订阅:发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。
Stream:主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。
而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。
BloomFilter:Reids布隆过滤器,布隆过滤器可以判断某个数据一定不存在,但是无法判断一定存在。
  优点:优点很明显,二进制组成的数组,占用内存极少,并且插入和查询速度都足够快。
  缺点:随着数据的增加,误判率会增加;还有无法判断数据一定存在;另外还有一个重要缺点,无法删除数据。

3、Redis相比memcache有什么优势?

Redis数据类型比memcache支持丰富,Redis支持五种数据类型,String、List、Hash、set、zset。而memcache只支持String。
  Redis性能比memcache高。
  Redis数据可以持久化。

4、Memcache与Redis区别有哪些?

区别:
  数据存储方式不同,memcache把数据全部存储在内存中,断电会挂掉造成数据丢失。数据大小不能超过内存大小。而Redis部分数据存在磁盘中,可以进行数据持久化。
  支持的数据类型不同,Memcache支持数据类型比较简单,只支持String,而Redis支持复杂的数据类型。
  使用底层模型不同,它们之间底层实现方式以及客户端之间通信应用协议不同。Redis直接自己构建了VM机制,因为一般的系统调用系统函数会浪费一定的时间移动和请求。

5、Redis是单进程单线程的?

Redis是单进程单线程的,redis利用队列技术将并发访问变成串行访问,消除了传统数据库串行的开销。

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

512M。

7、Redis的持久化机制是什么?各自有什么优缺点?

Redis提供两种持久化机制,分别是RDB和AOF;
  RDB(Redis DataBase)持久化方式:是指用数据集快照的方式半持久化默认。记录Redis数据库中所有的键值对,在某时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件;达到数据恢复。
  优点:
1、只有一个文件dump.rdb,方便持久化。
2、容灾性好,一个文件可以存到安全的磁盘上。
3、性能最大化,fork子进程来完成写操作,让主进程继续处理命令,所以是IO最大化。使用子进程来进行持久化,主进程就不会进行任何IO操作了,保证了Redis高性能。
4、相对于数据集大时,比AOF的启动效率更高。
  缺点:
1、数据安全性低,RDB是间隔一段时间进行持久化的,如果持久化之间redis发生了故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候使用。
  AOF(Append-only-file)持久化方式:是指所有的命令行记录以redis命令请求协议格式完全持久化存储,保存为aof文件。
  优点:
1、数据安全,aof可以持久化配置appendfsync属性,有always,每进行一次命令操作就记录到aof文件中一次。
2、通过append模式写文件,即使中途服务器宕机,可以通过redis-check-aof工具,解决数据一致性问题。
3、AOF机制的rewrite 模式。AOF文件没有被rewrite前,可以删除其中的某些命令。
  缺点:
1、AOF文件比RDB文件大,且恢复速度慢。
2、数据集大的时候,比rdb启动效率低。

8、Redis常见的性能问题和解决方法?

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

9、Redis 过期键的删除策略?

1、定时删除:在设置键的过期时间的同时,创建一个定时器 timer). 让定时器在键的过期时间来临时, 立即执行对键的删除操作。
2、惰性删除: 放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是 否过期,如果过期的话, 就删除该键;如果没有过期, 就返回该键。
3、定期删除:每隔一段时间程序就对数据库进行一次检查,删除里面的过期键。至 于要删除多少过期键, 以及要检查多少个数据库, 则由算法决定。

10、Redis的回收策略(淘汰策略)?

volatile-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:禁止驱逐,
使用策略:
  如果数据呈幂规律分布,也就是一部分访问频率高,一部分访问频率低,则使用allkeys-lru策略。
  如果数据呈现平等分布,也就是数据访问的频率都相同,则使用allkeys-random策略。

11、为什么Redis把所有数据都放到内存中?

Redis为了达到最快的读写速度,将数据都读取到内存中,并通过异步方式将数据写入磁盘中。所以Redis具有快读和持久化的特性。如果将数据不放在内存中,磁盘的IO速度严重影响性能。在内存越来越便宜的今天,redis将会越来越受欢迎。

12、Redis的同步机制了解吗?

Redis可以使用主从同步,从从同步。第一次同步时,主节点做一次bgSave,并同时将后续修改操作记录到内存buffer中,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。加载完成后,在通知主节点将期间修改的操作记录同步到复制节点进行重放,就完成了同步过程。

13、pipeline有什么好处,为什么要用pipeline?

可以将多次往返IO时间缩短为一次,前提是pipeline执行的命令之前没有因果关系。使用redis-benchmark进行压缩的时候可以发现影响redis的QPS峰值的一个重要因素是pipeline 批次指令的数目。

14、是否使用过redis集群,它们的原理是什么?

1、Redis Sentinal 适用于高可用,在master宕机时会自动将slave提升为master,继续提供服务。
2、Redis Cluster 使用于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。

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

有A、B、C三个节点的集群,在没有复制模式的情况下使用,如果B节点失败了,那么整个集群就会以为少5501-11000这个范围的槽而不可用。

16、Jedis与Redisson对比有什么优缺点?

jedis是Redis的Java客户端,其API提供了比较全面的Redis命令的支持;
Redisson实现了分布式和可扩展的Java数据结构,和Jedis相比,功能比较简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。
Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。

17、说说Redis哈希槽的概念?

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

18、Redis 集群的主从复制模型是怎样的?

为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有N-1个复制品。

19、Redis集群最大节点个数是多少?

16384个。16384 / 8 / 1024 = 2K,如果槽数太多,导致心跳发送请求过大。

20、Redis 如何做内存优化?

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

21、Redis 回收进程如何工作的?

一个客户端运行了新的命令,添加了新的数据。Redi检查内存使用情况,如果大雨maxmemory的限制,则根据设定好的策略进行回收。一个新的命令被执行,等等。所以我们不断的穿越内存限制的边界,通过不断达到边界然后不断地回收到边界一下。如果一个命令的结果导致大量内存被使用,不用多久内存限制就会被这个内存使用量超越。

22、Redis的内存用完了会发生什么?

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

23、MySql里面有200W数据,redis中只能存储20W数据,如何保证redis中的数据都是热点数据?

Redis内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略,使用URL数据淘汰策略,保留下热点数据。

24、Redis 最适合的场景?

1、会话缓存(Session Cache)
  最常用的一种使用Redis的情形是会话缓存。用Redis缓存会话比其他存储的优势在于:Redis提供持久化。当维护一个不是严格要求一致性缓存时,如果用户购物车信息全部丢失,大部分人都会不高兴的。所以恰当的使用Redis来缓存会话。
2、全页缓存(FPC)
  除了基本的会话缓存外,Redis还提供简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大的改进。
3、队列
4、排行榜/计数器
  Redis在内存中对数字进行递增或递减的操作实现的非常好。通常使用(Set)和有序集合(Sorted Set)。
5、发布/订阅

25、假如Redis里面有1亿个key,其中有10W个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?

使用keys指令可以扫出指定模式的key列表。如果使用keys指令,因为redis的单线程的。
  keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。

26、如果有大量的Key需要设置同一时间过期,一般需要注意什么?

如果大量的key过期时间设置过去集中,到过期的那个时间点,redis 可能会出现短暂的卡顿,并造成缓存雪崩对数据库造成巨大压力,甚至宕机。一般需要在时间上加个随机值,使得过期时间分散些。

27、Redis做分布式锁

/**
     * 尝试获取分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {

        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;

    }

解锁代码:

/**
     * 释放分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {

        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
        # eval命令执行Lua代码的时候,Lua代码将被当成一个命令去执行,并且直到eval命令执行完成,Redis才会执行其他命令。
        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;

    }

更多内容请查看 Julywhj的博客期待您的光顾。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Julywhj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值