redis-cheatsheet

面向 Go 开发者的 Redis 实战速查表,按常用度整理命令,便于开发中快速查阅。

按需求查找

想做什么 优先查哪里 代表操作
缓存、验证码、计数、条件写入 字符串 SET、GET、INCR、SET ... NX EX
过期时间、删缓存、找 key 通用键操作 EXPIRE、TTL、UNLINK、SCAN
存对象、改字段、记录投票方向 哈希 HSET、HGET、HINCRBY
排行榜、帖子排序、按分数筛选 有序集合 ZADD、ZRANGE、ZINCRBY
去重、成员判断、共同关注 集合 SADD、SISMEMBER、SINTER
简单队列、保留最近若干条记录 列表 RPUSH、BLPOP、LTRIM
批量请求、原子更新、比较后修改 批处理与事务、Lua 脚本 Pipeline、MULTI、WATCH、EVAL
连接调试、服务端时间、慢命令 连接与诊断、redis-cli PING、TIME、INFO、SLOWLOG GET
消息确认、失败后重新处理 流 XREADGROUP、XACK、XAUTOCLAIM
实时广播、签到、估算去重数、附近的人 发布订阅、位图与位域、HyperLogLog、地理空间 PUBLISH、SETBIT、PFCOUNT、GEOSEARCH
在 Go 中调用 Redis go-redis .Result()、.Err()、ZAddNX、NewScript

读表时常见的词 key 是 Redis 键名;field 是 Hash 字段;member 是 Set/ZSet 成员;score 是 ZSet 分数;TTL 是剩余生存时间。nil 表示空回复,和空字符串、数字 0 不同。相同选项在不同命令中可能含义不同,以所在行的说明为准。

字符串

用于缓存字符串或序列化后的 JSON,也可保存供计数命令操作的数值。

命令 示例 注释
SET SET user:1:name Jasper 设置或覆盖值,包括覆盖其他数据类型;默认清除原 TTL。
GET GET user:1:name 读取字符串;key 不存在返回 nil,类型不符报错。
SET ... EX / PX SET session:1 token EX 1800 原子写入并设置 TTL;EX 为秒,PX 为毫秒。
SET ... NX SET lock:job random-token NX EX 30 仅在 key 不存在时写入;成功返回 OK,未写入返回 nil。
MGET MGET user:1:name user:2:name 批量读取,顺序与参数一致;不存在或非字符串的项返回 nil。
MSET MSET user:1:name Jasper user:2:name Lee 原子批量写入;覆盖目标值并清除各 key 原 TTL,不支持 EX。
INCR / DECR INCR page:views 整数加 1 / 减 1,返回新值;不存在按 0 处理。
INCRBY / DECRBY DECRBY stock:1 2 按指定整数增减,返回新值;不会自动阻止库存变成负数。
INCRBYFLOAT INCRBYFLOAT weight:1 0.5 增加浮点数,可用负数减少;金额精确计算宜使用最小单位整数。
GETEX GETEX session:1 EX 1800 读取并刷新 TTL;PERSIST 可移除 TTL;不带选项则不改 TTL。
GETDEL GETDEL reset:token 原子读取并删除字符串 key;不存在返回 nil。
SET ... XX SET session:1 new-token XX EX 1800 仅在 key 已存在时写入;不满足条件返回 nil。
SET ... KEEPTTL SET user:1:name Lee KEEPTTL 覆盖值并保留原 TTL;原来不存在则创建无 TTL 的 key。
SET ... GET SET counter 0 GET 写入新值并返回旧字符串值;旧值不存在返回 nil,写入仍可能成功。
SET ... EXAT / PXAT SET token:1 abc EXAT 1893456000 按 Unix 秒 / 毫秒时间戳设置到期时间,示例时间应替换。
MSETNX MSETNX a 1 b 2 所有目标 key 都不存在才全部写入;成功 1,否则 0。
STRLEN STRLEN user:1:name 返回字节长度,非 Unicode 字符数;不存在返回 0。
APPEND APPEND text " world" 追加字符串,返回追加后的字节长度;不存在则创建。
GETRANGE GETRANGE text 0 4 按字节下标截取,首尾均包含;支持负下标。
SETRANGE SETRANGE text 6 Redis 从字节偏移量 6 开始覆盖;越界的空隙用零字节填充。
MSETEX MSETEX 2 a 1 b 2 EX 60 8.4+。原子批量写入并设置统一 TTL;2 是 key 数量。
SET ... IFEQ SET state:1 done IFEQ pending KEEPTTL 8.4+。当前值等于 pending 才写入,适合简单比较后更新。
DELEX ... IFEQ DELEX lock:job IFEQ random-token 8.4+。值匹配才原子删除;成功 1,未删除 0。

锁的边界 random-token 应替换为每次加锁生成的唯一随机值。释放锁必须比较令牌后原子删除;旧版本使用 Lua,不能直接 DEL。锁到期不代表业务已经结束,需要严格互斥的业务还须处理执行超时、续期和故障切换问题。

通用键操作

适用于各种数据类型,字段级 TTL 则见 Hash 部分。

命令 示例 注释
DEL DEL cache:user:1 cache:user:2 删除一个或多个 key,返回实际删除数量。
UNLINK UNLINK cache:large 立即移除 key,内存异步回收;清理大 key 时优先考虑。
EXISTS EXISTS user:1 user:2 返回存在的 key 数量;重复传入同一 key 会重复计数。
EXPIRE / PEXPIRE EXPIRE session:1 1800 设置秒 / 毫秒 TTL;成功 1,key 不存在等情况返回 0。
TTL / PTTL TTL session:1 返回剩余秒 / 毫秒;-1 为无 TTL,-2 为 key 不存在。
SCAN SCAN 0 MATCH user:* COUNT 100 返回下一游标和一批 key;继续传回游标,直到返回 0。
TYPE TYPE user:1 查看数据类型;不存在返回 none。
EXPIRE ... NX / XX EXPIRE session:1 1800 NX 7.0+。NX 仅在尚无 TTL 时设置;XX 仅在已有 TTL 时设置。
EXPIRE ... GT / LT EXPIRE session:1 3600 GT 7.0+。仅延长 / 缩短到期时间;无 TTL 按无限远处理。
PERSIST PERSIST session:1 移除 key 的 TTL;成功 1,不存在或原本无 TTL 返回 0。
EXPIREAT / PEXPIREAT EXPIREAT token:1 1893456000 按 Unix 秒 / 毫秒时间戳设置到期时间。
EXPIRETIME / PEXPIRETIME EXPIRETIME token:1 7.0+。读取绝对到期时间戳;-1 无 TTL,-2 不存在。
SCAN ... TYPE SCAN 0 MATCH user:* COUNT 100 TYPE hash 只返回指定类型;过滤不会变成按类型建立的索引查询。
RENAME RENAME user:1 user:1001 重命名并保留源 key 的 TTL;会覆盖目标 key,源不存在报错。
RENAMENX RENAMENX user:1 user:1001 仅在目标不存在时重命名;成功 1,目标存在 0。
COPY COPY user:1 user:1:backup 复制 key;目标存在时默认不复制,加 REPLACE 可覆盖。
KEYS KEYS user:* 一次扫描并返回所有匹配 key;可能阻塞服务,仅限受控调试。

