面试后端开发的职位,相信大家经常被问到有关redis问题。Redis作为缓存系统的代表很有必要弄熟搞懂,无论是在工作当中还是求职面试过程中都是大有裨益的,本文将详细介绍一些redis的一些典型问题,并给出了一些参考解答。
  由于作者水平有限,可能会有存在一些问题,欢迎大家不吝批评指教。文中参考了网友的一些资料,在这里先他们表示感谢。本文全文约4000字,阅读完大概需要10分钟时间。

常见问题

Redis性能为什么高?
单线程的redis如何利用多核cpu机器?
Redis的缓存淘汰策略?
Redis如何持久化数据?
Redis有哪几种数据结构?
Redis集群有哪几种形式?
有海量key和value都比较小的数据,在redis中如何存储才更省内存?
如何保证redis和DB中的数据一致性?
如何解决缓存穿透和缓存雪崩?
如何用redis实现分布式锁?

问题参考列表

Redis性能为什么高?

Redis是key-value存储的nosql数据库,具有以下一些性质,使其性能优异。

  1. 完全基于内存操作,绝大多数操作都在内存中完成,非常高效。
  2. 内部采用多路I/O复用模型,非阻塞式IO。Redis会根据系统情况优先调用高效的IO复用模型,例如linux的epoll多路IO函数;
  3. 数据结构和数据操作简单,redis中的数据结构是专门进行设计的;
  4. 处理请求模块采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
  5. 关于底层模型为了更有效的通讯,redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。

单线程的redis如何利用多核cpu机器?

  Redis的数据读取和处理性能非常强大,对于一般服务器配置,cpu都不会是性能瓶颈。Redis的性能瓶颈主要集中在内存和网络方面。举例来说,运行在一台普通的Linux机器上至少能处理50万并发请求。所以使用的redis命令多为O(N)、O(log(N))时间复杂度,那么基本上不会出现cpu瓶颈的情况。
  但是如果你确实需要充分使用多核cpu的能力,那么需要在单台服务器上运行多个redis实例(主从部署/集群化部署),并将每个redis实例和cpu内核进行绑定来实现充分利用多核CPU。

Redis的缓存淘汰策略?

Redis缓存淘汰策略与Redis键的过期删除策略并不完全相同,前者是在Redis内存使用超过一定值的时候(一般这个值可以配置)使用的淘汰策略;而后者是通过定期删除+惰性删除两者结合的方式进行内存淘汰的。
有六种缓存淘汰策略:

  1. volatile-lru:从已设置过期时间的数据中挑选最近最少使用的数据淘汰;
  2. volatile-ttl:从已设置过期时间的数据中挑选将要过期的数据淘汰;
  3. volatile-random:从已设置过期时间的数据中任意选择数据淘汰;
  4. allkeys-lru:从数据集中挑选最近最少使用的数据淘汰;
  5. allkeys-random:从数据集中任意选择数据淘汰;
  6. no-enviction(驱逐):禁止驱逐数据

注意这里的6种机制,volatile和allkeys都会对已设置过期时间的数据集淘汰数据。allkeys会从全部数据集淘汰数据,后面的lru、ttl以及random是三种不同的淘汰策略,再加上一种no-enviction永不回收的策略。

Redis如何持久化数据?

Redis支持两种数据持久化方式:RDB方式和AOF方式。前者会根据配置的规则定时将内存中的数据持久化到硬盘上,后者则是在每次执行写命令之后将命令记录下来。两种持久化方式可以单独使用,但是通常会将两者结合使用。
1、RDB方式
RDB方式的持久化是通过快照的方式完成的。当符合某种规则时,会将内存中的数据全量生成一份副本存储到硬盘上,这个过程称作”快照”。举例来说,根据配置规则进行自动快照流程:

  • 用户执行SAVE, BGSAVE命令;
  • 执行FLUSHALL命令;
  • 执行复制(replication)。

