[Redis] redis常见命令和String字符串解析

开篇:为什么要先讲"预备知识"

很多初学者看到 Redis 命令时,会直接陷入"命令太多,要背不完"的状态。但实际上,Redis 命令背后有几条非常稳定的主线:key-value 模型、数据结构、内部编码、单线程执行、命令复杂度和使用场景。

学 Redis 不能只学命令怎么敲,还要理解命令背后的运行方式。这样后面学习 String、Hash、List、Set、Zset 时,才能知道为什么某些命令很快,为什么某些命令要谨慎使用,以及为什么 Redis 在高并发场景下表现这么好。

String 是 Redis 最基础的数据类型,但它并不只是"保存一段文本"这么简单。它还能保存数字、JSON、二进制数据,并且可以配合过期时间、条件写入、原子计数等能力,实现缓存、计数器、Session、验证码限流等常见业务。

一, 预备知识

全局命令:所有数据类型都会用到的 key 操作

Redis 有多种数据类型,但它们都围绕 key-value 展开。不同类型主要区别在 value,而 key 本身有一批通用命令。

常见全局命令包括:

命令 作用 复习重点
KEYS pattern 查找符合模式的 key 会遍历全部 key,时间复杂度 O(N),生产环境慎用
EXISTS key [key ...] 判断 key 是否存在 返回存在的 key 数量
DEL key [key ...] 删除一个或多个 key 返回实际删除的 key 数量
EXPIRE key seconds 设置秒级过期时间 缓存场景非常常用
TTL key 查看 key 剩余过期时间 -1 表示无过期时间,-2 表示 key 不存在
TYPE key 查看 key 的数据类型 可返回 stringlisthashsetzset

其中最需要警惕的是 KEYS。它看起来很方便,可以用通配符搜索 key,例如:

redis 复制代码
KEYS user:*

但它的时间复杂度是 O(N),也就是会扫描 Redis 当前库中的所有 key。如果线上 Redis 数据量很大,执行 KEYS 可能导致 Redis 阻塞,影响其他请求。因此它更适合开发、测试或数据量很小的场景。

EXPIRETTL 则是缓存设计的基础。一个 key 被设置过期时间后,到期会被 Redis 淘汰。使用 TTL 查看剩余时间时要记住两个特殊值:

text 复制代码
TTL = -1:key 存在,但没有设置过期时间
TTL = -2:key 不存在

数据结构和内部编码:Redis 对外简单,对内灵活

Redis 对外提供的数据结构是我们平时使用的类型,例如 String、Hash、List、Set、Zset。但 Redis 内部并不是只用一种固定方式保存这些结构,而是会根据数据规模和内容选择不同的内部编码。

常见关系如下:

对外数据结构 常见内部编码
string intembstrraw
hash ziplisthashtable
list ziplistlinkedlist、新版本常见 quicklist
set intsethashtable
zset ziplistskiplist

可以使用下面的命令查看某个 key 的内部编码:

redis 复制代码
OBJECT ENCODING key

内部编码的意义在于:Redis 可以在不改变外部命令的情况下优化底层实现。比如同样是列表,小数据量时可以使用更节省内存的编码;数据量变大后,再切换到更适合大量元素操作的编码。

这对使用者来说是无感的。我们仍然使用相同的 Redis 命令,但 Redis 会尽量选择更合适的存储方式。这也是 Redis 兼顾易用性和性能的重要原因之一。

单线程模型:快,但怕慢命令

Redis 的命令执行采用单线程模型。这里的单线程主要指命令执行阶段:多个客户端可以同时连接 Redis,但 Redis 实际处理命令时,会把命令排队,然后按顺序一个个执行。

这带来一个好处:单条命令天然具有顺序执行的原子性。

比如两个客户端同时执行:

redis 复制代码
INCR counter

最终 counter 一定会被加两次,不会出现多个线程同时修改同一个变量时的竞争问题。因为 Redis 不会同时执行两条命令。

那为什么单线程还能这么快?主要原因有三点:

  1. Redis 数据主要存放在内存中,内存访问速度远快于磁盘。
  2. Redis 使用非阻塞 I/O 和 I/O 多路复用机制,可以高效处理大量客户端连接。
  3. 单线程避免了线程切换、锁竞争、共享数据同步等额外开销。

不过,单线程也意味着一个明显风险:如果某条命令执行很久,后面的所有命令都必须等待。

因此使用 Redis 时要特别小心这些情况:

  • 大量 key 场景下执行 KEYS
  • 一次 MGET/MSET 传入过多 key
  • 操作大 key
  • 使用高复杂度命令处理大量数据

可以把 Redis 理解为一个非常快的单窗口服务台。它处理每个请求都很快,所以整体吞吐很高;但如果某个请求特别耗时,后面排队的人都会被卡住。

