腾讯云分布式缓存数据库基于单线程模型处理命令请求,不当的命令使用可能阻塞整个实例并影响全部业务。本文档从高复杂度命令、禁用命令、数据库选择、批量操作、事务、Lua 脚本、Monitor 命令、Hashtag 使用和消息队列限制等方面,定义命令使用的规范和准则。
一、关注 O(N) 命令中的 N
hgetall、lrange、smembers、zrange、sinter 等命令的时间复杂度为 O(N),使用时需要明确 N 的值。当 N 较大时,这些命令会长时间占用单线程,阻塞其他请求。
命令 | 风险说明 | 替代方案 |
HGETALL | 一次性返回哈希表所有字段,Key 内字段过多时阻塞严重 | 使用 HSCAN 游标分批遍历 |
SMEMBERS | 一次性返回集合所有成员 | 使用 SSCAN 游标分批遍历 |
ZRANGE | 一次性返回有序集合指定范围的所有成员 | 使用 ZSCAN 游标分批遍历或缩小查询范围 |
LRANGE | 一次性返回列表指定范围的所有元素 | 缩小范围或分页获取 |
SINTER | 多个集合求交集,元素越多耗时越长 | 在业务侧进行交集运算 |
说明:
使用 HSCAN、SSCAN、ZSCAN 命令时,建议指定合适的 COUNT 参数,每次遍历返回1000个元素左右是比较合适的选择。具体数量需根据实例配置和业务场景调整。
二、禁用命令
以下命令在生产环境中禁止或限制使用。Redis 基于单线程工作,这些命令执行时间过长或操作风险过高,容易导致命令执行阻塞或数据丢失。建议通过参数
disable-command-list 配置禁用。命令 | 风险说明 | 替代方案 |
KEYS | 遍历所有键匹配模式,阻塞 Redis 服务器 | 使用 SCAN 游标渐进式匹配 |
FLUSHDB | 清空当前数据库所有数据,不可恢复 | 通过 SCAN + DEL 渐进式删除 |
FLUSHALL | 清空实例所有数据库的全部数据,不可恢复 | 通过 SCAN + DEL 渐进式删除 |
SHUTDOWN | 关闭 Redis 服务器,导致服务中断和数据丢失 | 通过控制台管理实例生命周期 |
CONFIG | 修改服务器运行时配置,操作不当可能导致崩溃 | 通过控制台修改实例参数 |
以下命令不建议在生产环境频繁使用:
命令 | 风险说明 | 使用建议 |
RANDOMKEY | 随机返回一个键,会阻塞 Redis 服务器 | 仅在测试环境使用 |
INFO | 返回服务器统计信息,执行过程中阻塞其他请求 | 仅在问题排查时短时使用 |
BGREWRITEAOF | 异步重写 AOF 文件,消耗大量系统资源 | 由系统自动触发,避免手动执行 |
BGSAVE | 异步生成 RDB 快照,消耗大量系统资源 | 由系统自动触发,避免手动执行 |
说明:
在运维场景中,如确需使用 INFO 或 CONFIG 命令进行排查,应在低峰期短时操作,操作完毕后及时退出。
三、合理使用 Select
Redis 支持多数据库(Multi-DB),数据库索引号以0作为起始索引值,可通过
SELECT 命令随时切换。架构 | 使用建议 |
标准版 | 可根据多 DB 进行数据区分,但 Redis 本身基于单线程处理,多 DB 之间的请求会相互影响 |
集群版 | 建议优先使用0号 DB,非 0 DB 不支持扩容 |
说明:
在集群版场景中,客户端请求0号 DB 时可以不执行
SELECT 0,减少非必要的网络交互。四、适当使用批量操作
应用侧访问 Redis 时,较大一部分耗时来自网络 RTT。如果需要执行大量的 GET 或 SET 操作,可以使用批量命令降低网络开销。
方式 | 说明 | 适用场景 |
原生批量命令( MGET/MSET) | 原子操作,服务端一次性执行 | 批量读写同类型的 Key |
Pipeline | 非原子操作,客户端将多条命令打包发送 | 批量执行不同类型的命令 |
反面示例: 单次批量操作元素个数超过500,导致单次请求耗时过长,后端抖动或扩容时对业务影响较大。
MGET key1 key2 key3 ... key1000
正确示例: 将批量操作拆分为多次,每次控制在500个元素以内。
# 第一批MGET key1 key2 ... key500# 第二批MGET key501 key502 ... key800
说明:
控制一次批量操作的元素个数在500以内,同时注意批量操作的元素中是否存在大 Key。
原生批量命令是原子操作,Pipeline 是非原子操作。
Pipeline 可以打包不同的命令,原生批量命令不支持。
Pipeline 需要客户端和服务端同时支持。
五、不建议使用事务
Redis 的事务功能较弱,不支持回滚。在集群版场景中,一次事务操作的 Key 必须在同一个 Slot 上,否则事务执行将失败。
说明:
如果业务需要事务性保障,建议使用 Lua 脚本替代。Lua 脚本在服务端原子执行,但同样要求集群版中所有操作的 Key 位于同一个节点上。
六、集群版使用 Lua 的特殊要求
6.1 Key 必须通过 KEYS 数组传递
redis.call / redis.pcall 中调用的 Redis 命令,Key 的位置必须来自 KEYS 数组,否则返回错误:-ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array
6.2 操作的 Key 必须在同一个节点
单个 Lua 脚本操作的 Key 必须在同一个节点上,否则返回错误:
Lua script attempted to access a non local key in a cluster node
说明:
如需在 Lua 脚本中操作多个 Key,可通过 Hashtag 将相关 Key 分配到同一个哈希槽中。使用前请参见本文第八节 Hashtag 的使用建议。
七、关于 Monitor 命令
Monitor 命令用于实时输出 Redis 服务器接收到的命令流,对服务器性能有一定影响。
场景 | 使用建议 |
日常运行 | 不建议开启 Monitor |
问题排查 | 可短时开启用于分析命令执行情况,排查完毕后及时关闭 |
说明:
长时间开启 Monitor 会持续消耗服务器资源并占用输出缓冲区,导致性能下降。如无排查需求,请勿开启。
八、使用 Hashtag 建议
Hashtag 是 Redis 集群提供的一种特殊规则,用于通过特定语法强制将多个不同的键分配至同一个哈希槽(Hash Slot),以支持跨键操作。如使用不当,将导致严重的数据与请求倾斜问题,且该问题无法通过集群扩容解决。
8.1 Hashtag 使用不当的风险
风险类型 | 说明 |
数据倾斜(Memory Skew) | 大量使用相同 Hashtag 的键聚集在某一个节点上,导致该节点内存使用率远高于其他节点,可能提前触发内存告警或写满 |
请求倾斜(Hotspot) | 所有针对这些数据的读写请求命中同一个节点,使其成为性能瓶颈,导致延迟增加甚至拖垮整个集群 |
不可扩容性 | 哈希槽的计算依赖固定的 Hashtag,由此引发的倾斜问题无法通过增加集群节点来缓解 |
8.2 Hashtag 使用准则
准则 | 说明 |
最小化与拆分 | 不要为所有关联数据使用一个统一的 Hashtag,应按业务类型或功能模块使用不同的细粒度 Hashtag |
保证均匀分布 | 确保 Hashtag 值在整体上均匀分布,可在原始 ID 后添加后缀进行人工分片 |
仅在必要时使用 | 仅在必须使用事务、Lua 脚本或多键命令时才使用 Hashtag,无关的键不要滥用此特性 |
反面示例: 所有用户数据使用统一的 Hashtag,导致全部数据聚集在单一节点。
SET {global}:user:1001 "data1"SET {global}:user:1002 "data2"SET {global}:order:5001 "order_data"
正确示例: 按业务类型拆分 Hashtag,数据分散在不同节点。
SET {user:1001}:profile "data1"SET {user:1001}:session "session_data"SET {order:5001}:detail "order_data"
说明:
建议在系统设计阶段评审 Hashtag 的使用方案,上线后再调整需要对存量数据进行迁移,成本较高。
九、禁止将 Redis 作为消息队列
禁止将 Redis 当作消息队列使用。Redis 的发布/订阅和 List 结构不具备消息队列的核心能力,在容量、网络、效率和功能方面存在多种限制。
限制项 | 说明 |
消息持久化 | Redis 的 Pub/Sub 不持久化消息,消费者离线期间的消息将丢失 |
消息确认 | 不支持消费确认机制(ACK),无法保证消息被可靠消费 |
堆积能力 | List 结构作为队列时,消息堆积会大量占用内存,影响缓存性能 |
消费模型 | 不支持消费者组、消息分区等高级特性 |
说明:
如有消息队列需求,建议使用专业的消息中间件,例如 CKafka 或 TDMQ。