1、Redis 简介

  • 是一个用 C 语言开发的,高性能的键值对数据库。
  • 数据存在于内存,读写速度快。
  • 可用来做缓存、分布式锁、消息队列。
  • 提供多种数据类型来支持不同的业务场景。
  • 支持事务、持久化、Lua 脚本、多种集群方案。

2、Redis 与 Memcached 对比

共同点:

  • 都是基于内存的数据库,常用来做缓存。
  • 都有过期策略。
  • 性能都非常高。

区别:

  • Redis 支持多种数据类型;而 Memcached 只支持 string。
  • Redis 支持数据持久化;而 Memcached 不支持。
  • Redis 有灾难恢复机制(通过加载持久化数据实现);而 Memcached 没有。
  • Redis 内存不足时,可以将不用的数据放到磁盘上;而 Memcached 会直接报异常。
  • Redis 原生支持集群模式;而 Memcached 没有原生的集群模式,需要客户端实现。
  • Redis 使用单线程、IO 多路复用的网络模型(Redis 6.0 引入了多线程 IO);而 Memcached 使用多线程、非阻塞 IO 复用的网络模式。
  • Redis 支持发布订阅模型、Lua 脚本、事务等功能;而 Memcached 不支持。
  • Redis 过期数据的删除策略使用了惰性删除和定期删除;而 Memcached 只用了惰性删除。

3、为什么要用 Redis

  • 高性能:Redis 的数据存在于内存,读写速度快。
  • 高并发:单机情况下,MySQL 这类数据库 QPS 在 1w 左右(4 核 8G),而 Redis 可达到 10w+,甚至 30w+。

4、Redis 数据类型

  • string:简单动态字符串(SDS)。

    • 常用命令:set、get、strlen、decr、incr、setex 等。
    • 应用场景:需要计数的场景,比如用户访问量、文章转发量等。
  • list:双向链表。
    • 常用命令:lpush、rpop、rpush、lpop、lrange、llen 等。
    • 应用场景:发布订阅(即消息队列)。
  • hash:类似 Java 的 HashMap,底层为数组 + 链表。
    • 常用命令:hset、hget、hexists、hkeys、hvals 等
    • 应用场景:存储对象数据。
  • set:类似 Java 的 HashSet,无序、去重,可实现交集、并集、差集的操作。
    • 常用命令:sadd、spop、smembers、sismember、scard、sunion 等。
    • 应用场景:需要存放的数据不能重复、需要获取多个数据源的交集、并集、差集。
  • sorted set(zset):和 set 相比,增加了一个权重参数 score,能够按 score 进行排序。类似 Java 的 TreeSet,有序、去重。
    • 常用命令:zadd、zcard、zscore、zrange、zrevrange 等。
    • 应用场景:需要根据某个权重进行排序的场景,比如直播系统中的礼物排行榜、消息弹幕等。

5、Redis 单线程模型

  • Redis 基于 Reactor 模式来开发自己的网络事件处理器,这个处理器被称为文件事件处理器。
  • 由于文件事件处理器是单线程的,所以我们一般都说 Redis 是单线程模型。
  • Redis 通过 IO 多路复用来监听多个客户端连接(或者说监听多个 socket)。
  • 文件事件处理器主要包含四个部分:
    • 多个 socket:客户端连接。
    • IO 多路复用程序:支持多个客户端连接的关键。
    • 文件事件分派器:将 socket 关联到相应的事件处理器。
    • 事件处理器:连接应答处理器、命令请求处理器、命令回复处理器。

6、Redis 单线程为什么那么快

  • 数据存在于内存,读写速度快。
  • 单线程操作,避免了死锁、上下文切换带来的性能开销。
  • 采用非阻塞 IO 多路复用机制。

7、Redis 6.0 之前为什么使用单线程

  • 单线程编程容易,并且更容易维护。
  • Redis 的性能瓶颈不在 CPU,主要在内存和网络。
  • 多线程存在死锁、线程上下文切换等问题,甚至会影响性能。

8、Redis 6.0 之后为何引入了多线程

  • 为了提高网络 IO 读写性能。
  • Redis 只在网络数据读写这类耗时操作上使用了多线程,执行命令仍然是单线程顺序执行,因此不需要担心线程安全问题。

9、Redis 如何判断数据是否过期

  • 通过过期字典(hash 表)保存数据过期时间。
  • 过期字典的键指向 Redis 中的某个键,过期字典的值保存了数据的过期时间(毫秒精度的时间戳)。

10、Redis 过期数据的删除策略

  • 定时删除:设置过期时间时,同时创建一个定时器,定时器会在过期时间到来时自动删除过期数据。节约内存,但 CPU 压力大。
  • 定期删除:每隔一段时间抽取一批数据进行过期检查。内存、CPU 压力都不是很大。
  • 惰性删除:在取出数据时进行过期检查。节约 CPU 性能、但内存压力大。

