ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Redis 数据结构全家桶:入门之前,先把这几个 “ 前置副本 “刷了

Redis 数据结构全家桶:入门之前,先把这几个 “ 前置副本 “刷了 概要上一节我们介绍了redis的发展历史,redis的版本,redis的核心原理等等,这一节我将继续通过3个模块去学习redis在正式开始学习之前我先点破两个非常关键的道理:一是 Redis 的命令有上百个纯靠死记硬背很难记住但如果理解了底层的机制会发现这些命令有很强的通用性 —— 学会几个对所有键都通用的命令后面学每种数据结构的具体命令时就能举一反三二是 Redis 不是万金油有些数据结构和命令只能在特定场景下使用一旦用错可能对 Redis 本身或者应用本身造成致命伤害由此来引出我们这节要学习的3个内容全局generic命令、数据结构和内部编码、单线程模式机制分析一.全局命令先学会操作 键Redis 有 5 种数据结构但它们都是键值对里的值。对于 键 本身有一批对所有键通用的命令,先把这几个掌握住后面的具体数据结构命令就好理解了1.1KEYS pattern—— 返回所有满足样式pattern的 key支持通配符h?llo 匹配 hello、hallo、hxllo? 匹配单个字符h*llo 匹配 hllo、heeeello* 匹配任意数量字符h[ae]llo 匹配 hello、hallo不匹配 hillo[] 匹配括号内任一字符h[^e]llo 匹配 hallo、hbllo但不匹配 hello[^] 匹配括号外的字符h[a-b]llo 匹配 hallo、hbllo[a-b] 匹配区间内字符语法:KEYS pattern有效版本 :1.0.0 之后时间复杂度 :O (N)返回值是匹配 pattern 的所有 key示例1.2.EXISTS—— 判断某个 key 是否存在返回存在的个数语法:EXISTS key [key ...]有效版本 :1.0.0 之后时间复杂度 :O (1)返回值key存在的个数示例1.3.DEL key [key ...]—— 删除指定的 key返回删除掉的 key 的个数语法:DEL key [key ...]有效版本 :1.0.0 之后时间复杂度 :O (1)返回值删除掉的key的个数示例1.4.EXPIRE key seconds—— 为指定 key 添加秒级的过期时间TTL语法:EXPIRE key seconds有效版本 :1.0.0 之后时间复杂度 :O (1)返回值1表⽰设置成功。0表示设置失败示例1.5.TTL key—— 获取指定 key 的过期时间秒级语法:TTL key有效版本 :1.0.0 之后时间复杂度 :O (1)返回值剩余过期时间。-1表⽰没有关联过期时间-2表⽰key不存在示例:注意EXPIRE 和 TTL 都有对应的毫秒级版本 ——PEXPIRE 和 PTTL键过期的整体机制可以参考下面这张时间轴示意1.6.TYPE key—— 返回 key 对应的数据类型。有效版本 :1.0.0 之后时间复杂度 :O (1)返回值可能是 none、string、list、set、zset、hash、stream示例中场小结这一节只是抛砖引玉给几个通用命令为 5 种数据结构的使用做热身键管理后面还有专门章节细讲二. 数据结构和内部编码TYPE 命令实际返回的就是当前键的数据结构类型string字符串、list列表、hash哈希、set集合、zset有序集合,但要注意一个关键区分这些只是 Redis对外呈现的数据结构,如下图所示.实际上Redis针对每种数据结构都有自己的底层内部编码实现而且是多种实现这样Redis会 在合适的场景选择合适的内部编码如下图所示可以看到每种数据结构都有⾄少两种以上的内部编码实现例如list数据结构包含了linkedlist和 ziplist 两种内部编码。同时有些内部编码例如ziplist可以作为多种数据结构的内部实现可以通 过objectencoding命令查询内部编码Redis 这样设计有两个好处1.可以改进内部编码而对外的数据结构和命令没有任何影响这样⼀旦开发出更优秀的内部编码 ⽆需改动外部数据结构和命令例如Redis3.2提供了quicklist结合了ziplist和linkedlist两者的优 势为列表类型提供了⼀种更为优秀的内部编码实现而对用户来说基本无感知2.多种内部编码实现可以在不同场景下发挥各自的优势例如ziplist比较节省内存但是在列表元素 ⽐较多的情况下性能会下降这时候Redis会根据配置选项将列表类型的内部实现转换为 linkedlist整个过程用户同样无感知三. 单线程模型为什么能做到每秒万级3.1示例先看一个例子客户端 2 和客户端 3 同时对 counter 做自增操作incr counter)一条命令从客户端发出要经历三个阶段发送命令、执行命令、返回结果其中要重点关注的是第 2 步 —— 执行命令所谓 Redis 是单线程模型执行命令指的是虽然三个客户端看起来是同时要求 Redis 执行命令但从微观角度看这些命令是线性执行的 —— 执行顺序不确定但一定不会有两条命令被同步执行。可以想象 Redis 内部只有一个服务窗口多个客户端按到达的先后顺序排队依次接受服务。所以两条 incr 命令无论谁先谁后结果一定是 2不会发生并发问题如下图所示宏观上同时要求服务的客户端:微观上客户端发送命令的时间有先后次序的:Redis的单线程模型:3.2单线程为什么还能这么快通常来说单线程处理能力要比多线程差。举个类比有 10000 公斤货物每辆车运载能力是 200 公斤那么要 50 次才能运完但如果有 50 辆车安排合理的话一次就能完成那为什么 Redis 用单线程模型还能达到每秒万级别的处理能力可以归结为三点纯内存访问。Redis 把所有数据放在内存中内存的响应时长大约为 100 纳秒这是达到每秒万级访问的重要基础非阻塞 IO。Redis 使用 epoll 作为 I/O 多路复用技术的实现再配合自身的事件处理模型把 epoll 中的连接、读写、关闭都转换为事件不在网络 I/O 上浪费过多时间如下图:单线程避免了线程切换和竞态产生的消耗。一方面单线程可以简化数据结构和算法的实现让程序模型更简单另一方面避免了多线程竞争同一份共享数据时带来的切换和等待消耗3.3单线程的一个致命短板虽然单线程给 Redis 带来很多好处但还是有一个致命问题对单个命令的执行时间是有要求的。如果某个命令执行过长会导致其他命令全部处于等待队列中迟迟等不到响应造成客户端的阻塞 —— 对于 Redis 这种高性能服务来说是非常严重的所以结论很明确Redis 是面向快速执行场景的数据库四.重点回顾这一节的要点拢成几条全局命令KEYS按样式找 keyO (N)、EXISTS判断存在返回个数、DEL删除返回个数、EXPIRE设秒级过期、TTL查剩余过期时间、TYPE返回数据类型通配符五种? 单字符、* 任意数量、[] 集合内任一、[^] 集合外、[a-b] 区间键过期EXPIRE 设秒级TTL 查过期-1 是没设过期、-2 是 key 不存在毫秒级用 PEXPIRE / PTTL对外数据结构 vs 内部编码TYPE 返回的 string /list/hash /set/zset 只是对外类型内部编码是另一套单线程模型命令经历 发送 → 执行 → 返回微观上线性执行、绝不同步并行像只有一个窗口在排队单线程为什么快纯内存访问、epoll 非阻塞 IO、没有线程切换和竞态短板一条慢命令会卡住所有命令所以 Redis 只适合快速执行场景本期博客到此结束,记得多总结,多回顾!!!
返回列表