个人主页island1314⛺️ 欢迎关注点赞 留言 收藏 生活总是不会一帆风顺前进的道路也不会永远一马平川如何面对挫折影响人生走向 – 《人民日报》 目录一、安装 Redis1. 配置Redis支持远程连接2. 重启 Redis 服务3. 连接服务器4. 关于 Redis 客户端二、Redis 常用命令1. get 和 set2. 基本全局命令2.1 KEYS2.2 EXISTS2.3 DEL2.5 EXPIRE关于 TTLRedis 删除过期键策略定期删除机制详解2.6 TYPE2.7 FLUSHALL三、Redis 对象类型及编码四、Redis 编码方式1. String2. Hash3. List4. Set5. ZSet (Sorted Set)五、单线程架构1. Redis 单线程概念2. 操作演示3. Redis 单线程模型如何支持高并发效率高一、安装 Redis① 首先确保你的系统是最新的。可以通过运行以下命令来更新你的软件包列表sudoaptupdate② 使用apt安装Redissudoaptinstallredis-ylighthouseVM-8-10-ubuntu:~$sudonetstat-nap|grepredis tcp00127.0.0.1:63790.0.0.0:* LISTEN3698310/redis-serve tcp600::1:6379 :::* LISTEN3698310/redis-serve1. 配置Redis支持远程连接默认情况下Redis仅监听本地回环接口127.0.0.1这意味着只有在同一台机器上的客户端才能连接到Redis服务器。为了允许从其他机器进行连接你需要编辑Redis的配置文件。1打开Redis配置文件使用文本编辑器如nano或vim打开Redis配置文件/etc/redis/redis.confsudovim/etc/redis/redis.conf2修改绑定地址找到bind指令默认可能设置为127.0.0.1。将其更改为0.0.0.0以便Redis监听所有网络接口。如果bind行前面有注释符号#请删除该符号以取消注释此行# bind 127.0.0.1bind0.0.0.03关闭保护模式找到protected-mode指令并将其值从yes更改为no。保护模式是一种安全特性当Redis没有密码保护并且监听非本地网络接口时会阻止某些命令的执行。由于我们正在开放Redis以接受远程连接因此需要关闭保护模式protected-mode no结果如下2. 重启 Redis 服务为了让更改生效你需要重启Redis服务sudoserviceredis-server restart# 重启 redis 服务# 其他指令补充sudoserviceredis-server start# 启动 redis 服务sudoserviceredis-server stop# 停止 redis 服务sudoserviceredis-server status# 查看 redis 服务状态# 操作结果如下lighthouseVM-8-10-ubuntu:~$sudoserviceredis-server status ● redis-server.service - Advanced key-value store Loaded: loaded(/lib/systemd/system/redis-server.service;enabled;vendor preset: enaActive: active(running)since Sun2025-06-0121:40:46 CST;3s ago Docs: http://redis.io/documentation, man:redis-server(1)Main PID:3708413(redis-server)Status:Ready to accept connectionsTasks:5(limit:3943)Memory:2.6M CPU: 60ms CGroup: /system.slice/redis-server.service └─3708413/usr/bin/redis-server 0.0.0.0:6379补充① 持久化文件存储目录lighthouseVM-8-10-ubuntu:~$sudols/var/lib/redis/ dump.rdbRedis 持久化生产的 RDB 和 AOF 文件都默认生成于该目录下② 日志文件目录lighthouseVM-8-10-ubuntu:~$sudols/var/log/redis/ redis-server.log/var/log/redis/目录下会保存Redis运行期间生产的日志文件默认按照天进行分割并且会将一定日期的日子文件使用gzip格式压缩保存。可以使用任意文本编辑器打开3. 连接服务器现在我们已经启动了Redis服务下面将介绍如何使用redis-cli连接、操作Redis服务redis-cli可以使用两种方式连接Redis服务器1交互式方式通过redis-cli-h{host}-p{port}的方式连接到Redis 服务后续所有的操作都是通过交互式的方式实现不需要再执行redis-cli了例如[roothost ~]# redis-cli -h 127.0.0.1 -p 6379127.0.0.1:6379pingPONG127.0.0.1:6379setkey hello OK127.0.0.1:6379get keyhello2命令方式用redis-cli-h{host}-p{port}{command}就可以直接得到命令的返回结果例如[roothost ~]# redis-cli -h 127.0.0.1 -p 6379 pingPONG[roothost ~]# redis-cli -h 127.0.0.1 -p 6379 set key helloOK[roothost ~]# redis-cli -h 127.0.0.1 -p 6379 get keyhello此时就算访问成功了然后Ctrl d就可以成功退出有些人进行客户端连接测试的时候可能会出现如下问题解决办法密码设置方式如下不需要重启redis服务的密码设置方式127.0.0.1:6379configsetrequirepass123456OK127.0.0.1:6379config get requirepass1)requirepass2)123456# 退出重进lighthouseVM-8-10-ubuntu:~$ redis-cli127.0.0.1:6379ping(error)NOAUTH Authentication required.127.0.0.1:6379auth123456OK127.0.0.1:6379pingPONG注意通过命令行修改了密码之后配置文件的requirepass字段后面的密码是不会随之修改的。为啥要设置密码就是因为避免 redis 的 key 变成 backup[解决redis的key都变成了backupredis所有缓存被清空_注意事项开启Redis的远程访问前请确保已经配置了合适的防火墙规则只允许受信任的IP地址访问Redis端口考虑设置一个密码来增强安全性。可以在/etc/redis/redis.conf中找到requirepass指令并设置一个强密码如果你的Redis服务器暴露在互联网上建议使用SSL/TLS加密通信以防止数据泄露4. 关于 Redis 客户端Redis 客户端也是一个客户端-服务器结构的程序!!MySQL 也是由于我们连接的Redis服务位于127.0.0.1端口使用的是默认的6379端⼝所以可以省略-h{host}-p{port}Redis 客户端和服务端可以在同一个主机上也可以在不同主机上。当前阶段我们一般只有一台机器此时客户端和服务端就是在同一个机器上如下是 Redis 客户端和服务器的交互过程二、Redis 常用命令注意Redis 中的命令是不区分大小写的1. get 和 setRedis中是使用键值对来进行存储的所以 get 是根据 key 来取 Value 的而 set 是来设置键值对SET功能设置一个键值对使用方法set key value注意事项key和value都是字符串可选地使用单引号或双引号包围案例127.0.0.1:6379setkey1 value1 OK127.0.0.1:6379setkey3 value3 OK127.0.0.1:6379setkey2value2OKGET功能获取键对应的值使用方法get key特点如果查询的键不存在则返回nil案例127.0.0.1:6379get key1value1127.0.0.1:6379get key2value2127.0.0.1:6379get key3value3127.0.0.1:6379get key(nil)2. 基本全局命令Redis可以看成是一个网络版本的哈希表它支持很多的数据结构key 固定是字符串但是 Value可以是多种多样的数据结构下面讲述的就是全局命令可以搭配各种各样的数据结构2.1 KEYS功能获取所有符合特定模式的键。使用方法keys patternpattern 是什么表示的意思是一个包含特殊符号的字符串存在的意义是来描述找的字符串是什么样子的常见模式?匹配任何一个字符。*匹配任意数量的任意字符[abc]匹配a、b、c中的一个[^a]排除a匹配其他任何字符。[a-c]匹配a到c范围内的字符。样例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注意key 命令的时间复杂度O ( N ) , 在生产环境上一般都会禁用KEYS命令尤其是KEYS *生产环境上的key可能会非常多而Redis是一个单线程服务器执行KEYS *的时间非常长就会使Redis服务器被阻塞无法给其他客户端提供服务此时其他的查询Redis操作超时了就直接会去查数据库突然一大波数据突然来了MySQL可能措手不及就直接挂了2.2 EXISTS功能检查一个或多个键是否存在。使用方法exists key [key ...]特点可以同时检查多个键返回存在的键的数量。由于使用哈希表存储数据此操作的时间复杂度为 O(1)lighthouseVM-8-10-ubuntu:code$ redis-cli127.0.0.1:6379set hello1OK127.0.0.1:6379set hallo2OK127.0.0.1:6379set hbllo3OK127.0.0.1:6379set hllo4OK127.0.0.1:6379set heeeeeelo5OK127.0.0.1:6379exists hellohallo(integer)2127.0.0.1:6379existshello(integer)1127.0.0.1:6379existshallo(integer)1EXISTS key1 key2和分开写EXISTS key1、EXISTS key2有什么区别分开的写法会产生更多的轮次的网络通信此时跟直接操作内存相比效率比较低成本比较高那为什么要这样进行一次请求多个呢这是考虑到了网络服务Redis 和 HTTP 的请求响应机制是一样的这就意味着如果每次都请求会消耗一定的网络资源但是如果采用一次去检查多个的情况减少网络通信的次数就不会这样相当于会节省一部分的网络资源2.3 DEL功能删除一个或多个键使用方法del key [key ...]特点支持一次删除多个键案例127.0.0.1:6379keys *1)hallo2)hbllo3)heeeeeelo4)hello5)hllo127.0.0.1:6379del hllo hallo(integer)2127.0.0.1:6379keys *1)hbllo2)heeeeeelo3)hello这里值得注意的是Redis 数据被删除要看它是否是一个数据库如果它作为缓存那问题不算特别大但是如果是作为数据库那就相当于在 MySQL 中丢失了数据这就是一个比较严重的错误了针对于 Redis 的误删数据的错误要根据具体情况具体分析2.5 EXPIRE功能给指定的 key 设置过期时间key 存活时间超过这个指定的值就会被自动删除以 秒为单位使用方法expire key seconds返回值成功返回 1失败例如键不存在返回 0127.0.0.1:6379expire hbllo2(integer)1127.0.0.1:6379keys *1)heeeeeelo2)hello关于 TTLTTL获取键的剩余生存时间以秒为单位全称是 time to livettl也有毫秒级别的指令pttl返回值剩余过期时间。-1表示没有关联过期时间-2表示 key不存在。127.0.0.1:6379sethello100OK127.0.0.1:6379ttl hello(integer)-1127.0.0.1:6379expire hello10(integer)1127.0.0.1:6379ttl hello(integer)4127.0.0.1:6379ttl hello(integer)-2Redis 删除过期键策略 Redis 的 **定期删除策略Periodic Key Eviction**是 Redis 为了在内存有限的情况下自动清理一些不再需要的键以释放内存的一种机制Redis 对设置了过期时间的键通过EXPIRE或PEXPIRE设置有以下三种删除策略来处理这些键策略描述优点缺点惰性删除Lazy Expiration只有当访问一个键时才检查是否过期如果过期则删除节省 CPU 资源过期键可能长期滞留内存浪费内存定期删除Active Expiration每隔一段时间主动随机抽查一批键并删除其中过期的键平衡内存与性能实现较复杂不能保证及时删除所有过期键定时删除Timed Deletion创建一个定时器在键到期时立即删除最及时内存友好但消耗大量 CPU 和内存资源Redis 实际使用的是前两种策略的结合惰性删除 定期删除原因因为Redis内部要存储不少数据轮询一遍所有数据要浪费很多时间所以不会遍历所有数据判断过期。而是等待用户访问数据才删除或者抽样检查删除以降低删除过期数据带来的时间浪费定期删除机制详解Redis 默认每秒运行一次定期删除任务由hz配置控制频率默认hz10即每 100ms 执行一次其流程如下1随机抽查数据库Redis 会从所有数据库中随机选择一部分数据库默认每次选 16 个2从每个选中的数据库中随机选取键在每个选中的数据库中随机抽取一定数量的设置了过期时间的键默认 20 个3检查并删除过期键如果发现某个键已经过期则删除它4统计过期键比例如果在这次抽查中超过 25% 的键是过期的即 5 个或以上Redis 会重复这一过程直到抽查的比例低于 25% 或者达到最大循环次数受maxmemory-samples影响。⚠️ 注意这种机制是“概率性的”意味着不是所有过期键都能被及时清除。效果尽管这两种策略结合使用整体效果仍不尽如人意可能会导致许多过期的键未被及时删除补充Redis 并没有采取定时器的方式来实现过期键的删除那么为啥 Redis 不采用定时器的方式删除过期键呢定时器作用如果有多个键过期可以通过一个定时器在高效节省 CPU 的前提下处理多个键redis 为什么不采用定时器原因多线程引入基于定时器实现势必会引入多线程。单线程基础Redis 早期版本奠定了单线程的基础引入多线程会打破作者的初衷。通过一些策略和方法Redis 基本在处理过期键和内存管理方面取得了平衡既保持了单线程的简洁性和高效性又尽量减少了过期键的残留。2.6 TYPE功能返回键对应的值的类型。使用方法type key返回值none不存在, string, list, set集合, zset有序集, hash, stream时间复杂度O ( 1 )127.0.0.1:6379setkey11OK127.0.0.1:6379lpush key22(integer)1127.0.0.1:6379sadd key33(integer)1127.0.0.1:6379typekey1 string127.0.0.1:6379typekey2 list127.0.0.1:6379typekey3set2.7 FLUSHALL功能删除Redis中所有数据库的数据。使用方法flushall注意在生产环境中谨慎使用此命令以免造成数据丢失。三、Redis 对象类型及编码Redis中的每个对象都由一个redisObject结构表示,该结构中和保存数据有关的三个属性分别是type属性、 encoding属性和ptr属性:typedefstructredisObiect{//类型unsignedtype:4;//编码unsignedencoding:4;//指向底层数据结构的指针void*ptr;}Redis使用对象来表示数据库中的键和值每次当我们在Redis的数据库中新创建一个键值对时我们至少会创建两个对象一个对象用作键值对的健(键对象)另一个对象用作键值对的值(值对象)。其中Redis的键对象都是字符串对象而Redis的值对象主要有字符串、哈希、列表、集合、有序集合几种。其分别对应的内部编码和底层数据结构如下图所示可以在 Redis 官网上找到 Redis 数据结构非常详细的介绍Data Structures - RedisRedis 5 种基本数据结构String、List、Hash、Set、Sorted Set详解 | JavaGuide - JavaGuide - SegmentFault 思否✅基础数据类型类型特点示例命令String最基础的类型可以是字符串、整数或浮点数SET,GET,INCRHash存储字段-值对适合存储对象HSET,HGET,HGETALLList有序、可重复的字符串列表LPUSH,RPUSH,LPOPSet无序、不重复的字符串集合SADD,SMEMBERS,SINTERSorted Set (ZSet)带权重的集合按分值排序ZADD,ZRANGE,ZSCORE✅扩展数据类型类型特点示例命令Stream消息队列结构支持持久化、消费者组等XADD,XREAD,XGROUPBitmap位操作结构用于高效统计SETBIT,GETBIT,BITCOUNTBitfield更精细的位操作控制BITFIELDGeospatial地理位置索引基于 Sorted Set 实现GEOADD,GEORADIUS这些数据结构构成了 Redis 的 API 接口用户通过这些命令进行操作时不需要关心底层是如何实现的。Redis 在底层实现上述数据结构的过程中会在源码的角度上对于上述的内容进行特定的优化这样的优化的主要目的是为了实现出节省时间和节省空间的效果具体的优化方法当然还是要看的是具体的内容Redis 在外部承诺对于哈希表来说保证用户在进行增删查改这些操作都能保证是O(1)但是具体内部的实现来说其实并不是一个传统意义的哈希表在特定的实现场景下会使用其他的数据结构来实现但是总体上来说还是能够保证时间复杂度是满足具体的要求的所以我们说对于 Redis 内部的数据结构或者说是数据类型来说这是 Redis 承诺给用户的但是在其内部的实现中可能会不同具体的方式是有编码方式来进行决定的因此换句话说对于同一个数据结构来说内部会有不同的实现方式在不同的场景下会使用不同的方式但是作为上层的使用者其实是感知不到这样的存在的Redis中的对象大都是通过多种数据结构来实现的为什么会这样设计呢用一种固定的数据结构来实现不是更加简单吗四、Redis 编码方式TYPE命令实际返回的就是当前键的数据结构类型但这些只是Redis对外的数据结构Redis这样设计多种数据结构有两个好处可以自由改进内部编码而对外的数据结构和命令没有影响这样一旦开发出更优秀的内部编码无需改动外部数据结构和命令例如Redis3.2提供了quicklist其结合了ziplist和linkedlist两者的优势为列表类型提供了一种更为优秀的内部编码实现而对外部用户来说基本感知不到。 这一点比较像程序设计中的分层架构。多种内部编码实现可以在不同场景下发挥各自的优势从而优化对象在不同场景下的使用效率。例如ziplist比较节省内存但是在列表元素比较多的情况下性能会有所下降这时候Redis会根据配置选项将列表类型的内部实现转换linkedlist。 (后续文章将根据具体对象介绍)每个 Redis 对象robj都有一个属性encoding用来表示其底层使用的具体实现方式。 你可以使用OBJECT ENCODING key来查看某个键的实际编码方式例如127.0.0.1:6379SET nameTomOK127.0.0.1:6379OBJECT ENCODING nameembstrRedis 对不同数据类型使用不同的内部编码以提高性能和内存使用效率1. Stringint当存储的值为整数且值的大小可以用long 类型表示时Redis 使用int 编码。在 int 编码中String 对象的实际值会被存储在一个 long 类型的整数中。这种编码方式的优点存储空间小且无需进行额外的解码操作 只有整数才会使用int如果是浮点数, Redis内部其实先将浮点数转化为字符串值然后再保存embstr当存储的值为字符串且长度小于等于 44 字节时Redis 使用 embstr 编码。在 embstr 编码中String 对象的实际值会被存储在一个特殊的字符串对象中该对象包含了字符串的长度和字符数组的指针但是不包含额外的空间。这种编码方式的优点存储空间小且无需进行额外的解码操作但是由于需要额外的内存分配可能会影响性能。raw当存储的值为字符串且长度小于等于 44 字节时Redis 使用raw编码。在 raw 编码中String 对象的实际值会被存储在一个简单的字符串对象中该对象包含了字符串的长度和字符数组的指针。这种编码方式的优点存储空间小且无需进行额外的解码操作。默认情况下值以字符串形式传入如果Redis检测到字符串为数字则转换为int存储从而节省空间。例如字符串1234567890若作为字符串存储需要10字节而转换为int后仅需8字节明明没有超过阈值,为什么变成raw对于embstr由于其实现是只读的因此在对embstr对象进行修改时都会先 转化为 raw 再进行修改。因此只要是修改embstr对象修改后的对象一定是 raw 的无论是否达到了 44 个字节。2. Hashhashtablehashtable是哈希表适用于存储大量数据支持高效的查找和插入操作ziplist一种压缩列表适用于存储少量、短字符串具有内存效率高、遍历速度快的优点但不擅长修改操作当数据量增多时Redis会将ziplist优化为 hashtablelistpack替代 ziplist 新版本中用于小对象的紧凑存储那到此可能会关心的问题是为什么要进行压缩意义在哪呢因为 Redis 内部是有很多的 key 值的这就意味着对于某些 key 的 Value 是一个 hash所以当 key 值比较多的时候对应的 hash 结构也会比较多但是每一个 hash 的实际占用其实不大因此就可以选择去尽量的压缩这样压缩后就可以使得整体上的占用变的比较少了核心意义就是在 Hash 数据量较小的情况下通过紧凑的内存布局显著降低内存占用从而提升整体内存利用率压缩的好处节省内存所有元素连续存储没有额外指针开销减少碎片单块内存分配避免频繁的小块内存分配适合小对象当 Hash 字段数量较少时效率更高自动切换当 Hash 变大时Redis 会自动切换到 hashtable 编码3. Listlinkedlist标准链表实现每个节点都是独立对象占用内存大ziplist当链表元素较少时采用压缩列表以节省空间Redis 3.2后List统一使用quicklist结合了linklist和ziplist的优点类似于 C中的 deque, 即基本结构为链表每个链表节点包含一个压缩列表。4. Sethashtable基于哈希表实现的集合提供O(1)时间复杂度的操作。intset如果集合成员全部为整数则使用整数集合进行优化。在现代编程语言中常用平衡二叉搜索树如红黑树实现Set时间复杂度为O(log N)而Redis选择哈希表实现Set以获得更高的效率。5. ZSet (Sorted Set)skiplistdict大集合使用跳表和字典结合的方式保证插入和查询效率跳表是一种高效的搜索结构与平衡二叉搜索树处于同一级别的时间复杂度但提供了更好的并发性能用于快速查找排序后的元素时间复杂度为O(log N)ziplist/listpack当有序集合元素较少时使用压缩列表以节省空间。内部编码的好处可以改进内部编码而对外的数据结构和命令没有任何影响这样⼀旦开发出更优秀的内部编码 无需改动外部数据结构和命令例如Redis3.2提供了quicklist结合了ziplist和linkedlist两者的优势为列表类型提供了⼀种更为优秀的内部编码实现而对用户来说基本无感知多种内部编码实现可以在不同场景下发挥各自的优势例如ziplist比较节省内存但是在列表元素比较多的情况下性能会下降这时候Redis会根据配置选项将列表类型的内部实现转换为linkedlist整个过程用户同样无感知小结Redis 对外提供统一的数据结构接口如 String、Hash 等但内部根据数据量、内容、性能需求等动态选择最优的底层编码方式从而实现高性能 高效内存利用的双重目标例如对于整数和短字符串Redis通过特殊编码如int和embstr来节省内存而对于集合和有序集合Redis通过哈希表和跳表等数据结构来提高操作的效率五、单线程架构Redis 的“单线程”到底指的是什么Redis 的核心网络 I/O 和键值操作命令处理是在一个单线程中完成的。也就是说所有的客户端请求读写都是由一个主线程串行处理。这个主线程负责接收客户端连接解析命令执行命令返回结果这种设计被称为单线程的事件循环模型Event Loop1. Redis 单线程概念❗Redis 6.0 引入了多线程 I/O 特性但核心命令执行仍然是单线程的。Redis 多线程的结构以 Redis 6.0 为例模块是否多线程描述I/O 读写网络请求✅ 多线程使用多个 I/O 线程并行读取/写入客户端数据命令解析与执行❌ 单线程主线程串行执行 Redis 命令持久化、慢日志等后台任务✅ 多线程由独立线程或进程处理单线程处理请求Redis 使用一个线程处理所有的客户端请求但这并不意味着Redis服务器内部只有一个线程。内部多线程Redis 内部确实有多个线程但这些线程主要用于处理网络 I/O。命令执行顺序尽管多个客户端看起来是同时发起请求但从微观角度看这些命令仍然是按线性顺序执行的且命令的执行顺序是不确定的但绝不会有两个命令同时执行。2. 操作演示现在开启了三个redis-cli客户端同时执行命令客户端 1 对 counter 设置初始值127.0.0.1:6379setcounter1OK客户端 2 对 counter 做自增操作127.0.0.1:6379incr counter(integer)2客户端 3 对 counter 做自增操作127.0.0.1:6379incr counter(integer)3我们已经知道从客户端发送的命令经历了发送命令、执行命令、返回结果三个阶段其中重点关注第2步。所谓的 Redis是采用单线程模型执行命令的是指虽然三个客户端看起来是同时要求 Redis 去执行命令的但微观角度这些命令还是采用线性方式去执行的只是原则上命令的执行顺序是不确定的但一定不会有两条命令被同步执行。如下面图所示可以想象 Redis内部只有一个服务窗口多个客户端按照它们达到的先后顺序被排队在窗口前依次接受 Redis 的服务所以两条incr命令无论执行顺序结果一定是2不会发生并发问题这个就是 Redis 的单线程执行模型。① 宏观上同时要求服务的客户端② 微观上客户端发送命令的时间有先后次序的③ Redis 的单线程模型理解并发请求与串行处理虽然多个客户端并发发起请求但Redis在处理这些请求时是单线程模型确保所有请求在内部依然串行执行.请求排队多个请求同时到达Redis服务器时会先在队列中排队然后由Redis服务器逐个取出并执行所以不存在之前学习的 多线程安全的 数据同步及加锁解决Redis 能够使用单线程模型很好的工作,原因主要在于 Redis 的核心业务逻辑都是短平快的不太消耗 cpu 资源【即不太吃多核】但是也有个弊端Redis 必须要特别小心, 某个操作占用时间长, 就会阻塞其他命令的执行!3. Redis 单线程模型如何支持高并发效率高虽然 Redis 是单线程处理命令但它依然可以支持数十万 QPS这得益于以下几个关键技术1. 非阻塞 I/ONon-blocking I/ORedis 使用epollLinux、kqueueBSD等 I/O 多路复用技术。可以同时监听大量客户端连接只在有事件发生时才处理。2. 事件驱动架构Event-drivenRedis 使用事件循环event loop处理所有事件如连接、读、写。所有事件都在一个主循环中被顺序处理。3. 高效的内存访问Redis 数据全部存储在内存中读写速度极快。避免了磁盘 I/O 的延迟问题。4. 命令本身执行时间短大多数 Redis 命令的时间复杂度是 O(1) 或 O(log N)非常高效。5. 简化数据结构和算法单线程避免了线程切换和竞态产⽣的消耗。单线程可以简化数据结构和算法的实现让程序模型更简单其次单线程避免了在线程竞争同⼀份共享数据时带来的切换和等待消耗Redis 使用 I/O 多路复用模型虽然单线程给 Redis 带来很多好处但还是有一个致命的问题对于单个命令的执行时间都是有要求的如果某个命令执行过长会导致其他命令全部处于等待队列中迟迟等不到响应造成客户端的阻塞对于 Redis 这种高性能的服务来说是非常严重的所以 Redis 是面向快速执行场景的数据库。小结Redis 的“单线程”模型是指其核心命令处理在一个线程中串行执行但通过非阻塞 I/O、事件驱动和内存操作的优势依然可以实现高性能、高并发的访问Redis 6.0 开始引入多线程 I/O 来进一步提升吞吐能力但核心逻辑依然是单线程的。