Redis:不只是缓存那么简单(二)

专栏:Redis 修行录

个人主页:手握风云

目录

一、环境搭建

[1.1. 在 Linux 上安装 Redis](#1.1. 在 Linux 上安装 Redis)

[1.2. Redis 客户端](#1.2. Redis 客户端)

[二、Redis 通用命令](#二、Redis 通用命令)

[2.1. 查看官方文档](#2.1. 查看官方文档)

[2.2. GET 和 SET](#2.2. GET 和 SET)

[1. GET 命令](#1. GET 命令)

[2. SET 命令](#2. SET 命令)

[2.3. KEYS 命令](#2.3. KEYS 命令)

[2.4. EXISTS 命令](#2.4. EXISTS 命令)

[2.5. DEL 命令](#2.5. DEL 命令)

[2.6. EXPIRE 命令](#2.6. EXPIRE 命令)

[2.7. TTL 命令](#2.7. TTL 命令)

[2.8. Redis 的 key 过期策略](#2.8. Redis 的 key 过期策略)

[2.9. TYPE 命令](#2.9. TYPE 命令)


一、环境搭建

1.1. 在 Linux 上安装 Redis

bash 复制代码
# 查找所有包含 redis 的软件包
dnf search redis
bash 复制代码
# 安装 Redis
dnf install redis
bash 复制代码
# 安装完之后启动 Redis
sudo systemctl start redis
bash 复制代码
# 找出进程名为 redis 的网络信息
netstat -anp|grep redis

但是这里我们会发现,Redis 客户端绑定了 127.0.0.1,这就意味着我们只能在自己的主机上进行访问,无法实行跨主机访问,这时我们就需要修改配置文件。

bash 复制代码
cd /etc/

Redis 的配置文件里面包含了 Redis 相关内容。

bash 复制代码
vim redis.conf

将 IP 改为 0.0.0.0,protected-mode 改为 no。改完配置之后,我们需要重新启动 Redis。

bash 复制代码
# 重启命令
sudo systemctl restart redis
#查看 Redis 状态
service redis status

1.2. Redis 客户端

启动好 Redis 之后,输入命令 redis-cli,就可以连接上自己的主机端口,再按一下 ctrl+d 就可以退出。redis-cli 用于与 Redis 服务端建立连接,执行所有 Redis 命令,完成数据操作、服务管理、集群管控等全场景操作。

交互式方式:通过redis-cli -h {主机IP} -p {端口}连接(默认本地 127.0.0.1:6379 可省略参数),进入交互终端后逐行执行命令,适合调试和学习。

命令方式:通过redis-cli -h {主机IP} -p {端口} {Redis命令}直接执行命令并返回结果,无需进入交互模式,适合脚本自动化执行。

二、Redis 通用命令

2.1. 查看官方文档

我们先来到 Redis 的官网:https://redis.io/。在右上角的搜索框里面,我们可以搜索一些命令,例如"ping"。

2.2. GET 和 SET

1. GET 命令

GET 命令用于获取指定 key 的字符串值,其语法为 GET key。在返回值与行为上,如果 key 存在则返回对应的字符串值,若 key 不存在则返回特殊值 nil(在 RESP3 协议中为 Null 响应),而当 key 存储的值不是字符串类型时,该命令会返回错误,因为 GET 仅支持处理字符串值,此命令的时间复杂度为 O (1)。

2. SET 命令

SET 命令的基本功能是将指定的字符串值设置给 key,若 key 已存在,会无视其原有类型直接覆盖旧值,且操作成功后该 key 之前关联的过期时间(TTL)会被清除,语法为SET key value [NX | XX | IFEQ ifeq-value | IFNE ifne-value | IFDEQ ifdeq-digest | IFDNE ifdne-digest] [GET] [EX seconds | PX milliseconds | EXAT unix-time-seconds | PXAT unix-time-milliseconds | KEEPTTL],时间复杂度为 O (1)。

该命令包含多个常用可选参数,其中存在性条件参数里,NX 表示仅当 key 不存在时才设置该 key,XX 则表示仅当 key 已经存在时才设置;值匹配条件参数为 Redis 8.4.0 版本起引入,IFEQ/IFNE 分别代表仅当 key 的当前值与指定值相等、不相等时才进行设置,IFDEQ/IFDNE 则是仅当 key 的当前值的哈希摘要与指定的哈希摘要相等、不相等时才执行设置;返回值选项中的 GET,可在设置新值的同时返回该 key 原来存储的旧字符串值,若 key 此前不存在则返回 nil,若旧值不是字符串则会返回错误并中止 SET 操作;过期时间(TTL)选项中,EX/PX 可将过期时间分别设置为指定的秒数、毫秒数,EXAT/PXAT 能将过期时间分别设为指定的 Unix 时间戳(秒 / 毫秒),KEEPTTL 则用于保留该 key 现有的过期时间,不对其进行修改。

set 的常见应用场景:SET 命令的参数组合常被用于实现简单的分布式锁机制,客户端可通过执行SET resource-name anystring NX EX max-lock-time尝试获取锁,返回 OK 代表获取成功,锁会在指定时间后自动释放,返回 Nil 则表示锁已被其他客户端占用。后续可通过校验 token 并搭配 Lua 脚本执行 DEL 命令安全解锁,不过官方更推荐使用容错性更优的 Redlock 算法来实现分布式锁。

bash 复制代码
set key1 value1
get key1
set key2 value2
get key2
set "key3" 'value3'
get "key3"
get key3

Redis 对于大小写是不敏感的。Redis 服务器底层并不关心你是否使用了引号,它只存储原始的字节数据。如果键或值只包含连续的普通字符(字母、数字、常规符号),中间没有空格或特殊的控制字符,可以直接输入,不需要加任何引号。如果键或值中包含空格,就必须使用引号将其包裹。否则,redis-cli 会将空格后的内容解析为多余的命令参数,导致 ERR wrong number of arguments 语法错误。

bash 复制代码
# 正确
set 'my key' 'hello world'
# 错误
set my key hello world

2.3. KEYS 命令

bash 复制代码
# 语法
KEYS pattern

Redis KEYS 命令不支持原生正则表达式,仅适配 glob-style 模式 匹配键名。

模式符 作用 示例 匹配结果
? 匹配单个任意字符 h?llo hello、hallo、hxllo
* 匹配任意个字符(含 0 个) h*llo hllo、heeeello
[ae] 匹配括号内任一字符 h[ae]llo hello、hallo(不匹配 hillo )
[^e] 匹配非括号内的字符 h[^e]llo hallo、hbllo(不匹配 hello )
[a-b] 匹配指定范围内的字符 h[a-b]llo hallo、hbllo
\ 转义特殊字符(匹配字面量) h*llo 仅匹配 h*llo
bash 复制代码
set hello 1
set hallo 1
set hbllo 1
set heeello 1
keys h?llo
keys h*llo
keys h[ae]llo
keys h[^e]llo
keys h[a-b]llo

keys 命令的时间复杂度为 。所以在生产环境上,一般禁止使用 keys 命令,尤其是 keys *。生产环境上的 keys 可能会非常多,而 Redis 是一个单线程的服务器,执行 keys * 命令就会非常长,就会使 Redis 服务器发生阻塞。

2.4. EXISTS 命令

bash 复制代码
# 语法
EXISTS key

EXISTS 命令的核心功能是判断一个或多个指定 key 是否存在,语法为EXISTS key [key ...]。其返回值为整数,代表参数中实际存在的 key 数量,若同一存在的 key 被多次提及也会重复计数,比如执行EXISTS somekey somekey会因 somekey 存在而返回 2。命令时间复杂度为 ,N 是待检查 key 的数量。

bash 复制代码
exists key1
exists hello
exists heello
bash 复制代码
exists hello hello
exists hello
  1. 网络往返时间(RTT)

Redis 中主要的性能瓶颈几乎总是网络,而非内存内的执行速度。单条命令:执行 `EXISTS hello hello` 仅需客户端与 Redis 服务器之间进行一次网络往返。两条命令:执行两次 `EXISTS hello` 则需要两次独立的网络往返。即便使用流水线将两条命令批量一次性发送,服务器仍需处理两个独立的网络数据载荷。

  1. 协议解析与指令分发

Redis 采用 RESP(Redis 序列化协议)进行通信。单条命令:Redis 服务器仅需解析一次协议数组,在内部字典中查询一次 `EXISTS` 命令,并构建一个整型响应结果。两条命令:Redis 需两次解析 RESP 格式,两次分发命令,且需分配内存来格式化两个独立的响应内容。

从 Redis 3.0.3 开始,EXISTS 命令已更新为支持多个键(EXISTS key [key ...])。如果多次传入完全相同的键,Redis 会将其计入每次出现的情况。

因此,如果键 hello 存在,执行 EXISTS hello hello 将返回 (Integer) 2。虽然从技术上讲,服务器会在内存中执行两次哈希表查找,但额外查找所消耗的纳秒级 CPU 成本,远低于通过省去第二次网络请求所节省的时间和资源。

2.5. DEL 命令

bash 复制代码
# 语法
DEL key [key ...]

DEL 命令是一个基础且常用的 Redis 键空间命令,主要用于删除一个或多个指定的 key,如果在操作中遇到了不存在的 key,该命令会自动将其忽略。它的基本语法为 DEL key [key ...]。命令执行完成后,会返回一个整数类型的响应(Integer reply),用来表示实际成功被移除的 key 的总数。此外,开发者需要注意,在 Redis 集群(clustered Redis environments)环境中执行该命令时,其行为可能会因多键操作的规则而有所不同。

在性能和时间复杂度方面,DEL 命令的整体复杂度为 O(N),其中 N 代表即将被移除的 key 的数量。针对单个被删除的 key,其耗时取决于所存储的数据类型:如果该 key 存储的是普通的字符串(string)值,那么删除它的时间复杂度仅为 O(1);但如果该 key 存储的是诸如列表(list)、集合(set)、有序集合(sorted set)或哈希(hash)等非字符串形式的复杂结构,那么删除这个 key 的时间复杂度就会变成 O(M),这里的 M 代表该数据结构内部实际包含的元素个数。

bash 复制代码
del heeello
del hcllo

Redis 中的 DEL 和 MySQL 中的 DROP 属于不同层级的操作。因为 DEL 用于删除指定的 Key 及其关联的 Value,删除完之后该 Key 消失,该 Key 占用的内存也会被释放。而 DROP 属于 数据定义语言,用于彻底销毁数据库对象,删除完之后,除非有备份,否则表不再存在。

2.6. EXPIRE 命令

bash 复制代码
EXISTS key [key ...]

EXPIRE 命令是 Redis 中非常基础且高频使用的键空间指令,主要功能是为指定的 key 设置生存时间(以秒为单位),其执行的时间复杂度为 O(1)。该命令的基本语法为 `EXPIRE key seconds [NX | XX | GT | LT]`。在 Redis 的术语中,被赋予了超时时间的 key 通常被称为"易失的"(volatile)。当设定的时间耗尽后,对应的 key 就会被系统自动删除。如果对一个 key 成功设置了超时时间,命令会返回整数 1;如果目标 key 不存在,或者因为用户提供的选项条件未满足而跳过了操作,则会返回整数 0。需要特别注意的是,如果为该命令传入了一个非正数的超时时间,该 key 会被立刻删除并触发 `del` 事件,而不是常规的 `expired` 事件。

关于过期状态的维护机制,只有当执行了诸如 `DEL`、`SET`、`GETSET` 等会直接删除或完全覆盖该 key 内容的指令时,其关联的超时时间才会被清除。如果仅仅是对 key 存储的数据进行局部或概念上的修改(例如使用 `INCR` 递增数值、使用 `LPUSH` 向列表追加元素或通过 `HSET` 修改哈希字段),其原有的超时时间将保持不变。开发者也可以随时使用 `PERSIST` 命令显式地清除超时限制,让 key 重新变回持久化状态。此外,当使用 `RENAME` 命令对 key 进行重命名时,相关的生存时间(TTL)会一并转移到新名称上;如果在重命名时覆盖了另一个已存在的 key,那么新的 key 将直接继承原有 key 的所有特性。

bash 复制代码
expire key1 10
get key1
# 10 秒之后再次查询
get key1

2.7. TTL 命令

bash 复制代码
# 语法
TTL key

TTL 用于查询并返回一个 key 的剩余过期时间,单位为秒。返回具体的剩余生存时间(整数,以秒为单位),如果指定的 key 存在,但没有设置任何关联的过期时间,命令将返回 -1,如果指定的 key 不存在,命令将返回 -2。执行的时间复杂度为 O(1)。

bash 复制代码
expire key2 15
ttl key2

2.8. Redis 的 key 过期策略

如果 Redis 里有百万级甚至千万级带过期时间的 key,直接遍历所有 key 检查过期会导致 CPU 被打满,严重影响服务性能,因此必须设计高效的过期清理方案。Redis 为了高效处理上述问题,采用了定期删除 + 惰性删除双策略组合,同时配合内存淘汰机制兜底。

  • 惰性删除:访问时触发删除

不会主动扫描过期 key,只有当客户端访问这个 key 时,Redis 才会检查它的过期时间:如果 key 已过期:立即删除该 key,并返回 nil 给客户端;如果 key 未过期:正常返回 key 的值。但这种策略存在内存泄漏风险------ 如果一个过期 key 永远不会被访问,它会一直占用内存,直到 Redis 重启或被其他机制清理。

  • 定期删除:定时抽样清理

Redis 会每隔一段时间(默认每秒 10 次,可通过 hz 配置调整),主动执行一次过期 key 清理操作:从所有带过期时间的 key 中,随机抽取一小部分(默认 20 个)进行检查;删除其中已经过期的 key;;如果本轮抽样中,过期 key 的比例超过 25%,则重复执行抽样删除,直到比例低于 25% 或达到本次执行的时间上限(默认 25ms),避免阻塞主线程。

2.9. TYPE 命令

bash 复制代码
# 语法
TYPE key

TYPE 命令主要用于查询并返回存储在指定 key 处的数据类型的字符串表示形式。其基本语法结构为 TYPE key。在执行后,如果指定的 key 存在,该命令会返回对应的数据类型(如 `string`、`list`、`set`、`zset`、`hash`、`stream` 或 `vectorset`);而如果该 key 不存在,命令则会返回 `none`。该命令的执行非常高效,时间复杂度仅为 O(1)。

相关推荐
一个有温度的技术博主2 小时前
告别单点瓶颈:Redis主从架构与读写分离实战
redis·分布式·缓存·架构
Devin~Y2 小时前
高并发内容社区实战面试:从 Java 基础到 Spring Cloud、Kafka、Redis、RAG 搜索全解析
java·spring boot·redis·spring cloud·kafka·向量数据库·rag
清水白石0082 小时前
《从缓存到数据库:一致性之痛与工程之道》
数据库·python·缓存
刘~浪地球4 小时前
Redis 从入门到精通(十):管道技术
数据库·redis·缓存
x***r15111 小时前
RedisStudio-en-0.1.5可视化管理工具安装步骤详解(附Redis可视化与Key管理教程)
redis
IGAn CTOU12 小时前
PHP使用Redis实战实录2:Redis扩展方法和PHP连接Redis的多种方案
开发语言·redis·php
iNgs IMAC13 小时前
redis 使用
数据库·redis·缓存
刘~浪地球15 小时前
Redis 从入门到精通(八):有序集合操作详解
数据库·chrome·redis
必胜刻17 小时前
Redis分布式锁讲解
数据库·redis·分布式