TTL EXPIRE key 0、负 TTL 或过去的绝对到期时间会立即删除 key。INCR、HSET、LPUSH 等修改已有值的操作通常保留整个 key 的 TTL;普通 SET、MSET 覆盖值会清除 TTL。新建 key 也不会自动获得 TTL。

SCAN COUNT 100 是工作量提示,不保证返回 100 条;一轮可能为空或出现重复项。只有返回游标 0 才结束,不能用“本轮为空”判断结束。扫描无序且不提供快照,也不能直接当业务分页接口。HSCAN、SSCAN、ZSCAN 同样遵循这些规则。

哈希

用于对象字段、局部更新,以及 用户 ID → 投票方向 等映射。

命令 示例 注释
HSET HSET user:1 name Jasper age 20 写入多个字段,存在则覆盖;返回新增字段数,更新已有字段也可能返回 0。
HGET HGET user:1 name 读取单个字段;key 或字段不存在返回 nil。
HMGET HMGET user:1 name age 按参数顺序返回多个字段;不存在的项为 nil。
HGETALL HGETALL user:1 返回全部字段和值;大 Hash 使用 HSCAN 分批读取。
HDEL HDEL user:1 email avatar 删除指定字段,返回实际删除数;最后一个字段删除后 key 也删除。
HEXISTS HEXISTS user:1 email 字段存在返回 1,否则 0。
HINCRBY HINCRBY user:1 login_count 1 字段整数值增加指定增量,返回新值;不存在按 0 处理。
HLEN HLEN user:1 返回字段数量;key 不存在返回 0。
HSETNX HSETNX user:1 created_by api 仅在字段不存在时写入;成功 1,已存在 0。
HSCAN HSCAN user:1 0 MATCH a* COUNT 100 游标遍历字段和值;MATCH 匹配字段名。
HINCRBYFLOAT HINCRBYFLOAT user:1 weight 0.5 字段浮点值增加指定增量,返回新值。
HKEYS / HVALS HKEYS user:1 分别返回全部字段名 / 值;大 Hash 慎用。
HSTRLEN HSTRLEN user:1 name 返回字段值的字节长度;字段不存在返回 0。
HRANDFIELD HRANDFIELD user:1 2 WITHVALUES 随机读取字段及值;正数数量不重复,负数允许重复。
HEXPIRE / HPEXPIRE HEXPIRE user:1 60 FIELDS 1 otp 7.4+。设置字段级秒 / 毫秒 TTL;1 是字段数量。
HTTL / HPTTL HTTL user:1 FIELDS 1 otp 7.4+。查看字段剩余秒 / 毫秒;字段无 TTL 为 -1,不存在为 -2。
HPERSIST HPERSIST user:1 FIELDS 1 otp 7.4+。移除指定字段的 TTL,不改变整个 key 的 TTL。
HSETEX HSETEX user:1 EX 60 FIELDS 1 otp 123456 8.0+。原子写入字段并设置其 TTL,避免两条命令间留下空隙。
HGETEX HGETEX user:1 EX 60 FIELDS 1 otp 8.0+。读取字段并刷新其 TTL。
HGETDEL HGETDEL user:1 FIELDS 1 otp 8.0+。原子读取并删除指定字段。

两层 TTL EXPIRE user:1 作用于整个 Hash,HEXPIRE 作用于字段;整个 key 到期时所有字段一起删除。HSET 覆盖字段会清除该字段自身的 TTL,但保留整个 key 的 TTL。

有序集合

成员唯一,按 score 排序,适合排行榜、帖子列表和时间索引。

读写与排序

命令 示例 注释
ZADD ZADD rank 100 u1 95 u2 添加或更新成员分数;默认返回新增成员数,不统计仅改分数的成员。
ZRANGE ZRANGE rank 0 9 按分数升序取前 10 名;下标从 0 开始,结束下标包含在内。
ZRANGE ... REV ZRANGE rank 0 9 REV 按分数降序取前 10 名;全部成员使用 0 -1。
ZRANGE ... WITHSCORES ZRANGE rank 0 9 REV WITHSCORES 返回成员及分数;WITHSCORES 不改变排序。
ZSCORE ZSCORE rank u1 读取成员分数;成员不存在返回 nil。
ZINCRBY ZINCRBY rank 10 u1 增加成员分数并返回新分数;不存在则以增量为初始分数。
ZREM ZREM rank u1 u2 删除成员,返回实际删除数。
ZCARD ZCARD rank 返回成员总数。
ZREVRANK / ZRANK ZREVRANK rank u1 返回降序 / 升序排名,从 0 开始;不存在返回 nil。
ZMSCORE ZMSCORE rank u1 u2 批量读取分数,保持参数顺序;不存在的项为 nil。
ZRANGE ... BYSCORE ZRANGE rank 80 100 BYSCORE 查询 80 <= score <= 100,按分数升序。
ZRANGE ... BYSCORE REV ZRANGE rank 100 80 BYSCORE REV 同一分数区间降序;参数顺序改成上界在前、下界在后。
ZRANGE ... BYSCORE LIMIT ZRANGE rank 100 80 BYSCORE REV LIMIT 0 10 从匹配结果中跳过 0 个、取 10 个;大偏移量仍有遍历开销。
ZCOUNT ZCOUNT rank 80 100 统计分数区间内的成员数量。
ZREMRANGEBYSCORE ZREMRANGEBYSCORE rank -inf 0 删除分数小于等于 0 的成员;返回删除数。
ZREMRANGEBYRANK ZREMRANGEBYRANK rank 0 9 删除升序排名前 10 个,即分数最低的 10 个。
ZSCAN ZSCAN rank 0 MATCH u* COUNT 100 游标遍历成员及分数;返回顺序不保证按分数排列。