Redis 采用定期删除 + 惰性删除。但仍会漏掉某些过期数据,可能导致大量过期数据堆积在内存,从而导致内存溢出,Redis 通过内存淘汰机制来解决这个问题。

11、Redis 内存淘汰机制

  • volatile-lru(least recently used):从已设置过期时间的数据中,淘汰最近最少使用的数据。
  • volatile-ttl:从已设置过期时间的数据中,淘汰将要过期的数据。
  • volatile-random:从已设置过期时间的数据中,随机淘汰数据。
  • allkeys-lru(least recently used):从所有数据中,淘汰最近最少使用的数据。
  • allkeys-random:从所有数据中,随机淘汰数据。
  • noeviction:禁止淘汰数据,内存不足时直接报错。

4.0 版本后增加两种:

  • volatile-lfu(least frequently used):从已设置过期时间的数据中,淘汰最不经常使用的数据。
  • allkeys-lfu(least frequently used):从所有数据中,淘汰最不经常使用的数据。

12、Redis 持久化机制

  • RDB 持久化:默认方式,将某个时刻内存中的数据以快照的形式保存在磁盘上。文件小、恢复速度快,对性能影响小,但是实时性差。
  • AOF 持久化:以日志的方式将每一条写命令保存到磁盘的文件上。文件大、恢复速度慢,对性能影响大,但是实时性高。目前 Redis 持久化的主流方式。
    • 一般设置为每秒同步一次 AOF 文件:appendfsync 选项设置为 everysec。
    • AOF 重写(bgrewriteaof 命令):将内存中的数据以命令的方式保存到新的 AOF 文件中,然后用新的 AOF 文件替换旧的 AOF 文件。

13、Redis 事务

  • 相关命令:

    • MULTI:开启事务。
    • EXEC:执行事务中的所有命令。
    • DISCARD:取消事务,放弃执行事务中的所有命令。
    • WATCH:监听一个或多个 key,如果事务在执行前,监听的 key 被其他命令修改,则中断事务,不会执行事务中的任何命令。
    • UNWATCH:取消 WATCH 对所有 key 的监听。
  • 使用 MULTI 命令后可输入多个命令,Redis 不会立即执行这些命令,而是会放到队列中,等调用 EXEC 命令后再原子化执行这些命令。
  • Redis 不支持回滚,因此不满足原子性。
  • 当 Redis 运行在 AOF 持久化模式下,并且 appendfsync 选项设为 always 时,具有持久性。

14、Redis 集群(多机)

  • 主从模式:主库(master)负责读写,从库(slave)负责读。不具备高可用。

    • master 挂了,不影响 slave,只是不再提供写服务。
    • master 挂了,不会在 slave 中选一个 master。
  • 哨兵(Sentinel)模式:通过 sentinel 进程监视 master、slave 的运行状态。
    • 哨兵模式是建立在主从模式的基础上。
    • 为了避免 sentinel 挂掉,一般会做 sentinel 集群。并且不和 master、slave 部署在同一台机器。
    • sentinel 会每秒向 master、slave 以及其他 sentinel 实例发送一个 PING 命令,以监视其运行状态。
    • master 挂了,sentinel 会在 slave 中选一个 master,并修改所有实例的配置。
    • master 重启后,将作为 slave 运行。
  • 集群(Cluster)模式:Redis 提供的分布式数据库方案。该模式是为了解决单机 Redis 容量上限的问题,它通过分片来进行数据共享。
    • 由多个节点组成,每个节点包含一主一从(或一主多从),从库仅作为备用。
    • 客户端可以连接任一节点的主库进行读写。
    • 集群的整个数据库被分为 16384 个槽(slot),当存储一个 key-value 时,会被分配在某个槽上。

15、缓存穿透

  • 大量请求不存在缓存中的 key,导致请求落在数据库上。
  • 解决办法:
    • 拦截非法 key:拦截所有一定不存在数据的 key。一般采用布隆过滤器。
    • 缓存空值:即使查询结果为空,也将这个空结果缓存,但设置一个较短的过期时间。

16、缓存雪崩

  • 大量缓存在同一时间失效,或者一些被大量访问的缓存(热点缓存)在某一时刻失效,导致大量请求落在数据库上。
  • 解决办法:
    • 设置不同的过期时间。
    • 限流,避免同时处理大量请求。
    • 设置热点缓存永不失效。

交流区



微信公众号:惊却一目

个人博客:惊却一目

Reference

[1] https://snailclimb.gitee.io/javaguide-interview/#/./docs/d-2-redis

[2] https://blog.csdn.net/miss1181248983/article/details/90056960

[3] 《Redis 设计与实现》

