Redis 的数据类型(数据结构)

  1. string (二进制安全,可以存储任意类型的数据)
  2. list(链表)
  3. 字典(就是hashmap)
  4. set(不重复无序的hashmap)
  5. zset(按照给定的 score 排序的 set)
  6. HyperLogLog(来做基数统计的算法,简介)
  7. Geo(支持地理位置的操作,使用简介)
  8. Pub/Sub
  9. BloomFilter
  10. RedisSearch
  11. Redis-ML

缓存雪崩(缓存击穿)

他们出现的原理都是访问缓存的时候,key 刚好失效,导致直接访问 DB,压垮后台。

解决办法就是让 key 的过期时间分散开,不要集中失效

分布式锁

使用 setnx 命令后为了防止死锁,需要对 key 施加 expire 命令,防止死锁,但是存在执行 expire 命令前宕机,造成死锁的发生。

解决办法就是使用复杂的 setnx 命令,他可以把 setnx 和 expire 一起原子执行

如何寻找有固定前缀的 key

使用 KEYS pattern 命令,如:KEYS alib*

但是因为 Redis 是单线程的,执行该命令后会导致 Redis 阻塞住。

解决办法就是使用 scan 命令,scan 命令可以无阻塞的提取出指定模式的 key 列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用 keys指令长

scan 命令的特点:

Redis中的Scan命令的使用 - MSSQL123 - 博客园​www.cnblogs.com

如何用 Redis 做异步队列

使用 list 数据结构,在一遍加入,另一边取出,若取出来的是 null,则消费线程应该 sleep,或者消费线程不使用 lpop 或 rpop 命令,改为 blpop 或者 brpop 命令,若没有元素可取,它会阻塞列表直到等待超时或发现可弹出元素为止。

如何生产一次,消费多次

使用发布订阅模式

但是在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如 rabbitmq

Redis 如何实现延时队列

使用 zset ,用时间戳作为 score,消息会按照时间顺序排序

然后使用 zrangebyscore key min max [WITHSCORES] [LIMIT offset count] 来取出比当前时间小的 key 的 value

持久化

Redis 4.0 时代以 RDB 为主,AOF 只记录上一次 RDB 到现在的更改记录

开启混合持久化:aof-use-rdb-preamble yes

工作原理:其实还是一种 AOF 机制,但是新增了 RDB 的特性,先看此模式下的 AOF 的数据结构图

  • 看图就知道混合模式指的就是重写 AOF 的时候,将此刻内存里面的数据做成 RDB,在此过程中增量的数据写入到缓冲区,最终形成新的 aof 文件。接着删除旧的 AOF。
  • 重启恢复时先恢复 RDB,再重放新增的 AOF 指令

持久化的意义在于故障恢复

  • AOF:记录每一次的写操作到日志上,重启时重放日志以重建数据

    • 每隔一段时间调用系统的 fsync 函数强制将 os cache 里面的数据刷新到磁盘上
  • RDB:每隔一段时间保存一次当前时间点上的数据快照
    • 快照就是一次又一次地从头开始创造一切,全量的

持久化如何工作的

关键词:写时复制和 fork 子进程

  • 每当 Redis 需要转储数据集到磁盘时,会发生:

    • Redis 调用 fork()。于是我们有了父子两个进程。
    • 子进程开始将数据集写入一个临时 RDB / AOF 文件。
    • 当子进程完成了新 RDB 文件,替换掉旧文件。
    • AOF 的 fork(),与 RDB 不同的是父进程会在一个内存缓冲区中积累新的变更,同时将新的变更写入新的 AOF 文件,所以即使重写失败我们也安全。当子进程完成重写文件,父进程收到一个信号,追加内存缓冲区到子进程创建的文件末尾,接着自动重命名文件为新的,然后开始追加新数据到新文件
  • 这个方法可以让 Redis 获益于写时复制(copy-on-write)机制

AOF 为什么要重写

AOF 记录的是 Redis 的每一次变更,这个变更包含了大量的冗余操作,导致 AOF 体积变大,恢复缓慢。