条件写入与弹出

命令 示例 注释
ZADD ... NX ZADD rank NX 100 u1 只添加新成员,不覆盖已有成员的分数;对应 go-redis ZAddNX。
ZADD ... XX ZADD rank XX 110 u1 只更新已有成员,不新增;对应 ZAddXX。
ZADD ... GT / LT ZADD rank XX GT 120 u1 已有成员仅接受更高 / 更低分数;单用 GT、LT 仍允许新增。
ZADD ... CH ZADD rank CH 120 u1 返回新增和分数发生变化的成员总数;分数未变化不计入。
ZADD ... INCR ZADD rank XX INCR 10 u1 条件式增分,只能传一组分数和成员;条件不满足返回 nil。
ZPOPMAX / ZPOPMIN ZPOPMAX rank 2 原子移除并返回最高 / 最低分成员及分数,示例最多弹出 2 个。
BZPOPMAX / BZPOPMIN BZPOPMAX queue:priority 5 阻塞式弹出一个成员,超时单位秒;0 无限等待。
ZMPOP ZMPOP 2 z1 z2 MIN COUNT 3 7.0+。从第一个非空有序集合弹出最多 3 个最低分成员。
BZMPOP BZMPOP 5 2 z1 z2 MIN COUNT 3 7.0+。阻塞式 ZMPOP,首个参数是秒级超时。

集合运算与字典序

命令 示例 注释
ZINTERSTORE ZINTERSTORE common 2 z1 z2 交集存入目标;2 是输入 key 数,默认将相同成员分数相加。
ZINTERSTORE ... WEIGHTS ZINTERSTORE feed:go 2 posts:score community:go WEIGHTS 1 0 取两者交集并保留 posts:score 的分数;第二个输入可为 Set。
ZUNIONSTORE ZUNIONSTORE total 2 z1 z2 AGGREGATE MAX 并集存入目标;聚合可选 SUM、MIN、MAX,默认 SUM。
ZINTER / ZUNION ZINTER 2 z1 z2 WITHSCORES 直接返回交集 / 并集,可带分数;不创建目标 key。
ZDIFF / ZDIFFSTORE ZDIFF 2 z1 z2 WITHSCORES 返回第一个集合减去后续集合的差集;保存形式为 ZDIFFSTORE out 2 z1 z2。
ZINTERCARD ZINTERCARD 2 z1 z2 7.0+。只返回交集成员数量。
ZRANGESTORE ZRANGESTORE top10 rank 0 9 REV 将范围查询结果及原分数保存为新有序集合;会覆盖目标。
ZRANGE ... BYLEX ZRANGE names "[a" "(n" BYLEX 查字典序 a <= member < n;要求集合内所有成员分数相同。
ZLEXCOUNT ZLEXCOUNT names "[a" "(n" 统计指定字典序区间;同样要求所有分数相同。
ZREMRANGEBYLEX ZREMRANGEBYLEX names "[a" "(n" 删除指定字典序区间内的成员。