Redis 面试必备知识点的更多相关文章

  1. java面试必备知识点-上中下三篇写的很详细

    参考博客:写的还是相当的经典 http://www.cnblogs.com/absfree/p/5568849.html 上中下三篇写的很详细 http://blog.csdn.net/riverfl ...

  2. 金九银十跳槽高峰,面试必备之 Redis + MongoDB 常问80道面试题

    前言 有着“金九银十”之称的招聘旺季已经开启,跳槽高峰期也如约而至. 本文为主要是 Redis + MongoDB 知识点的攻略,希望能帮助到大家. 内容较多,大家准备好耐心和瓜子矿泉水. Redis ...

  3. 可能是全网最好的MySQL重要知识点 | 面试必备

    可能是全网最好的MySQL重要知识点 | 面试必备  mp.weixin.qq.com 点击蓝色“程序猿DD”关注我 回复“资源”获取独家整理的学习资料! 标题有点标题党的意思,但希望你在看了文章之后 ...

  4. 【面试必备】常见Java面试题大综合

    一.Java基础 1.Arrays.sort实现原理和Collections.sort实现原理答:Collections.sort方法底层会调用Arrays.sort方法,底层实现都是TimeSort ...

  5. Python自动化面试必备 之 你真明白装饰器么?

    Python自动化面试必备 之 你真明白装饰器么? 装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率如虎添翼,所以这也是Python面试中必问的问题,但对于好多小白来讲,这个功能 有点绕 ...

  6. 【并发编程】一文带你读懂深入理解Java内存模型(面试必备)

    并发编程这一块内容,是高级资深工程师必备知识点,25K起如果不懂并发编程,那基本到顶.但是并发编程内容庞杂,如何系统学习?本专题将会系统讲解并发编程的所有知识点,包括但不限于: 线程通信机制,深入JM ...

  7. Redis面试热点之底层实现篇

    通过本文你将了解到以下内容: Redis的作者.发展演进和江湖地位 Redis面试问题的概况 Redis底层实现相关的问题包括:常用数据类型底层实现.SDS的原理和优势.字典的实现原理.跳表和有序集合 ...

  8. MySQL数据库之大厂面试必备技能v8.0.27

    概述 **本人博客网站 **IT小神 www.itxiaoshen.com 定义 MySQL官方地址 https://www.mysql.com/ MySQL 8系列最新版本为8.0.27,5系列的最 ...

  9. 李洪强iOS经典面试题156 - Runtime详解(面试必备)

    李洪强iOS经典面试题156 - Runtime详解(面试必备)   一.runtime简介 RunTime简称运行时.OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制. 对于C ...

随机推荐

  1. C#实现JWT无状态验证的实战应用

    前言 本文主要介绍JWT的实战运用. 准备工作 首先我们创建一个Asp.Net的,包含MVC和WebApi的Web项目. 然后使用Nuget搜索JWT,安装JWT类库,如下图. 设计思路 这里我们简单 ...

  2. 剑指 Offer 66. 构建乘积数组 + 思维

    剑指 Offer 66. 构建乘积数组 Offer_66 题目描述 题解分析 java代码 package com.walegarrett.offer; /** * @Author WaleGarre ...

  3. [00]数字图像处理-matlab速成

    原本听的是mooc武汉大学的数字图像处理课程,但是无奈老师读ppt的能力太强,不太适应,后面的课程对于实验方面的要求甚低,无奈之下到处找课程,终于找到了一个适合自己的教程<王伟强-数字图像处理& ...

  4. Reincarnation Without New Body(RWNB): Basic Theory and Baseline 现世转生基本理论及简单操作

    Abstract 投胎学是一门高深的学问,不仅没有现存的理论,也没有过往的经验.根据种种猜测,投胎后前世的记忆也不能保留,造成了很大的不方便.在本文中,我们绕过了投胎需要"来世"的 ...

  5. Java安全初学之反射

    前言: 复现fastjson的时候深深意识到了需要好好学习一下Java和Java安全,激情的学习了一番java安全中重要的几部分:反序列化.反射.rmi.动态代理,从反射开始做个总结. 反射:java ...

  6. 记录 Allsec 解题过程

    开局打开URL:http://119.3.191.245:65532/#/allsecPlayGame,前去做游戏 游戏URL:http://119.3.191.245:8877/Login.php ...

  7. 优化自动化测试流程,使用 flask 开发一个 toy jenkins工具

    1.自动化 某一天你入职了一家高大上的科技公司,开心的做着软件测试的工作,每天点点点,下班就走,晚上陪女朋友玩王者,生活很惬意. 但是美好时光一般不长,这种生活很快被女主管打破.为了提升公司测试效率, ...

  8. C# 基础 - 堆栈跟踪使用

    使用一:可用于捕获报错时. using System.Diagnostics; ... StackTrace st = new StackTrace(true); string stackIndent ...

  9. go beego框架与python实现数据交互

    目标:将go中一个二维数组传到pythone中处理并返回.难点在于数据格式的转换. go代码如下: package main import ( "os/exec" "sy ...

  10. [换根DP][倍增]luogu P5666 树的重心

    题面 https://www.luogu.com.cn/problem/P5666 分析 对于一棵以i为根的树来说,它的重心必然在其size大于等于sumsize/2的子树中. 那么断掉一条边e(u, ...