二, String 字符串

String 是 Redis 最基础的数据类型

String 是 Redis 中最基础、最常用的数据类型。需要注意的是,Redis 中所有 key 本身都是字符串,而 String 类型说的是 value 也是字符串结构。

Redis 的 String 不只可以保存普通文本,还可以保存:

  • 普通字符串,例如 "hello"
  • JSON 或 XML 文本
  • 整数或浮点数
  • 二进制数据,例如图片、音频、视频片段

一个 String 最大不能超过 512 MB。Redis 内部按照二进制安全的方式保存字符串,不主动处理字符集编码。也就是说,客户端传入什么字节,Redis 就保存什么字节。

基础读写命令:SET、GET、MSET、MGET

String 最基础的读写命令是 SETGET

redis 复制代码
SET name "James"
GET name

如果 key 已经存在,SET 会直接覆盖旧值。这里有一个容易忽略的点:SET 覆盖旧值时,会清除原来的 TTL。

例如某个缓存 key 原本 10 分钟后过期,如果再次执行普通 SET key value,它就会变成永不过期,除非重新指定过期时间。

因此缓存场景更推荐直接写成:

redis 复制代码
SET user:1001 "{...json...}" EX 3600

SET 还支持几个常用选项:

写法 含义
SET key value EX seconds 设置值,并设置秒级过期时间
SET key value PX milliseconds 设置值,并设置毫秒级过期时间
SET key value NX key 不存在时才设置
SET key value XX key 存在时才设置

MGETMSET 用于批量读写:

redis 复制代码
MSET k1 v1 k2 v2 k3 v3
MGET k1 k2 k3

批量命令的优势是减少网络往返。如果执行 1000 次 GET,客户端和 Redis 之间要来回通信 1000 次;如果使用一次 MGET 获取 1000 个 key,就只需要一次网络请求。

但批量不是越大越好。因为 Redis 单线程执行命令,一次批量操作太大,也会让这条命令执行时间过长,从而阻塞后续请求。

条件写入:SETNX 和 SET NX

SETNX 的含义是:只有 key 不存在时才设置成功。

redis 复制代码
SETNX lock:order:1001 1

成功返回 1,失败返回 0

现在更常见的写法是使用 SET key value NX

redis 复制代码
SET lock:order:1001 1 NX EX 30

这种写法可以同时完成"只有不存在才写入"和"设置过期时间",在很多限流、去重、简单锁场景中都很有用。

计数命令:String 不只是字符串,也能做数字

String 可以保存数字,因此 Redis 提供了一组计数命令:

命令 作用
INCR key 数值加 1
INCRBY key n 数值加 n
DECR key 数值减 1
DECRBY key n 数值减 n
INCRBYFLOAT key n 浮点数加 n,n 可以是负数

如果 key 不存在,Redis 会把它当作 0 处理。比如:

redis 复制代码
INCR article:1001:view

如果 article:1001:view 不存在,执行后结果就是 1

由于 Redis 命令是单线程顺序执行的,INCR 这类命令天然适合做高并发计数。它不需要像一些多线程系统那样额外使用 CAS 机制来保证计数正确。

但要注意:如果 key 对应的 value 不是合法整数或浮点数,计数命令会报错。

字符串追加和范围操作

String 还支持一些偏底层的字符串操作:

命令 作用
APPEND key value 在原字符串末尾追加内容
GETRANGE key start end 获取指定范围的子串
SETRANGE key offset value 从指定偏移位置开始覆盖字符串
STRLEN key 获取字符串长度

例如:

redis 复制代码
SET greeting "Hello World"
SETRANGE greeting 6 "Redis"
GET greeting

最终结果是:

text 复制代码
Hello Redis

这些命令适合处理较短字符串。如果字符串很大,范围读取或覆盖也会产生更高的处理成本。

String 的内部编码

String 的内部编码主要有三种:

编码 使用场景
int 可以用 8 字节长整型表示的整数
embstr 小于等于 39 字节的短字符串
raw 大于 39 字节的长字符串

例如:

redis 复制代码
SET key 6379
OBJECT ENCODING key

可能返回:

text 复制代码
int

如果保存的是短字符串,例如 "hello",可能使用 embstr;如果字符串较长,则使用 raw

这再次说明:Redis 对外提供的是统一的 String 类型,但内部会根据内容自动选择更合适的编码。

三, String 的典型业务场景

场景一:缓存

String 最经典的用法是缓存。常见架构是 Redis 作为缓存层,MySQL 等数据库作为存储层。

基本流程如下:

  1. 业务请求先查询 Redis。
  2. 如果 Redis 命中,直接返回缓存结果。
  3. 如果 Redis 未命中,再查询数据库。
  4. 将数据库结果序列化成 JSON,写入 Redis 并设置过期时间。
  5. 返回数据。