通过重写这个体积大的 AOF 文件,可以实现新的 AOF 文件不会包含任何浪费空间的冗余命令,通常体积会较旧 AOF 文件小很多。

Pipeline

将多个指令一起发送,减少 IO,提高吞吐量

Redis 的同步机制

Redis 可以使用主从同步,从从同步。

第一次同步时,主节点做一次 bgsave,并同时将后续修改操作记录到内存 buffer,待完成后将 RDB 文件全量同步到复制节点,复制节点接受完成后将 RDB 镜像加载到内存。

加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。后续的增量数据通过 AOF 日志同步即可,有点类似数据库的 binlog

Redis 集群

Redis Sentinal 着眼于高可用,在 master 宕机时会自动将 slave 提升为 master,继续提供服务。

Redis Cluster 着眼于扩展性,在单个 redis 内存不足时,使用 Cluster 进行分片存储。

Redis 的通讯协议是什么

答案是文本协议

虽然文本协议耗费流量,但是解析性能很好

Redis 的事务

首先 Redis 支持事务,但是它的事务与MySQL这类传统的数据库的事务不同,不同点为:

  1. 通过 MULTI 开启事务(类似于MySQL的 STARTtransaction; 命令)
  2. 通过 EXEC 命令触发事务(类似于MySQL的 COMMIT; 命令)
  3. 执行事务的时候放入事务队列里面的命令都会被执行,不管是否有命令执行时出错
  4. Redis 的事务可以理解为打包的批量执行脚本,所以不支持原子性,失败了可以继续执行完,也不会回滚
  5. 但是单个的Redis命令是原子的

具备隔离性:Redis 因为是单线程操作,所以在隔离性上有天生的隔离机制,当 Redis 执行事务时,Redis 的服务端保证在执行事务期间不会对事务进行中断,所以,Redis 事务总是以串行的方式运行,事务也具备隔离性。

不具备一致性:虽然开启持久化之后可以在数据出现问题是恢复到之前的状态,但是因为Redis的事务不是原子性的,不会回滚数据,Redis设计时也没有考虑ACID特性,所以认为Redis不具备一致性

持久性:开启持久化就支持,不开启就不支持

Redis 的乐观锁 Watch 是怎么实现的

Watch 会在事务开始之前盯住 1 个或多个关键变量,如下图:

当事务执行时,也就是服务器收到了 exec 指令要顺序执行缓存的事务队列时, Redis 会检查关键变量自 Watch 之后,是否被修改了。

上图显示,watch abc 之后执行事务之前,执行了一次 incr 操作,所以在 exec 的时候失败,watch 的实现原理不是 CAS 中的 Cmpxchg 指令,而是借助 Redis 的单线程执行机制,采用了 watched_keys 的数据结构和串行流程实现了乐观锁,具体解释就是:

每一个被 watch 的 key 都会被构造成一个 watched_keys 数据类型,多个被 watch 的 key 构造成链表存储着假设客户端 A 和 B 都 watch abc
但是并发时 Redis Server 中只会有一个线程在执行,
当 A 修改了 watch 命令监视的 key 后,会改变 abc 的 watched_keys 的状态为 dirty,
客户端 B 会检查这个被 watch 的 abc,发现他的状态是 dirty 的时候就会终止事务

Redis 如何节省内存

关键词:ziplist、quicklist、对象共享

Ziplist 是一个紧凑的数据结构,每一个元素之间都是连续的内存,如果在 Redis 中,Redis 启用的数据结构数据量很小时,Redis 就会切换到使用紧凑存储的形式来进行压缩存储

Quicklist 是 ziplist 的双向链表版本,可以在两端执行 push 和 pop 操作

对象共享:指的就是多个key的value是一样的话,就把多个key指向同一个value即可,如下图:

A和B都指向值100,则A、B 共用同一个100对象