2、AOF方式
在使用Redis存储非临时数据时,一般都需要打开AOF持久化来降低进程终止导致的数据丢失,AOF可以将Redis执行的每一条写命令追加到硬盘文件中,这一过程显然会降低Redis的性能,但是大部分情况下这个影响是可以接受的,另外,使用较快的硬盘能提高AOF的性能。

Redis有哪几种数据结构?

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

Redis集群有哪几种形式?

redis有三种集群方式:主从复制,哨兵模式和集群。 详细内容参见:Redis集群管理方式

有海量key和value都比较小的数据,在redis中如何存储才更省内存?

可以考虑通过大幅减少key的数量来降低内存的消耗。
实现:在客户端通过分组将海量的key根据一定的策略映射到一组hash对象中,由于value较小,故hash类型的对象会使用占用内存较小的ziplist编码。
例如:如存在100万个键,可以映射到1000个hash中,每个hash保存1000个元素。

如何保证redis和DB中的数据一致性?

大多情况下,缓存策略是:读缓存,读取不到就读数据库然后同步到缓存中。
问题出现场景
在并发访问中,不论是先写库,再删除缓存;还是先删缓存,再写库,都有可能出现数据不一致的情况
1、在并发中是无法保证读写的先后顺序的,如果删掉了缓存还没来得及写库,另一个线程就过来读取发现缓存为空就去数据库读取并写入缓存,此时缓存中为脏数据。
2、如果先写了库,再删除缓存前,写库的线程宕机了,没有删除掉缓存,则也会出现数据不一致情况。
3、如果是redis集群,或者主从模式,写主读从,由于redis复制存在一定的时间延迟,也有可能导致数据不一致。
双删 + 超时
在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。这样最差的情况是在超时时间内存在不一致,当然这种情况极其少见,可能的原因就是服务宕机。此种情况可以满足绝大多数需求。
当然这种策略要考虑redis和数据库主从同步的耗时,所以在第二次删除前最好休眠一定时间,比如500毫秒,这样毫无疑问又增加了写请求的耗时。

如何解决缓存穿透和缓存雪崩?

缓存雪崩:是指缓存同一时间大面积的失效,瞬间请求全落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案:缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。

缓存穿透: 是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。

解决方案

  • 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
  • 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
  • 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap拦截掉,从而避免了对底层存储系统的查询压力

如何用redis实现分布式锁?

在分布式环境下多个不同线程对共享资源进行访问,传统的锁比如Java的锁机制就无法实现了,这个时候就必须借助分布式锁来解决分布式环境下共享资源的同步问题。

为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:

  1. 互斥性。在任意时刻,只有一个客户端能持有锁
  2. 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
  3. 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
  4. 加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。[1]