示例:

redis 复制代码
SET user:info:1001 "{...json...}" EX 3600

这种方式可以让热点数据大部分时间从 Redis 返回,减少数据库压力。

设计缓存 key 时,推荐使用有层次的命名方式:

text 复制代码
业务名:对象名:唯一标识:属性

例如:

text 复制代码
shop:user_info:1001
shop:user_info:1001:name

key 名要清晰,但也不要过长。过长的 key 会增加内存占用和网络传输成本。

场景二:计数器

视频播放量、文章阅读量、点赞数、接口调用次数,都可以用 String 的计数命令实现。

redis 复制代码
INCR video:5253:play_count

这种计数方式简单、高效、原子性好。真实项目中,还需要进一步考虑防刷、异步落库、按时间维度统计、数据持久化等问题。

场景三:共享 Session

在分布式 Web 服务中,如果每台服务器各自保存 Session,用户请求被负载均衡到另一台服务器时,可能会出现登录状态丢失。

把 Session 集中存储到 Redis 后,所有 Web 服务器都从 Redis 读取和更新 Session,就能解决这个问题。

常见形式:

redis 复制代码
SET session:token:abc123 "{...user info...}" EX 7200

这里的过期时间也很重要。Session 不应该永久存在,通常需要设置合理的有效期。

场景四:手机验证码和简单限流

验证码场景可以组合使用 SET NXEXPIREINCRGET

一个常见思路是:

  1. SET phone:limit:手机号 1 EX 60 NX 创建一分钟发送窗口。
  2. 如果 key 已存在,说明一分钟内已经请求过,再用 INCR 增加请求次数。
  3. 如果次数超过限制,例如超过 5 次,则拒绝发送。
  4. 生成验证码后,用 SET phone:code:手机号 验证码 EX 300 保存 5 分钟。
  5. 用户提交验证码时,用 GET 取出并比对。

示例:

redis 复制代码
SET sms:limit:13800138000 1 EX 60 NX
INCR sms:limit:13800138000
SET sms:code:13800138000 637928 EX 300

这个场景很好地体现了 String 的组合能力:它本身很简单,但配合过期时间、条件写入和原子计数,就能解决不少高频业务问题。

四, 复习时最该记住的点

  1. Redis 的数据类型是 value 的类型,key 本身都是字符串。
  2. 全局命令作用于 key,EXPIRETTLTYPE 是复习重点。
  3. KEYSO(N) 命令,生产环境要谨慎。
  4. Redis 对外是数据结构,对内是内部编码,内部编码会自动适配数据情况。
  5. Redis 单线程执行命令,所以单条命令具有顺序执行的原子性。
  6. 单线程模型很快,但怕慢命令;大 key、大批量、高复杂度命令都可能阻塞。
  7. String 可以保存文本、数字、JSON、二进制数据,最大 512 MB。
  8. SET 会覆盖旧值,并清除原 TTL,缓存场景要特别注意。
  9. MGET/MSET 能减少网络开销,但批量过大也会造成阻塞。
  10. INCR/DECR 系列是实现高并发计数器的核心。

总结

不是记住几个零散命令,而是要建立 Redis 的基础理解:所有操作都围绕 key-value 展开,Redis 对外提供清晰的数据结构,对内通过不同编码优化性能,并通过单线程模型实现简单而高效的命令执行。

理解 String 的基础地位。它既是最简单的数据类型,也是很多业务能力的起点。缓存、计数器、共享 Session、验证码限流这些场景,本质上都是在使用 String 的存储、过期、条件写入和原子计数能力。

相关推荐
Database_Cool_1 小时前
企业级多模态分析计算引擎选型:阿里云 AnalyticDB MySQL 统一分析平台方案
数据库·mysql·阿里云
阿演1 小时前
我把这个桌面数据库工具又升级了一轮:现在支持 ClickHouse,还能可视化建表和改表了
数据库·clickhouse·ai编程·数据库连接工具
J.Kuchiki1 小时前
【PostgreSQL内核学习 —— 外部排序生成与归并】
数据库·学习·postgresql
SAP庖丁解码2 小时前
SAP 物料凭证表详解
数据库
Jul1en_2 小时前
【Redis】一文讲透缓存更新策略与缓存预热、穿透、雪崩、击穿
数据库·redis·缓存
189228048612 小时前
NV041固态MT29F16T08GSLCEM9-QBES:C
人工智能·算法·microsoft·缓存·性能优化
Database_Cool_2 小时前
AnalyticDB MySQL vs Apache Doris:企业级云数仓如何选型——全维度对比指南
数据库·数据仓库·mysql·阿里云
心翼叶少2 小时前
Redis(二):设置密码
数据库·redis·缓存
_Kafka_2 小时前
Oracle平均成本计算流程
数据库·oracle