区间速记 分数默认包含边界,(80 表示不含 80,-inf / +inf 表示无穷。字典序用 [ 包含、( 排除,- / + 表示无界。普通按排名分页直接使用 start stop;LIMIT offset count 仅用于 BYSCORE 或 BYLEX。

排序与选项 同分成员按字节字典序排序,REV 也会反转同分顺序。NX 与 XX 互斥,NX、GT、LT 三者互斥。score 使用双精度浮点数,整数精确范围为 [-2^53, 2^53];更大的整数 ID 应作为字符串成员保存。

集合

无序、成员唯一,适合去重、标签和关系判断。

命令 示例 注释
SADD SADD tags:1 go redis 添加成员,重复项忽略;返回实际新增数。
SISMEMBER SISMEMBER tags:1 go 成员存在返回 1,否则 0。
SREM SREM tags:1 redis 删除成员,返回实际删除数。
SCARD SCARD tags:1 返回成员数量。
SMEMBERS SMEMBERS tags:1 返回全部成员,不保证顺序;大集合用 SSCAN。
SMISMEMBER SMISMEMBER tags:1 go redis 批量判断成员是否存在,按参数顺序返回 1 / 0。
SSCAN SSCAN tags:1 0 MATCH g* COUNT 100 游标遍历成员;第一项是 key,第二项是游标。
SINTER SINTER following:u1 following:u2 返回交集,例如两人共同关注的用户。
SUNION SUNION tags:1 tags:2 返回去重后的并集。
SDIFF SDIFF following:u1 following:u2 返回第一个集合中存在、后续集合中都不存在的成员。
SPOP SPOP pool 2 随机移除并返回最多 2 个成员。
SRANDMEMBER SRANDMEMBER pool 2 随机读取,不删除;正数量不重复,负数量允许重复。
SMOVE SMOVE pending done task1 原子移动一个成员到目标集合;成功 1,源中不存在 0。
SINTERSTORE SINTERSTORE common users:a users:b 交集写入目标集合,会覆盖目标。
SUNIONSTORE SUNIONSTORE all users:a users:b 并集写入目标集合,会覆盖目标。
SDIFFSTORE SDIFFSTORE only:a users:a users:b 差集写入目标集合,会覆盖目标。
SINTERCARD SINTERCARD 2 users:a users:b 7.0+。只计算交集数量;2 是输入 key 数。

列表

按插入位置排列,允许重复成员。常见 FIFO 队列使用 RPUSH 入队、LPOP / BLPOP 出队。

命令 示例 注释
RPUSH RPUSH queue job1 job2 从右端依次插入,结果为 job1, job2;返回列表长度。
LPOP LPOP queue 移除并返回左端元素;列表不存在返回 nil。
BLPOP BLPOP queue 5 无元素时最多等待 5 秒;返回 key 和元素,超时返回 nil。
LPUSH LPUSH recent item1 item2 从左端依次插入,最终左到右为 item2, item1。
RPOP / BRPOP BRPOP queue 5 从右端弹出;BRPOP 可按秒阻塞等待。
LRANGE LRANGE recent 0 9 返回前 10 个元素;首尾下标均包含,0 -1 返回全部。
LLEN LLEN queue 返回列表长度;不存在返回 0。
LTRIM LTRIM recent 0 99 只保留指定区间,示例保留前 100 个;其他元素删除。
LPOP / RPOP 带数量 LPOP queue 3 一次弹出最多 3 个元素,返回数组。
LMOVE LMOVE queue processing LEFT RIGHT 原子地从源左端弹出并推入目标右端;源为空返回 nil。
BLMOVE BLMOVE queue processing LEFT RIGHT 5 阻塞式移动,最后一个参数是秒级超时。
LREM LREM processing 1 job1 正数从左删、负数从右删,绝对值为数量;0 删除全部匹配项。
LINDEX LINDEX recent 0 读取指定下标;-1 表示最后一个,越界返回 nil。
LSET LSET recent 0 item0 修改指定下标的元素;key 不存在或下标越界报错。
LPOS LPOS recent item1 查找匹配元素的下标;无匹配返回 nil,COUNT 可取多个。
LINSERT LINSERT recent BEFORE item1 item0 在第一个匹配元素之前 / 之后插入;可选 BEFORE / AFTER。
LPUSHX / RPUSHX RPUSHX queue job3 仅在列表已存在时插入;不会创建新列表。
LMPOP LMPOP 2 q1 q2 LEFT COUNT 3 7.0+。从第一个非空列表弹出最多 3 个元素。
BLMPOP BLMPOP 5 2 q1 q2 LEFT COUNT 3 7.0+。阻塞式批量弹出,首个参数是秒级超时。

队列边界 上述阻塞命令的 0 表示无限等待。直接 LPOP / BLPOP 后消费者崩溃,消息可能丢失;LMOVE 到处理中列表仍需自行实现确认和超时重试。需要消费者组与待确认记录时,优先查看 Streams。

批处理与事务

先选机制,再查命令。单个 INCR、ZINCRBY 等命令本身已是原子操作。

机制 适用情况 注意
Pipeline 批量执行互不依赖的请求,减少网络往返 不保证整批原子性;结果在整批执行后读取。
MULTI + EXEC 多条已知命令需要连续执行,期间不插入其他客户端命令 没有传统数据库式回滚。
WATCH + 事务 在 Go 中先读值,再计算,提交前检查值是否被修改 冲突后重读并有限重试;必须在同一连接完成。
Lua 根据 Redis 中的当前值判断并更新,例如扣库存、投票、释放锁 服务端原子执行,但运行错误不会撤销此前写入。
命令 示例 注释
MULTI MULTI 开始事务,后续命令先排队,通常返回 QUEUED。
EXEC EXEC 执行队列,返回各命令结果;WATCH 冲突时返回 nil,整批不执行。
WATCH WATCH stock:1 监视 key;必须在 MULTI 前调用,修改、过期、淘汰都可能导致冲突。
DISCARD DISCARD 丢弃尚未执行的事务队列,同时取消监视。
UNWATCH UNWATCH 取消当前连接对所有 key 的监视。

同一交互连接中逐行执行下面的命令,可将计数与设置 TTL 放入一个事务。

MULTI
INCR counter:demo
EXPIRE counter:demo 60
EXEC

这会在每次执行时刷新 TTL。固定窗口计数通常只在首次计数时设置 TTL,需要 Lua 或其他条件式实现。事务执行阶段某条命令失败,其他命令仍可能成功;不要把返回错误理解成“全部没有执行”。

Lua 脚本

执行与管理

命令 示例 注释
EVAL EVAL "return redis.call('GET', KEYS[1])" 1 user:1:name 执行脚本;1 是 key 数量,后面先传 key,再传普通参数。
EVALSHA EVALSHA <sha1> 1 user:1:name 用已缓存脚本的 SHA1 执行;缓存不存在返回 NOSCRIPT。
SCRIPT LOAD SCRIPT LOAD "return redis.call('GET', KEYS[1])" 缓存脚本并返回 SHA1,不执行;示例可供上一行使用。
SCRIPT EXISTS SCRIPT EXISTS <sha1> 检查指定脚本是否在当前服务器缓存中。
EVAL_RO / EVALSHA_RO EVAL_RO "return redis.call('GET', KEYS[1])" 1 user:1:name 7.0+。执行只读脚本;包含写操作会报错。

<sha1> 需替换为 SCRIPT LOAD 返回的值。脚本缓存可能因重启、故障切换等丢失,应用必须处理 NOSCRIPT;go-redis 的普通客户端调用可使用 NewScript(...).Run(...)。

脚本中常查的语法

操作 示例 注释
KEYS[n] local key = KEYS[1] 读取传入的 Redis key;所有访问的 key 都应显式传入,下标从 1 开始。
ARGV[n] local userID = ARGV[1] 读取普通参数;Redis 传入脚本的参数是字符串。
redis.call() local value = redis.call("HGET", KEYS[1], ARGV[1]) 调用 Redis 命令;命令错误会终止脚本。
tonumber() local n = tonumber(ARGV[2]) 转成数字;转换失败返回 nil,应先校验再比较或计算。
tostring() return tostring(score) 转成字符串;需要保留小数返回值时很有用。
TIME local now = tonumber(redis.call("TIME")[1]) 读取服务端当前 Unix 秒;第二项为当前秒内的微秒数。
local local delta = new - old 声明局部变量;Redis 脚本中的自定义变量应使用 local。
if ... then ... end if old == new then return 0 end 条件判断,支持 elseif 和 else。
== / ~= / >= if now >= deadline then return 0 end ~= 表示不等于;两侧应是可比较的值。
and / or / not if not n then return redis.error_reply("ERR invalid number") end 逻辑运算;Lua 中只有 false、nil 为假,数字 0 也为真。
false / nil if value == false then return 0 end 默认 RESP2 的空回复映射为 false;Lua 无值或转换失败用 nil。
return / {} return {old, new, delta} 返回数组式 table;默认协议转换中直接返回小数会截去小数部分。
for / # for i = 1, #ARGV do redis.call("SADD", KEYS[1], ARGV[i]) end #ARGV 取序列长度;循环只处理有界、少量数据。
redis.pcall() local r = redis.pcall("INCR", KEYS[1]) 捕获命令错误,错误回复可检查 r.err;不会自动回滚。
redis.error_reply() return redis.error_reply("ERR invalid argument") 显式返回 Redis 错误,客户端会收到非空 error。

数值检查 先处理不存在的值,再做转换。tonumber(value) or 0 会把“缺失”和“非法数值”都变成 0,只能在业务确实允许时使用。用户 ID 等标识通常保持字符串,不要为了比较而随意转成 Lua 数字。

执行边界 脚本执行期间会阻塞其他命令,不要在脚本里做全库扫描或大循环。先校验参数和数据类型,再开始写入。默认脚本内部使用 RESP2 转换规则,不能仅因客户端采用 RESP3 就把空值判断改成 nil。

连接与诊断

命令 示例 注释
PING PING 检查连接是否正常响应,通常返回 PONG。
TIME TIME 返回两个字符串,分别为 Unix 秒和当前秒内的微秒数。
INFO INFO server 查看版本与运行信息;常用分区有 memory、stats、clients、keyspace。
DBSIZE DBSIZE 当前逻辑数据库的 key 数量,不是某类集合的元素数量。
MEMORY USAGE MEMORY USAGE user:1 估算指定 key 的内存占用,单位字节。
SLOWLOG GET SLOWLOG GET 10 读取最近的慢命令;耗时不包含与客户端通信的时间。
SLOWLOG LEN SLOWLOG LEN 返回慢日志条数。
CLIENT LIST CLIENT LIST 查看客户端连接;连接很多时注意回复规模。
CLIENT SETNAME CLIENT SETNAME bluebell-api 命名当前连接,便于排障;连接池客户端通常通过配置统一设置。
CLIENT INFO / CLIENT ID CLIENT INFO 查看当前连接信息 / ID。
CLIENT GETNAME CLIENT GETNAME 读取当前连接名称。
AUTH AUTH default password 认证当前连接;不要把真实密码写入共享记录。
SELECT SELECT 1 切换当前连接的逻辑数据库;Redis Cluster 仅支持 DB 0。
HELLO HELLO 3 协商 RESP 协议;使用客户端库时通常由库处理。
ACL WHOAMI ACL WHOAMI 查看当前连接使用的 ACL 用户。
ACL LOG ACL LOG 10 查看最近的认证或权限拒绝记录,通常需要管理权限。
CONFIG GET CONFIG GET maxmemory maxmemory-policy 查看运行配置;一次传多个参数模式需要 7.0+。
OBJECT ENCODING OBJECT ENCODING user:1 查看内部编码,用于理解内存和性能,不等同于 TYPE。
LATENCY LATEST LATENCY LATEST 查看延迟监控事件;通常需先启用延迟监控阈值。
COMMAND INFO COMMAND INFO GET HEXPIRE 检查服务端是否认识这些命令;不支持的命令对应项为 nil。

Cluster 提醒 多 key 命令、事务和 Lua 通常要求相关 key 位于同一 hash slot。需要关联的 key 可使用相同 hash tag,例如 order:{123}:data 与 order:{123}:lock。扫描整个集群要遍历各主节点,单次 SCAN 只扫描当前节点。

redis-cli

以下是终端中的 Shell 命令,redis 是示例容器名。

命令 / 选项 示例 注释
本机连接 redis-cli 默认连接 127.0.0.1:6379 并进入交互模式。
指定地址 redis-cli -h 127.0.0.1 -p 6379 指定主机与端口。
认证 redis-cli --user default --askpass 交互输入密码;也支持预先配置 REDISCLI_AUTH 环境变量。
Docker 容器 docker exec -it redis redis-cli 从容器内连接 Redis;按实际情况替换容器名和认证参数。
单次执行 redis-cli GET user:1:name 执行一条命令后退出。
选择数据库 redis-cli -n 1 连接后选择 DB 1,不适用于 Cluster。
扫描 key redis-cli --scan --pattern 'user:*' 使用 SCAN 增量列出匹配 key;仍需考虑扫描负载和重复结果。
运行脚本文件 redis-cli --eval unlock.lua lock:job , random-token 逗号两侧要留空格;前面是 KEYS,后面是 ARGV。
大 key 排查 redis-cli --bigkeys 按类型统计字符串长度或容器元素数,不能直接当内存占用排名。
内存排查 redis-cli --memkeys 扫描 key 的内存占用;较新 CLI 可用 --keystats 综合统计。
延迟采样 redis-cli --latency 持续测量客户端到 Redis 的往返延迟。
实时统计 redis-cli --stat 持续输出 key 数、内存、连接、请求等统计。
跟随集群重定向 redis-cli -c -h 127.0.0.1 -p 6379 自动跟随 MOVED / ASK;不会自动聚合全节点扫描。
TLS 连接 redis-cli --tls --cacert ca.pem -h redis.example.com 使用 TLS 并验证服务端证书;不要用跳过验证代替正确配置。

CLI 选项是否可用取决于本机 redis-cli 的版本,可先运行 redis-cli --help。在 Shell 中执行原生命令时,*、>、$、( 等应按需加引号,例如 redis-cli XADD orders '*' id 1001。

流

Streams 可保存消息和消费者组的待确认记录。通常在业务处理成功后 XACK,处理逻辑应能承受重复投递。

生产、消费与确认

命令 示例 注释
XADD XADD orders * id 1001 status new 追加消息,* 自动生成消息 ID;返回实际 ID。
XGROUP CREATE XGROUP CREATE orders workers 0 MKSTREAM 创建组;0 从历史开始,$ 仅消费之后的新消息;MKSTREAM 可创建流。
XREADGROUP XREADGROUP GROUP workers c1 COUNT 10 BLOCK 5000 STREAMS orders > 读取该组未投递过的新消息,记录到 PEL;BLOCK 单位毫秒。
XACK XACK orders workers 1710000000000-0 从该组的待确认列表 PEL 移除;不会删除流中的消息。
XPENDING XPENDING orders workers 查看待确认消息总量、ID 范围及消费者概况。
XPENDING 明细 XPENDING orders workers - + 10 查看待确认消息 ID、所属消费者、空闲毫秒和投递次数。
XAUTOCLAIM XAUTOCLAIM orders workers c2 60000 0-0 COUNT 10 接管空闲至少 60000 毫秒的消息;按返回游标继续扫描,0-0 表示本轮结束。
XCLAIM XCLAIM orders workers c2 60000 1710000000000-0 接管指定的待确认消息;空闲阈值单位毫秒。
XREADGROUP 读待确认 XREADGROUP GROUP workers c1 COUNT 10 STREAMS orders 0 读取当前消费者自己尚未确认的消息,不是读取全部历史。
XREADGROUP ... CLAIM XREADGROUP GROUP workers c2 COUNT 10 CLAIM 60000 STREAMS orders > 8.4+。优先接管超时待确认消息,再按规则读取新消息;返回结构可能附带接管信息。
XACKDEL XACKDEL orders workers ACKED IDS 1 1710000000000-0 8.2+。确认消息;ACKED 仅在所有组都已读取并确认时删除消息。

普通读取、清理与管理

命令 示例 注释
XREAD XREAD COUNT 10 STREAMS orders 0-0 不使用消费者组;读取指定 ID 之后的消息,不写入 PEL。
XREAD ... BLOCK XREAD BLOCK 5000 COUNT 10 STREAMS orders $ 从当前末尾等待新消息;$ 仅用于首次定位,之后传上次最后读取的 ID。
XRANGE XRANGE orders - + COUNT 10 按 ID 升序读取,默认包含边界;- / + 表示最小 / 最大。
XREVRANGE XREVRANGE orders + - COUNT 10 按 ID 降序读取,取最近 10 条;上界在前。
XLEN XLEN orders 返回流中仍保留的消息数量。
XADD ... MAXLEN XADD orders MAXLEN ~ 10000 * id 1002 追加时顺便近似裁剪;~ 不保证长度严格等于上限。
XTRIM XTRIM orders MAXLEN ~ 10000 裁剪旧消息;可能影响尚未处理的消息,保留策略须覆盖重试窗口。
XDEL XDEL orders 1710000000000-0 删除流中的消息;不等同于对消费者组执行确认。
XINFO GROUPS XINFO GROUPS orders 查看消费者组及待确认量等状态。
XINFO CONSUMERS XINFO CONSUMERS orders workers 查看消费者及其待确认数量等状态。
XINFO STREAM XINFO STREAM orders 查看流长度、首尾 ID 等信息。
XGROUP CREATECONSUMER XGROUP CREATECONSUMER orders workers c2 显式创建消费者;通常也可由首次 XREADGROUP 自动创建。
XGROUP SETID XGROUP SETID orders workers 0 修改组的最后投递 ID;不等于清空 PEL,使用前确认重复投递影响。
XGROUP DELCONSUMER XGROUP DELCONSUMER orders workers c1 删除消费者;应先处理或转移其待确认消息,否则这些记录无法再接管。
XGROUP DESTROY XGROUP DESTROY orders workers 删除消费者组及其 PEL,不删除流中的消息。

BLOCK 0 表示无限等待;这里的单位是毫秒,和列表阻塞命令的秒不同。PEL 是已投递但尚未确认的记录;不能只读取 > 而从不处理 PEL。Streams 的持久性还取决于 Redis 的持久化和复制配置。

发布订阅

适合在线实时通知。Pub/Sub 不保存离线消息、不提供确认和重放,断线期间的消息会丢失。

命令 示例 注释
PUBLISH PUBLISH notice:user:1 updated 发布消息,返回接收客户端数;不代表业务处理成功。
SUBSCRIBE SUBSCRIBE notice:user:1 订阅频道并持续接收消息;通常使用专门的订阅连接。
UNSUBSCRIBE UNSUBSCRIBE notice:user:1 取消频道订阅;不带频道则取消当前连接的全部普通频道订阅。
PSUBSCRIBE PSUBSCRIBE notice:user:* 按 glob 模式订阅,* 可匹配多个字符。
PUNSUBSCRIBE PUNSUBSCRIBE notice:user:* 取消模式订阅。
PUBSUB NUMSUB PUBSUB NUMSUB notice:user:1 返回频道直接订阅者数,不包含模式订阅者。
PUBSUB CHANNELS PUBSUB CHANNELS notice:* 查看存在直接订阅者的匹配频道,不包含仅由模式订阅覆盖的频道。
SSUBSCRIBE / SPUBLISH SPUBLISH notice:{1} updated 7.0+。分片 Pub/Sub,配合 SSUBSCRIBE 使用;取消用 SUNSUBSCRIBE。

位图与位域

两者底层都是 String。位图保存单个 bit,位域把一段 bit 解释成整数。

位图

命令 示例 注释
SETBIT SETBIT signin:2026-09 17 1 设置第 17 个偏移位置的 bit,返回旧值;偏移量从 0 开始。
GETBIT GETBIT signin:2026-09 17 读取 bit;超出已有长度的位返回 0。
BITCOUNT BITCOUNT signin:2026-09 统计值为 1 的 bit 数,例如已签到天数。
BITCOUNT 字节范围 BITCOUNT flags 0 1 只统计第 0 到第 1 字节,首尾包含;默认范围单位为字节。
BITCOUNT ... BIT BITCOUNT flags 0 7 BIT 7.0+。按 bit 范围统计,示例统计前 8 位。
BITOP BITOP AND active:both active:d1 active:d2 位运算后保存到目标;常用 AND、OR、XOR、NOT,NOT 只接一个源。
BITPOS BITPOS flags 1 查找第一个值为 1 的 bit 位置;也可查 0。

业务中的“第 18 天”可映射为偏移量 17,需自行统一规则。设置很大的偏移量会扩展底层字符串,使用稀疏的大整数 ID 前应评估内存占用。

位域

命令 示例 注释
BITFIELD ... SET BITFIELD stats SET u8 0 10 从第 0 位写入 8 位无符号整数,返回旧值;i8 表示 8 位有符号整数。
BITFIELD ... GET BITFIELD stats GET u8 0 读取指定宽度和偏移的整数。
BITFIELD ... INCRBY BITFIELD stats INCRBY u8 0 1 对指定位域加 1,返回新值。
BITFIELD ... OVERFLOW BITFIELD stats OVERFLOW SAT INCRBY u8 0 1 WRAP 回绕、SAT 保持在上下界、FAIL 不修改并返回空项;默认 WRAP。
BITFIELD_RO BITFIELD_RO stats GET u8 0 只读执行位域 GET。

HyperLogLog

用于低内存的近似去重计数,不能取回成员,也不能判断某个成员是否已出现。

命令 示例 注释
PFADD PFADD uv:day u1 u2 加入观测值;返回结构是否变化,不能作为精确的新增人数。
PFCOUNT PFCOUNT uv:day 返回不同元素数量的估计值。
PFCOUNT 多 key PFCOUNT uv:d1 uv:d2 返回多个 HyperLogLog 并集的估计数量,不是简单相加。
PFMERGE PFMERGE uv:week uv:d1 uv:d2 合并多个 HyperLogLog 到目标 key。

地理空间

适合附近地点、距离计算。坐标顺序始终是经度在前、纬度在后。

命令 示例 注释
GEOADD GEOADD stores 113.26 23.13 gz 114.06 22.54 sz 写入或更新地点坐标;成员唯一。
GEOSEARCH GEOSEARCH stores FROMLONLAT 113.26 23.13 BYRADIUS 5 km ASC COUNT 10 WITHDIST 查中心坐标 5 千米内最近的 10 个地点,并返回距离。
GEOSEARCH ... FROMMEMBER GEOSEARCH stores FROMMEMBER gz BYBOX 10 20 km 以已有成员为中心,查宽 10、高 20 千米的矩形范围。
GEODIST GEODIST stores gz sz km 计算两个成员距离;单位可选 m、km、mi、ft。
GEOPOS GEOPOS stores gz sz 读取成员坐标,不存在的项返回 nil。
GEOSEARCHSTORE GEOSEARCHSTORE nearby stores FROMMEMBER gz BYRADIUS 5 km 将搜索结果保存到目标;加 STOREDIST 可用距离作为分数。
ZREM ZREM stores gz 删除地理成员;GEO 底层使用有序集合。
GEOHASH GEOHASH stores gz 返回位置的 geohash 字符串。

管理与高风险操作

以下操作可能修改配置、删除数据或增加负载,使用前确认实例、权限与备份。ASYNC 只改变释放内存的方式,不提供撤销能力。

命令 示例 注释
BGSAVE BGSAVE 后台生成 RDB 快照;创建子进程等过程仍可能带来停顿和内存压力。
LASTSAVE LASTSAVE 返回最近一次成功保存 RDB 的 Unix 秒时间戳。
BGREWRITEAOF BGREWRITEAOF 后台重写 AOF,重建更紧凑的日志;关注磁盘和内存资源。
CONFIG SET CONFIG SET maxmemory 512mb 修改运行配置;先确认内存限制与淘汰策略是否适合实例。
CONFIG REWRITE CONFIG REWRITE 将当前配置重写到启动配置文件;需要文件存在且可写。
MONITOR MONITOR 实时查看命令,开销大且可能暴露业务参数;仅短时、受控排障。
CLIENT KILL CLIENT KILL ID 42 关闭指定连接;可能影响正在处理的请求。
SCRIPT KILL SCRIPT KILL 尝试终止尚未修改数据的运行中脚本;已写入数据的脚本不能这样终止。
SCRIPT FLUSH SCRIPT FLUSH ASYNC 清空脚本缓存,后续 EVALSHA 可能收到 NOSCRIPT。
FLUSHDB FLUSHDB ASYNC 高危。删除当前逻辑数据库全部 key。
FLUSHALL FLUSHALL ASYNC 极高危。删除当前 Redis 实例所有逻辑数据库的 key。

Redis Cluster 的这些管理命令通常针对所连接节点;不要把单节点清理或快照误认为全集群操作。

go-redis

初始化与结果处理

安装并导入 github.com/redis/go-redis/v9,包名为 redis。示例按需导入标准库 context、errors、fmt、time。

go get github.com/redis/go-redis/v9

客户端在应用启动时创建并复用,退出时关闭;不要为每个请求创建客户端。ctx 使用调用方传入的上下文。下面片段位于能返回 error 的函数中,实际连接参数由配置提供。

rdb := redis.NewClient(&redis.Options{
	Addr:     "127.0.0.1:6379",
	Password: "", // 本地无密码示例;线上从配置或环境读取。
	DB:       0,
})
if err := rdb.Ping(ctx).Err(); err != nil {
	_ = rdb.Close()
	return fmt.Errorf("连接 Redis: %w", err)
}
// rdb 交给后续业务复用,在应用退出时调用 rdb.Close()。
写法 示例 注释
.Err() err := rdb.Set(ctx, "k", "v", time.Minute).Err() 只关心命令是否出错;常用于写操作。
.Result() value, err := rdb.Get(ctx, "k").Result() 同时取得返回值和错误,读取时优先使用。
.Val() value := cmd.Val() 只取值,不处理错误;应先检查该命令的错误。
.Int64() n, err := rdb.Get(ctx, "counter").Int64() 将字符串解析为整数;缺失、非法数字、溢出均需处理。
redis.Nil errors.Is(err, redis.Nil) 表示空回复,例如 GET 未命中、ZSCORE 成员不存在、阻塞读取超时。

HGETALL、LRANGE、SMEMBERS 查不到数据通常返回空容器和 nil 错误。MGET / HMGET 的未命中位于结果切片的 nil 项中;不能把所有“没数据”都统一判断为 redis.Nil。

value, err := rdb.Get(ctx, "user:1:name").Result()
switch {
case errors.Is(err, redis.Nil):
	// 缓存未命中,按业务决定是否回源。
case err != nil:
	return fmt.Errorf("读取缓存: %w", err)
default:
	fmt.Println(value) // 空字符串也可能是合法的命中值。
}

常用原生命令映射

以下列出调用表达式,实际使用时接收结果并检查错误。token 代表每次加锁生成的唯一随机令牌。

Redis 操作 go-redis 示例 注释
SET ... EX rdb.Set(ctx, "k", "v", 30*time.Second).Err() TTL 使用 time.Duration;0 表示写入后不设 TTL。
GET rdb.Get(ctx, "k").Result() 返回 string, error。
SET ... NX EX rdb.SetNX(ctx, "lock:job", token, 30*time.Second).Result() 返回 bool, error;条件不满足是 false, nil。
SET ... XX EX rdb.SetXX(ctx, "k", "v", time.Minute).Result() 只更新已有 key;返回布尔结果。
SET ... KEEPTTL rdb.Set(ctx, "k", "v", redis.KeepTTL).Err() 覆盖值并保留旧 TTL,和传 0 不同。
GETEX / GETDEL rdb.GetEx(ctx, "k", time.Minute).Result() 刷新 TTL 并读值;取后删除用 rdb.GetDel(ctx, "k")。
MGET rdb.MGet(ctx, "k1", "k2").Result() 返回 []any, error,未命中的项为 nil。
INCR / INCRBY rdb.IncrBy(ctx, "counter", 2).Result() 返回 int64, error;Incr 固定加 1。
DEL / UNLINK rdb.Unlink(ctx, "k1", "k2").Result() 返回删除数量和错误。
EXISTS rdb.Exists(ctx, "k1", "k2").Result() 返回存在数量,类型为 int64,并非布尔值。
EXPIRE rdb.Expire(ctx, "k", time.Minute).Result() 返回是否成功设置 TTL;ExpireNX 等对应条件选项。
TTL / PTTL rdb.TTL(ctx, "k").Result() 返回 time.Duration, error,特殊负值见表后说明。
HSET rdb.HSet(ctx, "user:1", "name", "Jasper", "age", 20).Result() 字段和值交替传入,也可使用 map[string]any。
HGET / HMGET rdb.HMGet(ctx, "user:1", "name", "age").Result() HGet 返回字符串,HMGet 返回保持字段顺序的切片。
HGETALL rdb.HGetAll(ctx, "user:1").Result() 返回 map[string]string, error;.Scan(&obj) 可映射 redis 标签字段。
HINCRBY rdb.HIncrBy(ctx, "user:1", "login_count", 1).Result() 返回字段的新整数值。
SADD / SISMEMBER rdb.SIsMember(ctx, "tags:1", "go").Result() SIsMember 返回布尔值;SAdd 返回新增数量。
LRANGE rdb.LRange(ctx, "recent", 0, 9).Result() 返回 []string, error,结束下标包含在内。
BLPOP rdb.BLPop(ctx, 5*time.Second, "queue").Result() 超时参数在 key 前;结果包含 key 和弹出的值。
ZADD rdb.ZAdd(ctx, "rank", redis.Z{Score: 100, Member: "u1"}).Result() redis.Z 保存成员和分数;可传多组。
ZADD ... NX / XX rdb.ZAddNX(ctx, "rank", redis.Z{Score: 100, Member: "u1"}).Result() 返回新增数;ZAddXX 只更新,成功也可返回 0,变更数需 Ch。
ZINCRBY rdb.ZIncrBy(ctx, "rank", 10, "u1").Result() 增量在成员前,返回新分数 float64。
ZSCORE / ZREVRANK rdb.ZScore(ctx, "rank", "u1").Result() 分数为 float64,排名为 int64;成员不存在时注意 redis.Nil。
ZRANGE rdb.ZRange(ctx, "rank", 0, 9).Result() 升序成员列表;倒序、分数区间使用下面的 ZRangeArgs。
TIME rdb.Time(ctx).Result() 返回 time.Time, error;.Unix() 是秒,.UnixMilli() 是毫秒。
任意已支持的原生命令 rdb.Do(ctx, "COMMAND", "INFO", "HEXPIRE").Result() 库暂无专用方法时的补充;不会让旧服务器获得新命令能力。

时间参数 不要把 30 当作 30 秒传入 time.Duration,应写 30*time.Second。TTL / PTTL 返回的哨兵值是 time.Duration(-1) 和 time.Duration(-2),直接判断 ttl == -1 / ttl == -2;不要和 -time.Second 比较,也不要先调用 .Seconds() 再判断。

名称对照 Redis 没有名为 ZAddNX 的原生命令,它是库对 ZADD ... NX 的封装。ZRangeByScore、ZRevRange 等旧方法在旧代码中仍常见,新写范围查询可统一使用 ZRangeArgs。

有序集合选项

// ZRANGE rank 100 80 BYSCORE REV LIMIT 0 10 WITHSCORES
items, err := rdb.ZRangeArgsWithScores(ctx, redis.ZRangeArgs{
	Key: "rank", Start: 100, Stop: 80,
	ByScore: true, Rev: true, Offset: 0, Count: 10,
}).Result()
if err != nil {
	return err
}
fmt.Println(items) // []redis.Z;Member 为成员,Score 为 float64。

只取降序前 10 名时使用 Start: 0, Stop: 9, Rev: true,不设置 ByScore、Offset、Count。只要成员列表则用 ZRangeArgs。组合 XX、GT、CH 时用 ZAddArgs,选项结构中的字段名是 XX、GT、Ch,成员放入 Members: []redis.Z{...}。

批处理、扫描与脚本

_, err := rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error {
	pipe.Set(ctx, "cache:a", "1", time.Minute)
	pipe.Set(ctx, "cache:b", "2", time.Minute)
	return nil
})
if err != nil {
	return err // 不代表整批都没有执行。
}

Pipelined 自动执行批处理;要用事务则改成 TxPipelined。手动创建 Pipeline() / TxPipeline() 后要调用 Exec(ctx)。有读命令时,等待批处理执行结束,再对保存的命令对象调用 .Result() 并检查各自错误。

乐观锁使用 rdb.Watch(ctx, func(tx *redis.Tx) error { ... }, keys...);回调中通过 tx 读取,再用 tx.TxPipelined 提交。errors.Is(err, redis.TxFailedErr) 表示监视冲突,应重读并有限重试。

iter := rdb.Scan(ctx, 0, "user:*", 100).Iterator()
for iter.Next(ctx) {
	fmt.Println(iter.Val())
}
if err := iter.Err(); err != nil {
	return err
}

迭代器代为推进游标,不会消除 SCAN 的重复结果或快照限制;Cluster 中需要遍历各主节点。

// 脚本对象创建一次并复用;释放锁前核对令牌。
var unlockScript = redis.NewScript(`
if redis.call("GET", KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
end
return 0
`)

func unlock(ctx context.Context, rdb *redis.Client, key, token string) (bool, error) {
	n, err := unlockScript.Run(ctx, rdb, []string{key}, token).Int64()
	if err != nil {
		return false, err
	}
	return n == 1, nil // false 表示本次未删除,可能已过期或令牌不匹配。
}

Run(ctx, rdb, keys, args...) 中,keys 必须是 []string,其余参数对应 ARGV;库自动填写 EVAL 的 key 数量。普通客户端的 Run 先尝试 EVALSHA,遇到 NOSCRIPT 后改用 EVAL。不要把这一自动回退直接套用于尚未执行的 Pipeline;批处理中需预加载脚本或使用 EVAL。

参考资料

命令名链接指向对应的 Redis 官方页面;版本标记表示本表写法的最低服务端版本。托管 Redis 的命令权限与可用性还应检查产品限制。

Redis 命令参考 · 事务 · Pipeline · Lua API · redis-cli · 分布式锁 · Cluster 规范

go-redis 官方指南 · go-redis API · ZSet 实现 · 脚本封装 · 返回值解析