Redis 的过期策略

  1. 定时删除:创建一个定时器,让定时器在键过期时来执行删除

    1. 对CPU不友好
    2. 影响性能
  2. 定期删除:每隔一段时间,程序都要对数据库进行一次检查,删除里面的过期键,至于要删除多少过期键,由算法而定。
    1. 要么对 CPU 不友好
    2. 要么对内存不友好
  3. 惰性删除:get Key 的时候才检查是否过期,过期了就删除返回 null
    1. 对内存不友好
    2. 可能导致内存溢出

Redis 同步策略

最简单的架构模式就是:一台 master 和多个 slave

仅 master 开启持久化策略,负责写入操作,slave 只负责读取操作

同步的目的就是为了【读写分离】和【容灾备份】

同步的过程:

  1. slave 发送 SYNC 给 master
  2. master 接收到命令后一边缓存继续写入的命令,一边 fork 子进程生成 RDB 文件
  3. 子进程写完 RDB 之后,父进程把 RDB 发送给 slave,slave 接收 RDB 并重现数据
  4. 父进程增量地将缓存的写命令发送给 slave

Redis 为什么是单进程单线程的

注意:这里的单线程指的是处理 I/O 事件是单线程的,并发的请求进入 Redis 后会排队,只有上一个处理完了,才会继续处理下一个。

注意:Redis 可不完全是单进程的,开启持久化的时候,会 fork 子进程完成 RDB/AOF 的创建

Redis 的线程模型
命令处理过程

我们所谓的多线程操作是为了加快计算,所以开启多个线程同步操作,而这会耗费大量的 CPU 资源。

Redis 设计之初就是纯内存运行,计算速度够快了,若再使用多线程操作的话会因为线程管理问题以及上下文切换耗时,反而会降低性能。Redis 官方测试中一台普通的笔记本电脑没鸟的QPS可达十几万,所以目前来看没有必要使用多线程。

客户端获取 value 阻塞时,却不会影响后面的命令的执行

Redis 为什么这么快

  1. 纯内存运行
  2. 单线程(这个单线程指的是处理命令的时候只有一个线程执行,其他的命令加入队列阻塞)
  3. 数据结构简单,使用专门的数据结构存储数据
    1. 例如:ZSet 使用跳表存储
    2. 字符串使用 SDS(Simple Dynamic String)的结构体保存(该结构体可以存储字符串的长度,还能防止字符串溢出,实现二进制存储安全等特性)
    3. 哈希表用的是字典,且通过两个 ht 实现渐进式 rehash(有利于加快Redis响应效率)
    4. 还有通过 ZipList、QuickList 来压缩内存
  4. 非阻塞的 I/O 多路复用模型:用一个线程管理多个网络连接
    1. epoll
    2. React 线程模型

谈一下 Redis 的哈希槽

Redis 集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现分区(因为一致性哈希开销很大)

数据分片就是用到了16384个槽,槽里面可存多个key

集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽

也就是说整个集群里面不管有几台机器,只有 16384 个槽,集群把槽分配给全部的实例,每个实例管理一部分的槽,如图:

扩容、缩容都要涉及槽的迁移;扩容后要给新机器分配槽、缩容后要分配被释放的槽给其他节点。

传统的一致性哈希

后知后觉:面试必备:什么是一致性Hash算法?​zhuanlan.zhihu.com

