阿里P9架构师分享:通俗易懂Redis原理,都是你没看过的

前言redis 是如今互联网技术架构中,使用最广泛的缓存 。支持复杂的数据结构,支持持久化,支持主从集群,支持高可用,支持较大的value存储...

阿里P9架构师分享:通俗易懂Redis原理,都是你没看过的

文章插图
 
同时,Redis 也是中高级后端工程师技术面试中,面试官最喜欢问的问题之一 。特别是那些优秀的、竞争激烈的大厂,通常要求面试者不仅仅掌握 Redis 基础使用,更要求深层理解 Redis 内部实现的细节原理 。毫不夸张地说,能把 Redis 的知识点全部吃透,你的半只脚就已经踏进心仪大公司的技术研发部 。
然而,绝大部分开发者只会拿 Redis 做数据缓存,使用最简单的 get/set 方法,除此之外几乎一片茫然,对 Redis 内部实现的细节原理知之甚少 。例如:
  1. 有同学知道 Redis 的分布式锁,但完全不清楚其内部实现机制
  2. 有同学知道 Redis 是单线程结构,但完全不理解 Redis 缘何单线程还可以支持高并发
  3. 有同学知道 Redis 支持主从,但完全不晓得内部的实现机制
Redis 特点如下:
  • 数据类型丰富
  • 支持数据磁盘持久化存储
  • 支持主从
  • 支持分片
为什么 Redis 能这么快
Redis 的效率很高,官方给出的数据是 100000+QPS,这是因为:
  • Redis 完全基于内存,绝大部分请求是纯粹的内存操作,执行效率高 。
  • Redis 使用单进程单线程模型的(K,V)数据库,将数据存储在内存中,存取均不会受到硬盘 IO 的限制,因此其执行速度极快 。
另外单线程也能处理高并发请求,还可以避免频繁上下文切换和锁的竞争,如果想要多核运行也可以启动多个实例 。
  • 数据结构简单,对数据操作也简单,Redis 不使用表,不会强制用户对各个关系进行关联,不会有复杂的关系限制,其存储结构就是键值对,类似于 HashMap,HashMap 最大的优点就是存取的时间复杂度为 O(1) 。
  • Redis 使用多路 I/O 复用模型,为非阻塞 IO 。
注:Redis 采用的 I/O 多路复用函数:epoll/kqueue/evport/select 。
选用策略:
  • 因地制宜,优先选择时间复杂度为 O(1) 的 I/O 多路复用函数作为底层实现 。
  • 由于 Select 要遍历每一个 IO,所以其时间复杂度为 O(n),通常被作为保底方案 。
  • 基于 React 设计模式监听 I/O 事件 。
Redis 的数据类型
String
最基本的数据类型,其值最大可存储 512M,二进制安全(Redis 的 String 可以包含任何二进制数据,包含 jpg 对象等) 。
阿里P9架构师分享:通俗易懂Redis原理,都是你没看过的

文章插图
 
注:如果重复写入 key 相同的键值对,后写入的会将之前写入的覆盖 。
Hash
String 元素组成的字典,适用于存储对象 。
阿里P9架构师分享:通俗易懂Redis原理,都是你没看过的

文章插图
 
List
列表,按照 String 元素插入顺序排序 。其顺序为后进先出 。由于其具有栈的特性,所以可以实现如“最新消息排行榜”这类的功能 。
Set
String 元素组成的无序集合,通过哈希表实现(增删改查时间复杂度为 O(1)),不允许重复 。
阿里P9架构师分享:通俗易懂Redis原理,都是你没看过的

文章插图
【阿里P9架构师分享:通俗易懂Redis原理,都是你没看过的】 
另外,当我们使用 Smembers 遍历 Set 中的元素时,其顺序也是不确定的,是通过 Hash 运算过后的结果 。
Redis 还对集合提供了求交集、并集、差集等操作,可以实现如同共同关注,共同好友等功能 。
Sorted Set
通过分数来为集合中的成员进行从小到大的排序 。
阿里P9架构师分享:通俗易懂Redis原理,都是你没看过的

文章插图
 
更高级的 Redis 类型
用于计数的 HyperLogLog、用于支持存储地理位置信息的 Geo 。
从海量 Key 里查询出某一个固定前缀的 Key
假设 Redis 中有十亿条 Key,如何从这么多 Key 中找到固定前缀的 Key?
方法 1:使用 Keys [pattern]:查找所有符合给定模式 Pattern 的 Key
使用 Keys [pattern] 指令可以找到所有符合 Pattern 条件的 Key,但是 Keys 会一次性返回所有符合条件的 Key,所以会造成 Redis 的卡顿 。
假设 Redis 此时正在生产环境下,使用该命令就会造成隐患,另外如果一次性返回所有 Key,对内存的消耗在某些条件下也是巨大的 。
例:
keys test* //返回所有以test为前缀的key 方法 2:使用 SCAN cursor [MATCH pattern] [COUNT count]


推荐阅读