文章目录
-
- [1. 什么是redis?](#1. 什么是redis?)
- [2. redis的一些特性](#2. redis的一些特性)
- [3. redis典型应用场景](#3. redis典型应用场景)
-
-
- [1. 缓存(Cache)](#1. 缓存(Cache))
- [2. 排行榜系统](#2. 排行榜系统)
- [3. 计数器应用](#3. 计数器应用)
- [4. 社交网络](#4. 社交网络)
- [5. 消息队列系统](#5. 消息队列系统)
-
- [4. redis安装与配置](#4. redis安装与配置)
-
- [1. 更新并安装 Redis Server](#1. 更新并安装 Redis Server)
- [2. 检查 Redis 服务状态](#2. 检查 Redis 服务状态)
- [3. 常用服务管理命令](#3. 常用服务管理命令)
- [4. 配置文件](#4. 配置文件)
-
- [1. 配置密码(不是很推荐)](#1. 配置密码(不是很推荐))
- [2. 允许远程访问](#2. 允许远程访问)
- [5. 重启 Redis 使配置生效](#5. 重启 Redis 使配置生效)
- [6. 卸载 Redis](#6. 卸载 Redis)
- [5. Redis-cli 客户端使用](#5. Redis-cli 客户端使用)
-
- [1. 交互式方式](#1. 交互式方式)
- [2. 命令方式](#2. 命令方式)
- 基本全局命令
- 扩展内容:定时器的两种主流实现方案
- [6. 数据结构和内部编码](#6. 数据结构和内部编码)
-
- [1. string 字符串](#1. string 字符串)
- [2. hash 哈希](#2. hash 哈希)
- [3. list 列表](#3. list 列表)
- [4. set 集合](#4. set 集合)
- [5. zset 有序集合](#5. zset 有序集合)
- [7. 单线程架构](#7. 单线程架构)
-
- [1. 单线程模型](#1. 单线程模型)
- [2. 为什么单线程还能这么快](#2. 为什么单线程还能这么快)
1. 什么是redis?
Redis 是一种基于键值对(key-value)的 NoSQL 数据库 ,与很多键值对数据库不同的是,Redis 中的值可以是由 string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)、 Bitmaps(位图)、HyperLogLog、GEO(地理信息定位)等多种数据结构和算法组成,因此 Redis 可以满足很多的应用场景,而且因为 Redis 会将所有数据都存放再内存中,所以它的读写性能非常惊人。不仅如此,Redis 还可以将内存的数据利用快照和日志的形式保存到硬盘上,这样在发生类似断电或者机器故障的时候,内存中的数据不会"丢失"。
2. redis的一些特性
Redis 之所以受到如此多公司的⻘睐,必然有之过⼈之处,下⾯是关于 Redis 的 8 个重要特性:
一、极致的高性能与低延迟
这是Redis最核心的基础特性,核心优势来自底层架构设计:
- 基于内存的存储 :所有数据默认存储在内存中,内存读写速度远超磁盘IO,随机读写延迟可达微秒级,单机QPS(每秒查询率)轻松突破10万+。
- 优化的线程模型 :
- 核心命令执行采用单线程模型,彻底避免了多线程上下文切换、锁竞争带来的性能开销,同时天然保证了单命令的原子性。
- Redis 6.0+引入多线程IO,但是仅将网络请求的读写、协议解析等操作交给多线程处理,核心命令执行依然保持单线程,在高并发场景下进一步提升吞吐量,同时不破坏命令原子性。
- IO多路复用模型:采用epoll/kqueue等IO多路复用技术,实现非阻塞网络IO,可高效处理数万级的并发客户端连接。
二、丰富的原生数据类型支持
区别于普通键值数据库,Redis提供了丰富的内置数据类型,可直接适配多样化业务场景,无需额外编码转换:
| 核心数据类型 | 核心说明 | 典型适用场景 |
|---|---|---|
| String(字符串) | 最基础的二进制安全类型,单key最大支持512MB | 业务缓存、计数器、分布式锁、限流、Session存储 |
| Hash(哈希) | 键值对集合,专为结构化对象设计 | 用户信息、商品属性、配置项等对象型数据存储 |
| List(列表) | 双向链表,支持两端高效插入/弹出,有序可重复 | 轻量消息队列、时间线、任务队列、排行榜 |
| Set(集合) | 无序不可重复集合,原生支持交/并/差集运算 | 好友关注、共同好友、数据去重、标签系统 |
| ZSet(有序集合) | 不可重复集合,每个元素关联score权重,按权重自动排序 | 实时排行榜、延时队列、优先级任务调度 |
除此之外,Redis还原生支持Bitmap(位图)、HyperLogLog(基数统计)、Geospatial(地理空间)、Stream(流)、Bitfield等进阶数据结构。
三、可靠的持久化机制
作为内存数据库,Redis提供了完善的持久化方案,解决内存数据断电丢失的问题,保障数据可靠性:
- RDB(快照持久化):在指定时间间隔内,对内存全量数据生成快照并写入磁盘。优点是恢复速度快,适合备份、灾难恢复;缺点是两次快照之间的故障会丢失数据。
- AOF(追加日志持久化):以日志形式记录每一条写命令,服务重启时重放AOF文件恢复数据。优点是数据安全性更高,可配置每秒/每次写命令刷盘,最多丢失1秒数据;缺点是文件体积大,恢复速度慢于RDB。
- 混合持久化:结合RDB与AOF的优势,持久化文件前半段是RDB格式的全量快照,后半段是AOF格式的增量写命令。兼顾了恢复速度与数据安全性,是当前主流推荐的持久化方案。
四、原生的高可用能力
Redis提供了完整的高可用架构方案,保障服务持续可用:
- 主从复制(Replication) :支持一主多从架构,主节点负责写请求,从节点同步主节点数据、承担读请求,实现读写分离,提升集群读吞吐量,同时提供多副本数据备份。支持全量同步与增量同步(PSYNC,2.8+新增),断线重连后可基于复制积压缓冲区实现增量同步,避免全量同步的性能开销。
- 哨兵机制:专为主从架构设计的高可用组件,核心能力包括:节点健康监控、自动故障转移(主节点故障时自动将从节点晋升为主节点)、配置中心、故障告警。解决了主从架构手动故障转移的痛点,实现服务秒级切换,大幅提升服务可用性。
五、分布式集群横向扩展能力
Redis Cluster(3.0+正式推出)是官方原生的分布式集群方案,彻底解决单机内存、并发、容量的瓶颈问题:
- 采用哈希槽分片机制,集群预分16384个哈希槽,数据按key的哈希值分配到不同槽位,分散到多个集群节点,实现数据分布式存储。
- 支持水平在线扩容/缩容,可动态增减节点,哈希槽可平滑迁移,业务无感知。
- 内置副本机制与自动故障转移,每个主节点可配置多个从节点,主节点故障时自动切换从节点,保障集群高可用。
- 采用去中心化对等架构,无中心节点,客户端可访问任意集群节点获取数据。
六、原子性与事务支持
- 单命令原子性:Redis所有单个命令的执行都是原子性的,得益于核心单线程执行模型,不会出现并发竞争导致的数据异常。
- 事务支持 :通过
MULTI/EXEC/DISCARD/WATCH四个命令实现事务,可将多个命令打包成一个事务单元,按顺序原子性执行,执行过程中不会被其他客户端的命令打断。通过WATCH命令实现乐观锁,保障事务执行前后的数据一致性。 注:Redis事务为弱事务,不支持回滚,仅语法错误会导致整体事务失败,运行时错误不会回滚已执行的命令。
七、丰富的进阶功能特性
- 过期键与内存淘汰策略 :支持给key设置TTL过期时间,到期自动删除;当内存使用达到上限时,提供8种灵活的淘汰策略(如
allkeys-lru、volatile-lfu、noeviction等),适配不同业务场景。 - Lua脚本支持(新增):支持编写Lua脚本,将多个Redis命令打包成一个脚本原子性执行,减少网络往返开销,同时可实现复杂的业务逻辑,是分布式锁、限流等场景的核心实现方案。
- Pipeline管道机制:支持批量打包发送多个命令,一次性接收返回结果,大幅减少TCP网络往返的RTT开销,提升批量操作的性能。
- 发布订阅(Pub/Sub)模式:支持消息的发布与订阅,包括频道精准订阅、模式匹配订阅,可实现广播、消息通知、实时消息推送等场景。
- Stream流(新增):专为消息队列设计的数据结构,支持消息持久化、消费者组、消息确认、回溯消费,弥补了Pub/Sub、List做消息队列的缺陷,可实现轻量级的消息中间件能力。
- 精细化安全访问控制 :支持基础密码认证,Redis 6.0+新增ACL(访问控制列表) 功能,可创建多个用户,为不同用户分配精细化的命令执行权限、key访问权限,同时支持SSL/TLS传输加密,保障数据安全。
八、完善的生态与可扩展性
- 全语言客户端支持:几乎覆盖所有主流编程语言(Java、Python、Go、PHP、C/C++、Node.js等),拥有成熟稳定的官方/社区客户端SDK,接入成本极低。
- 模块化扩展:支持自定义模块扩展能力,官方与社区提供了大量成熟模块,如RedisJSON(JSON原生支持)、RediSearch(全文检索)、RedisTimeSeries(时序数据处理)、RedisBloom(布隆过滤器)等,大幅扩展了Redis的能力边界,形成了完整的Redis Stack生态。
- 跨平台兼容:支持Linux、Windows、macOS等主流操作系统,可部署在物理机、虚拟机、容器、云平台等多种环境。
3. redis典型应用场景
1. 缓存(Cache)
缓存机制几乎在所有大型网站都有使用,合理地使用缓存不仅可以加速数据的访问速度,而且能够有效地降低后端数据源的压力。Redis提供了键值过期时间设置,并且也提供了灵活控制最大内存和内存溢出后的淘汰策略。
2. 排行榜系统
排行榜系统几乎存在于所有的网站,例如按照热度排名的排行榜,按照发布时间的排行榜,按照各种复杂维度计算出的排行榜,Redis提供了列表和有序集合的结构,合理地使用这些数据结构可以很方便地构建各种排行榜系统。
3. 计数器应用
计数器在网站中的作用至关重要,例如视频网站有播放数、电商网站有浏览数,为了保证数据的实时性,每一次播放和浏览都要做加1的操作,如果并发量很大对于传统关系型数据的性能是一种挑战。Redis天然支持计数功能而且计数的性能也非常好,可以说是计数器系统的重要选择。
4. 社交网络
赞/踩、粉丝、共同好友/喜好、推送、下拉刷新等是社交网站的必备功能,由于社交网站访问量通常比较大,而且传统的关系型数据不太适合保存这种类型的数据,Redis提供的数据结构可以相对比较容易地实现这些功能。
5. 消息队列系统
消息队列系统可以说是一个大型网站的必备基础组件,因为其具有业务解耦、非实时业务削峰等特性。Redis提供了发布订阅功能和阻塞队列的功能,虽然和专业的消息队列比还不足够强大,但是对于一般的消息队列功能基本可以满足。
redis 最大的缺点即是无法存储大量数据
4. redis安装与配置
在 Ubuntu 24.04 中安装和配置 Redis 非常简单,以下是完整的步骤指南,包括安装、基础配置和安全加固。
Ubuntu 24.04 的官方软件仓库中已经包含了 Redis,直接使用 apt 安装即可(版本通常为 Redis 7.x,稳定可靠)。
1. 更新并安装 Redis Server
首先更新本地的包列表,确保安装的是最新版本:
bash
sudo apt update
执行以下命令安装 Redis 服务端:
bash
sudo apt install redis-server -y
2. 检查 Redis 服务状态
bash
sudo systemctl status redis-server
如果看到 active (running) 绿色字样,说明服务已成功启动。
可以选择设置开机自启(默认已开启,可确认)
bash
sudo systemctl enable redis-server
3. 常用服务管理命令
- 启动服务:
sudo systemctl start redis-server - 停止服务:
sudo systemctl stop redis-server - 重启服务:
sudo systemctl restart redis-server - 重载配置:
sudo systemctl reload redis-server
4. 配置文件
Redis 的主配置文件位于 /etc/redis/redis.conf,所有重要配置都在此文件中修改。
注意:修改配置前建议先备份:
bashsudo cp /etc/redis/redis.conf /etc/redis/redis.conf.bak
使用文本编辑器(如 nano 或 vim)打开配置文件:
bash
sudo nano /etc/redis/redis.conf
1. 配置密码(不是很推荐)
默认 Redis 没有密码,生产环境必须设置。找到 # requirepass foobared 这一行,去掉注释并修改密码:
conf
requirepass your_secure_password_here
设置后,连接 Redis 需要认证:
bash
redis-cli -a your_secure_password_here
# 或者进入后再认证:
redis-cli
auth your_secure_password_here
2. 允许远程访问
默认 Redis 仅绑定 127.0.0.1(本地访问)。如果需要从其他服务器连接,修改 bind 配置:
找到 bind 127.0.0.1 -::1 这一行,修改为:
conf
# 允许所有 IP 访问(生产环境不建议,建议绑定具体 IP)
bind 0.0.0.0 -::1
# 或者仅允许指定 IP 访问(更安全)
# bind 127.0.0.1 192.168.1.100
同时,将 protected-mode 改为 no(否则远程连接会被拒绝):
conf
protected-mode no
提醒 :允许远程访问时,务必配置强密码,并通过防火墙(
ufw)限制仅允许信任的 IP 访问 6379 端口。
bash
# 允许所有 IP(不推荐,仅用于测试)
sudo ufw allow 6379
# 查看防火墙状态
sudo ufw status
5. 重启 Redis 使配置生效
修改完配置后,必须重启 Redis 服务:
bash
sudo systemctl restart redis-server
再次检查服务状态,确保重启成功:
bash
sudo systemctl status redis-server
验证:
bash
root@VM-0-14-ubuntu:/etc/redis# redis-cli #启动redis客户端
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> exit
6. 卸载 Redis
如果需要完全卸载 Redis:
bash
# 停止服务
sudo systemctl stop redis-server
# 卸载软件包
sudo apt purge redis-server redis-tools -y
# 删除残留文件
sudo rm -rf /etc/redis /var/lib/redis
5. Redis-cli 客户端使用
1. 交互式方式
通过 redis-cli -h {host} -p {port} 的方式连接到 Redis 服务,后续所有的操作都是通过交互式的方式实现,不需要再重复执行 redis-cli 命令,例如:
shell
[root@host ~]# redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set key hello
OK
127.0.0.1:6379> get key
"hello"
2. 命令方式
用 redis-cli -h {host} -p {port} {command} 可以直接执行命令并获取返回结果,无需进入交互终端,例如:
shell
[root@host ~]# redis-cli -h 127.0.0.1 -p 6379 ping
PONG
[root@host ~]# redis-cli -h 127.0.0.1 -p 6379 set key hello
OK
[root@host ~]# redis-cli -h 127.0.0.1 -p 6379 get key
"hello"
图 1-3 Redis 客户端与服务端的交互过程
- 发送命令
- 执行命令
- 返回结果
Redis 客户端
网络
Redis 服务端
基本全局命令
Redis 有 5 种数据结构,它们都是键值对的值,对于键来说有一些通用的命令:
KEYS
返回所有满足样式(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 -
语法:
shell
KEYS pattern
- 示例:
shell
127.0.0.1:6379> keys a?d
1) "add"
127.0.0.1:6379> keys a*
1) "apple"
2) "any"
3) "analysis"
4) "add"
127.0.0.1:6379> keys a[^a]*
1) "apple"
2) "any"
3) "analysis"
4) "add"
127.0.0.1:6379> keys *
1) "backup1"
2) "backup3"
3) "apple"
4) "any"
5) "backup4"
6) "backup2"
7) "analysis"
8) "add"
谨慎使用keys命令,如果key太多会阻塞进程(redis为单进程),redis可能会崩溃
EXISTS
判断某个 key 是否存在。
- 语法:
shell
EXISTS key [key ...]
-
时间复杂度:O(1) (
keys由哈希表存储) -
返回值:key 存在的个数。
-
示例:
shell
127.0.0.1:6379> exists add
(integer) 1
127.0.0.1:6379> exists asdasdasd
(integer) 0
127.0.0.1:6379> exists add apple
(integer) 2
推荐使用exists一次查询多个key,减少网络使用开销,提升性能!
DEL
删除指定的 key。
- 语法:
shell
DEL key [key ...]
-
命令有效版本:1.0.0 之后
-
时间复杂度:O(1)
-
返回值:删除掉的 key 的个数。
-
示例:
shell
redis> SET key1 "Hello"
"OK"
redis> SET key2 "World"
"OK"
redis> DEL key1 key2 key3
(integer) 2
EXPIRE
为指定的 key 添加秒级的过期时间(Time To Live TTL)
- 语法:
shell
EXPIRE key seconds
-
命令有效版本:1.0.0 之后
-
时间复杂度:O(1)
-
返回值:1 表示设置成功,0 表示设置失败。
-
示例:
shell
redis> SET mykey "hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
TTL
获取指定 key 的过期时间,秒级。
- 语法:
shell
TTL key
-
命令有效版本:1.0.0 之后
-
时间复杂度:O(1)
-
返回值:剩余过期时间。-1 表示没有关联过期时间,-2 表示 key 不存在。
-
示例:
shell
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
EXPIRE 和 TTL 命令都有对应的支持毫秒为单位的版本:
PEXPIRE和PTTL,详细用法就不再介绍了。
TYPE
返回key对应的数据类型。
-
语法:
TYPE key
-
命令有效版本: 1.0.0之后
-
时间复杂度: O(1)
-
返回值: none, string, list, set, zset, hash and stream
-
示例:
127.0.0.1:6379> keys *
- "abcdef"
- "abcd"
127.0.0.1:6379> type abcd
string
127.0.0.1:6379> type "abcdef"
string
扩展内容:定时器的两种主流实现方案
一、优先级队列(最小堆)
优先级队列是定时器最经典的实现方式,采用任务到期时间作为优先级排序依据,到期时间越早的任务,优先级越高,始终位于堆顶。
-
堆的每个节点存储定时任务的完整信息:唯一ID、绝对到期时间、回调函数、自定义参数等。
-
最小堆的核心特性:堆顶节点永远是全局最近到期的任务 ,可直接获取,无需遍历,这样使得时间复杂度非常低(只需要考虑堆调整的时间复杂度)。
核心操作的时间复杂度:操作 实现逻辑 时间复杂度 插入任务 将任务追加到堆尾,执行「向上堆化」,调整堆结构保证最小堆特性 O(logn) 取出到期任务 取出堆顶任务,将堆尾节点移到堆顶,执行「向下堆化」调整结构 O(logn) 取消任务 配合哈希表(任务ID→堆下标)O(1)定位节点,修改值后堆化调整 O(logn)
二、时间轮
时间轮通过时间分片、环形结构,将所有定时操作的时间复杂度降至O(1)
-
一个固定长度的环形数组(时间轮盘) ,数组的每个元素称为时间槽(Slot);槽位数
N、每个槽对应的时间间隔tickMs,整个轮盘的最大时间跨度为N * tickMs; -
每个时间槽挂载一个双向链表,存储该时间点到期的所有定时任务;
-
一个当前指针
currentTime,指向轮盘当前正在处理的槽位。 -
任务插入:计算任务到期时间与当前时间的差值,算出目标槽位与剩余圈数,将任务追加到对应槽位的链表尾部,时间复杂度O(1);
-
时钟推进 :每经过
tickMs时间,当前指针向前移动一个槽位,遍历该槽位的链表,执行所有到期任务,其余任务的剩余圈数减1; -
任务取消:通过哈希表定位任务所在的槽位与链表节点,直接从链表中删除,时间复杂度O(1)。
redis 的定时器没有采用上述任何一种实现方式,详细的实现方式将在后面介绍
6. 数据结构和内部编码
type命令实际返回的就是当前键的数据结构类型,它们分别是:string(字符串)、list(列表)、hash(哈希)、set(集合)、zset(有序集合),但这些只是Redis对外的数据结构。
Redis一个key对应value,value的类型分为:
- 字符串:纯字符串或字节流(相当于std::string)
- 哈希:field-value 键值对集合(相当于std::unordered_map)
- 列表:有序的元素序列(相当于std::deque)
- 集合:无序、不重复的元素集合(相当于std::set)
- 有序集合:带分数的、有序不重复的元素集合(与stl的数据结构都有差别)
实际上Redis针对每种数据结构都有自己的底层内部编码实现,而且是多种实现,这样Redis会在合适的场景选择合适的内部编码(具体的实现方式可能会根据使用场景进行改变或优化,不一定完全按照规定方式实现!):
| 数据结构 | 内部编码 |
|---|---|
| string | raw |
| int | |
| embstr | |
| hash | hashtable |
| ziplist | |
| list | linkedlist |
| ziplist | |
| set | hashtable |
| intset | |
| zset | skiplist |
| ziplist |
1. string 字符串
对外都是string,底层3种结构自动切换:
- int :存整数 (比如
100、9999),直接用整型数字存储; - embstr :存短字符串 (比如
hello、name),优化内存布局; - raw :存长字符串(比如长文章、大JSON),用普通字符串结构存储
例:存
SET age 18→ Redis自动用int编码;存SET content 长文本→ 自动用raw。
2. hash 哈希
对外都是hash,底层二选一:
- ziplist(压缩列表) :紧凑的连续数组结构,适用于字段少、值很小的哈希(比如存单个用户信息)
- hashtable(哈希表) :标准字典结构,查询速度O(1),适用于字段多、值很大的哈希(比如存海量用户)
3. list 列表
- ziplist:短列表、小数据
- linkedlist(链表):长列表、大数据
- 新版用
quicklist(结合ziplist+linkedlist,是一个链表,每一个元素又是一个ziplist短列表 )
4. set 集合
- intset(整数集合) :存纯整数、元素少的集合;
- hashtable(哈希表):元素多、包含非整数;
5. zset 有序集合
- ziplist(压缩列表):元素少、值小
- skiplist(跳表):元素多、需要排序 , seloch排序/查询超快
可以看到每种数据结构都有至少两种以上的内部编码实现,例如list数据结构包含了linkedlist和ziplist两种内部编码。同时有些内部编码,例如ziplist,可以作为多种数据结构的内部实现,可以通过object encoding命令查询内部编码:
127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> lpush mylist a b c
(integer) 3
127.0.0.1:6379> object encoding hello
"embstr"
127.0.0.1:6379> object encoding mylist
"quicklist"
Redis这样设计有两个核心好处:
- 可以改进内部编码,而对外的数据结构和命令没有任何影响,这样一旦开发出更优秀的内部编码,无需改动外部数据结构和命令,例如Redis 3.2提供了quicklist,结合了ziplist和linkedlist两者的优势,为列表类型提供了一种更为优秀的内部编码实现,而对用户来说基本无感知。
- 多种内部编码实现可以在不同场景下发挥各自的优势,例如ziplist比较节省内存,但是在列表元素比较多的情况下,性能会下降,这时候Redis会根据配置选项将列表类型的内部实现转换为linkedlist,整个过程用户同样无感知。
7. 单线程架构
1. 单线程模型
现在开启了三个redis-cli客户端同时执行命令。
客户端1设置一个字符串键值对:
127.0.0.1:6379> set hello world
客户端2对counter做自增操作:
127.0.0.1:6379> incr counter
客户端3对counter做自增操作:
127.0.0.1:6379> incr counter
从客户端发送的命令会经历三个阶段:发送命令、执行命令、返回结果 ,其中核心是执行命令 阶段。所谓Redis单线程执行命令,是指:虽然多个客户端看起来同时向Redis发送命令,但所有命令都会采用线性方式执行,同一时刻绝对不会有两条命令被同时执行。
宏观上,多个客户端是同时请求Redis服务的;微观上,客户端发送命令的时间有先后次序,只是顺序不确定,所有命令都会在Redis服务端排队串行执行。
2. 为什么单线程还能这么快
通常来讲,单线程处理能力要比多线程差,那为什么Redis使用单线程模型能达到每秒万级别的处理能力呢?可以将其归结为三点核心原因:
- 纯内存访问:Redis将所有数据放在内存中,内存的响应时长大约为100纳秒,这是Redis达到每秒万级别访问的最重要基础。
- 非阻塞I/O :Redis使用
epoll作为I/O多路复用技术的实现,再加上Redis自身的事件处理模型,将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间。 - 单线程避免了线程 切换和竞态产生的消耗:单线程可以避免线程切换带来的系统开销,让程序执行更简单稳定;其次多线程开发模式下,线程访问共享数据会带来锁竞争,一旦处理不当会导致严重的性能问题,单线程可以完全规避这些问题,且代码更容易维护和实现。
虽然单线程给Redis带来诸多好处,但也有一个致命的限制:对单个命令的执行时长有严格要求。如果某个Redis命令执行耗时过长,会导致其他所有命令都阻塞在等待队列中