为什么redis取出来是null_[2020] Redis 最新面试题相关推荐

  1. 2020前端最新面试题总结(js、html、小程序、React、ES6、Vue、算法、全栈热门视频资源)(3年前端菜鸟级开发师含泪总结)

    2020前端最新面试题总结(js.html.小程序.React.ES6.Vue.算法.全栈热门视频资源) 文档描述 (今年确实挺难 3年前端菜鸟级开发师含泪总结 希望能帮助大家) 本文是关注微信小程序 ...

  2. 2020前端最新面试题(vue篇)

    2020前端最新面试题(vue篇) 由于疫情原因,原本每年的"金三银四"仿佛消失,随之而来的是找工作的压力,这里给要面试的小伙伴们总结了到目前为止我遇到的前端面试题,仅供参考哦,第 ...

  3. 为什么redis取出来是null_跳表:为什么Redis一定要用跳表来实现有序集合

    上两节我们讲了二分查找算法.当时我讲到,因为二分查找底层依赖的是数组随机访问的特性,所以只能用数组来实现.如果数据存储在链表中,就真的没法用二分查找算法了吗? 实际上,我们只需要对链表稍加改造,就可以 ...

  4. 2020 阿里最新面试题,掌握这些轻松拿offer

    阿里巴巴不用我多说了吧,旗下有阿里云.蚂蚁金服.菜鸟网络.支付宝等都属阿里旗下,以上这些企业面试题都不太一样,但是面试流程基本上是差不多的,今天我主要说一下Java后端方向岗位. 面试开始会让自我介绍 ...

  5. 项目总结10:通过反射解决springboot环境下从redis取缓存进行转换时出现ClassCastException异常问题...

    通过反射解决springboot环境下从redis取缓存进行转换时出现ClassCastException异常问题 关键字 springboot热部署  ClassCastException异常 反射 ...

  6. 2020年最新Redis面试题

    什么是Redis Redis(Remote Dictionary Server) 是一个使用 C 语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对数据库. Redis 可以存储键和 ...

  7. redis取mysql数据类型_redis数据类型操作

    redis数据类型操作 一.value exists key:测试指定的key是否存在,1表示存在,0表示不存在 del key1 key2 ...keyN: 删除指定的key type key: 返 ...

  8. linux的iso镜像机没有redis,在Linux系统上安装Redis【避坑篇】

    redis官网下载地址,当前稳定版本是6.0.0. redis的下载 具体下载方式依照当前网页下面提供的命令即可: # 下载及安装 wget http://download.redis.io/rele ...

  9. 关于redis的几件小事(一)redis的使用目的与问题

    1.redis是用来干嘛的? Redis is an open source (BSD licensed), in-memory data structure store, used as a dat ...

最新文章

  1. wamp php非线程安全,wampserver PHP多版本切换
  2. ERP顾问的三层境界
  3. 解决安装rrdtool遇到的一个问题
  4. react全局状态管理_react 状态管理的复杂度来源
  5. 重读经典:《ImageNet Classification with Deep Convolutional Neural Networks》
  6. python的repr和str有什么不同_str()和repr()的异同
  7. 腾讯云实验之Linux 基础入门
  8. python使用-Python 应该怎么去练习和使用?
  9. kafka查看消费位置
  10. 总线接口与计算机通信(三)UART起止式异步通用串行数据总线
  11. 30个免费网页设计模板
  12. 2021 RoboCup机器人中国赛大学组比赛即将开始 智能佳为您提供适合的比赛平台
  13. vue项目调用企业微信扫码权限skd,js-sdk
  14. JS实现一个打点计时器
  15. outlook html 格式签名,Outlook HTML电子邮件签名
  16. (附源码)springboot应用支撑平台和应用系统 毕业设计 984655
  17. 地图比例尺、地图分辨率、屏幕分辨率浅析
  18. VR演示室设备使用说明
  19. 多相机拍照系统3D拍照建模,3D真人手办,博物馆模型制作
  20. 嵌入式开发学习之--RCC(下)

热门文章

  1. 玩转 Linux 常用命令
  2. full join 和full outer join_多表关联:公式展开、join、过滤条件的顺序
  3. Python eval 与 exec 函数 - Python零基础入门教程
  4. java map清除值为null的元素_Java中的集合框架大总结
  5. hook控制浏览器的方法_Java-Hook技术-入门实践+反射、动态代理、热修复再看看
  6. ckeditor java 上传_java使用CKEditor实现图片上传功能
  7. oracle display set,Check if the DISPLAY variable is set
  8. html5怎么改为vue_Vue实战——编程式导航打开新窗口,登录状态本地存储
  9. datax oracle mysql_从 MySQL 到 Lindorm时序引擎 的数据迁移
  10. matlab 动态分配内存,[Matlab科学计算之高效编程] 1. 预分配内存