public class RedisTool {private static final String LOCK_SUCCESS = "OK";private static final String SET_IF_NOT_EXIST = "NX";private static final String SET_WITH_EXPIRE_TIME = "PX";private static final Long RELEASE_SUCCESS = 1L;/*** 尝试获取分布式锁* @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));if (RELEASE_SUCCESS.equals(result)) {return true;}return false;}
}

参考文献
[1]: Redis分布式锁的正确实现方式

欢迎大家关注我的CSDN博客,您的行动就是对我最大的鼓励!

Redis常见面试问题汇总及解析相关推荐

  1. Redis常见客户端异常汇总

    一.无法从连接池获取到连接 JedisPool中的Jedis对象个数是有限的,默认是8个.这里假设使用的默认配置,如果有8个Jedis对象被占用,并且没有归还,如果调用者还要从JedisPool中借用 ...

  2. 面试中 项目遇见的难点答案_你和offer之间只差这几个面试问题!常见面试问题汇总...

    99%的人都会大呼"坑爹"的面试问题,你真的知道该怎么回答吗? 记得第一次面试的时候,面试官对简历也很满意,前面都聊的好好的,最后问了一句简历上没有的内容:你的职业规划是什么?我一 ...

  3. 计算机专业常见面试题目汇总

    机器学习与深度学习常见面试题(上)-知乎 机器学习与深度学习常见面试题(下)-知乎 计算机考研专业课思维导图-知乎 (31条消息)常见C++笔试面试题整理_ljh0302的专栏-CSDN博客_c++面 ...

  4. 新编php找工作常见面试笔试汇总

    今天偶然看到了一篇文章,说是php程序员在找工作当中常见的问题汇总,我觉得不错.特意转来了.收藏. form表单 1.简述 POST 和 GET 传输的最大容量分别是多少? GET 方法提交的表单数据 ...

  5. 大数据常见面试问题汇总

    目录 第1章 核心技术 1.1 Linux&Shell 1.1.1 Linux常用高级命令 1.1.2 Shell常用工具及写过的脚本 1.1.3 Shell中单引号和双引号区别 1.2 Ha ...

  6. html+css常见面试问题汇总

    对WEB标准以及W3C的理解与认识 WEB标准不是某一个标准,而是一系列标准的集合.网页主要由三部分组成:结构(Structure).表现(Presentation)和行为(Behavior).对应的 ...

  7. 漫画 | Redis常见面试问题(二)

    上期,小知和阿音在进行面试问答,可是呢,还没问完小知就表示累了想休息一会,然后就休息去了,但是,以为这样就完了吗? 当然不是,还得继续啊,嘿嘿嘿 注:对于第一种,需要应用程序自己处理资源的同步,可以使 ...

  8. clr 面试_C# 常见面试问题汇总

    1.c#垃圾回收机制 从以下方面入手展开:  1.压缩合并算法   2.代的机制  3.GC调用终结器 Garbage Collector . NET采用了和Java类似的方法由CLR(Common ...

  9. 桌面运维工程师常见面试问题汇总

    第一部分:A卷 1. 加快win10系统开机速度的方法有那些? 2. 目前常用的磁盘分区格式是什么?他们之间有什么区别? 3. 电脑比较多的情况下,快速安装所有电脑的操作系统采用什么方法? 4. BI ...

最新文章

  1. 推荐远程办公的产品软件
  2. iOS load方法和initialize方法的异同
  3. 全国大学生智能猫竞速比赛
  4. python入门经典例题-Python入门经典练习题
  5. 基于OpenResty的弹性网关实践(一)
  6. 对数周期天线hfss建模_HFSS也有金手指,FADDM招式详解
  7. 若依前后端分离前端使用Vue3启动教程
  8. div不占位置_Python爬取校花网,妈妈再也不会担心我不给她发女朋友照片了
  9. 图的绝对中心(bzoj 2180: 最小直径生成树)
  10. 机器学习之路: python 支持向量机 LinearSVC 手写字体识别
  11. 程序猿的道路~~(How to be a programmer?)
  12. VC编程中,判断野指针
  13. 分享Silverlight/WPF/Windows Phone/HTML5一周学习导读(12月5日-12月11日)
  14. python操作redis集群是连接池么_Python如何操作redis使用连接池
  15. 掌握如何使用Rose绘制活动图的方法
  16. 教育行业数据防泄密解决方案
  17. 这台笔记本最适合程序员编程!
  18. [stanford NLP] 原理小结
  19. linux发行版本排行,2020年10种最受欢迎的Linux发行版排名
  20. 【数据集】Kinetics-600 dataset介绍

热门文章

  1. 在Dockerfile中设置G1垃圾回收器参数
  2. 发现服务内存中free部分很小,available部分很大,应该怎么办
  3. eclipse运行maven web项目
  4. pytorch空间变换网络
  5. Jittor 的Op, Var算子
  6. 至强® 平台配备先进遥测技术让您的数据中心更智能
  7. 部署通用基础设施, 满足顶级 SLA 要求
  8. 视频系列:RTX实时射线追踪(上)
  9. 2021年大数据Kafka(七):Kafka的分片和副本机制
  10. Android 自定义View Canvas —— Bitmap