命令使用规范

最近更新时间:2026-04-24 10:57:51

我的收藏
KeeWiDB 兼容 Redis 协议,但在架构上属于磁盘型数据库,数据访问涉及磁盘 IO,其延迟特性与内存型 Redis 存在显著差异。由于磁盘操作耗时远高于内存,命令复杂度对响应时间的影响具有放大效应。为确保数据库响应时间及系统整体稳定性,本文档遵循"先规避风险、再规范用法"的原则,定义以下使用准则:
1. 禁用命令:明确禁止在生产环境执行的高危命令。
2. O(N) 命令管控:识别高复杂度命令的潜在风险,提供标准化替代方案。
3. 批量操作规范:定义单批次处理的数量阈值,防止磁盘 IO 累加导致请求超时。
4. 功能限制:界定存储架构层面的约束,规避非兼容特性调用。
5. Lua 脚本使用规范:约束脚本执行逻辑,确保其在分布式集群环境下的正确性。
6. Hashtag 使用规范:规范 Key 路由逻辑,防止数据分布倾斜。

一、禁用命令

受限于磁盘 IO 独占风险或数据安全考虑,以下命令不建议在生产环境的业务逻辑中直接调用。为确保系统吞吐量及响应延迟的稳定,本节提供了对应的标准化替代路径,建议在开发设计阶段优先采用。

1. 默认禁用命令清单

命令
禁用原因
替代方案
KEYS
对整个键空间执行全量扫描,复杂度 O(N)。在百万级 Key 的实例上,单次执行可能阻塞数据库数秒,影响所有并发请求
使用 SCAN 命令分批遍历
FLUSHALL / FLUSHDB
清空全部或当前库的数据,产生大量磁盘 IO 和 CPU 开销,且操作不可逆
通过控制台的清空实例功能执行,该操作具备二次确认和审计日志
CLIENT LIST
当连接数较高时(如数千并发),遍历并序列化所有连接信息会增加 CPU 和内存开销
通过提交工单获取连接信息

2. 自定义禁用

如需根据业务需求禁用其他命令,可通过调整参数 disable-command-list 进行配置。

二、O(N) 命令管控

KeeWiDB 的磁盘存储特性决定了 O(N) 命令的每个元素访问均可能涉及物理磁盘 IO。当 N 规模较大时,累计耗时将从毫秒级线性上升至秒级,不仅会导致当前请求超时,还会长时间占用后端执行线程,引发同节点其他请求的排队堆积。本节界定高危命令的识别标准,并提供标准化替代路径,用于指导开发阶段的方案选型。

1. 高危命令识别

以下命令在处理大规模数据集合时具有较高的执行风险,需严格评估其元素规模:
命令
风险说明
规范建议
HGETALL
一次性返回 Hash 全部字段。字段数达到数千级时,单次调用涉及数 MB 数据的磁盘读取与网络传输。
字段数 > 500 时禁用,改用 HGET/HMGET/HSCAN。
LRANGE
返回 List 指定范围元素。若执行 0 -1 等全量遍历操作,将引发持续的磁盘扫描。
禁止对未知长度的 List 执行全量查询,改为分段读取。
SMEMBERS
返回 Set 全部成员,将引发持续的磁盘扫描。
建议替换为 SSCAN
ZRANGE
返回有序集合成员。耗时随范围扩大呈线性增长,且涉及较多磁盘读。
控制 Range 区间,或改用 ZSCAN
SINTER/SUNION/ZINTERSTORE/ZINTERSTORE
多集合交集或并集运算。复杂度取决于参与集合的成员总数,在集合规模不对称时性能波动剧烈。
在业务层执行逻辑交集计算,减轻服务端压力。

2. 标准替代方案:游标式扫描(SCAN 类命令)

为规避大规模数据访问带来的阻塞风险,应采用 HSCANSSCANZSCAN 等游标式命令。通过分批迭代,将单次请求的 IO 耗时和传输数据量锁定在可控范围内。
反面示例(全量读取):当集合包含万级元素时,下述操作将导致数秒的独占阻塞。
# 潜在风险:字段数达 5000+ 时,触发秒级延迟
HGETALL cx:orderdb:order_index:hash

# 潜在风险:成员数达 10000+ 时,导致磁盘 IO 饱和
SMEMBERS cx:userdb:active_users:set
正确示例(分批迭代):通过设置合理的 COUNT 参数,平衡执行效率与系统稳定性。
# 分段获取,建议单次 COUNT 值在 100-500 之间
HSCAN cx:orderdb:order_index:hash 0 COUNT 200

# 配合模式匹配进行分批扫描(不指定COUNT值)
SSCAN cx:userd b:active users:set 0 MATCH U10*

3. COUNT 参数使用建议

使用场景
COUNT 参数建议
原因
未指定 MATCH 参数
指定合适的 COUNT 值(建议 ≤ 1000)
控制每轮扫描返回的元素上限,避免单次返回数据量过大
已指定 MATCH 参数
使用数据库默认值,不额外指定 COUNT
MATCH 过滤在扫描之后执行。若 COUNT 过大,可能出现"扫描了大量数据但匹配结果极少"的低效情况

三、批量操作规范

KeeWiDB 的数据主要存储在磁盘上,磁盘寻址耗时与网络往返耗时处于同一量级(均为毫秒级)。将多个命令打包发送所节省的网络往返时间,会被磁盘 IO 的线性累加所抵消——当单批次包含的 Key 数量超过阈值时,整批请求的总耗时将突破 Proxy 超时上限,引发请求积压与客户端报错。本节定义单批次操作的数量阈值与拆分策略,用于指导批量接口的设计与调用。

1. 数量限制

操作方式
数量限制
风险说明
规范建议
MGET / MSET
单次 ≤ 20个元素
每个 Key 的磁盘读取耗时线性累加,超限后整批耗时突破超时阈值。
超过20个 Key 时,拆分为多批顺序发送。
Pipeline
单次 ≤ 20条命令
打包命令在服务端串行执行,命令数过多将导致后端线程长时间占用。
超过20条命令时,拆分为多个 Pipeline 分批执行。

2. 代码实现规范

反面示例(单批超限):单次批量100个 Key,磁盘 IO 累加导致整批超时。
# 潜在风险:100 个 Key 的磁盘随机读累加,耗时可达数秒
MGET key1 key2 key3 ... key100
正确示例(分批发送):拆分为5批,每批20个,逐批发送。
# 第 1 批:20 个 Key,单批耗时可控
MGET key1 key2 key3 ... key20
# 第 2 批:20 个 Key
MGET key21 key22 key23 ... key40
# ...依次类推,共 5 批完成

四、功能限制

以下限制源于 KeeWiDB 的磁盘存储引擎与集群路由架构,属于引擎层面的固有约束而非配置可调项。若在开发阶段未识别这些限制,将在运行时触发命令报错或数据不一致。本节逐项界定限制范围、根因说明及标准化替代路径,用于指导选型与方案设计阶段的兼容性评估。

1. 仅支持 DB 0

KeeWiDB 不支持多 DB 切换,SELECT 命令将返回错误。
隔离需求
限制说明
替代方案
业务级隔离
多 DB 切换在磁盘引擎下涉及文件句柄与索引切换,架构不予支持。
通过 Key 前缀命名区分不同业务(如 cx:rx:)。
环境级隔离
同上。
部署独立实例(如生产实例和开发实例)。

2. 不支持事务

不支持事务相关命令:MULTIEXECWATCHUNWATCHDISCARD
原子性需求
限制说明
替代方案
单节点范围内的原子操作
集群架构下事务无法跨节点保证一致性,引擎层面不予支持。
使用 Lua 脚本实现(详见第五章),脚本内所有 Key 须路由到同一节点。

3. 禁止作为消息队列

KeeWiDB 的存储模型面向持久化键值访问,不具备消息队列所需的投递保障与消费确认机制。
机制
风险说明
规范建议
Pub/Sub
消息不做持久化,客户端断连后消息丢失,无法满足可靠投递要求。
谨慎使用。
List 模拟队列
缺乏 ACK 确认机制,消费失败后消息不可回溯,且磁盘 IO 下吞吐量远低于专业消息中间件。
不建议在生产环境使用。
如有消息队列需求,请使用专业消息中间件(如 CKafka、TDMQ),获取可靠投递、消费确认和消息回溯能力。

五、Lua 脚本使用规范

Lua 脚本可在 KeeWiDB 服务端原子执行多条命令,适用于需要原子性保障的业务场景(如库存扣减、状态流转)。但在集群版架构下,请求由 Proxy 根据 Key 路由到不同后端节点,脚本的 Key 引用方式和路由逻辑需满足特定约束——违反这些约束将导致 Proxy 路由失败、跨节点执行异常或脚本加载性能劣化。本节定义三条核心规则,确保脚本在分布式集群环境下的正确性与执行效率。

规则1:Key 必须通过 KEYS 数组传递

redis.call / pcall 中引用的所有 Key,必须通过 KEYS 数组传递,禁止硬编码在脚本中。Proxy 依赖 KEYS 数组判断路由目标节点;硬编码 Key 将导致 Proxy 无法解析路由信息,请求直接失败。
反面示例(Key 硬编码):Proxy 无法从脚本文本中提取路由信息,请求将返回路由错误。
# 潜在风险:Key 硬编码在脚本中,Proxy 无法识别路由目标
EVAL "redis.call('SET', 'cx:orderdb:order:202401150001:hash', 'paid')" 0
正确示例(KEYS 数组传递):Proxy 从 KEYS 数组提取路由信息,正确分发到目标节点。
# Key 通过 KEYS[1] 传递,Proxy 可正确计算哈希槽并路由
EVAL "redis.call('SET', KEYS[1], ARGV[1])" 1 cx:orderdb:order:202401150001:hash paid

规则2:单脚本所有 Key 必须位于同一节点

单个 Lua 脚本操作的所有 Key 必须路由到同一个节点。若 Key 分布在不同节点,脚本将执行失败。可通过 Hashtag(如 {order:202401150001})确保相关 Key 落在同一哈希槽。如下示例使用 Hashtag 将同一订单的多个属性 Key 绑定到同一哈希槽。
# 两个 Key 共享 Hashtag {order:202401150001},确保路由到同一节点
EVAL "redis.call('SET', KEYS[1], ARGV[1]); redis.call('SET', KEYS[2], ARGV[2])" 2 \\
{order:202401150001}:status {order:202401150001}:amount paid 12580

规则3:使用 EVALSHA 替代 EVAL

首次通过 SCRIPT LOAD 加载脚本后,后续调用应使用 EVALSHA 传入脚本的 SHA1 摘要。每次使用 EVAL 都会传输完整脚本文本并触发重新编译,在高频调用场景下将产生显著的网络开销与 CPU 消耗。建议部署阶段使用 SCRIPT LOAD 将脚本文本上传至服务端并获取 SHA1 摘要;运行阶段使用 EVALSHA 仅传输20字节的摘要值即可调用已缓存的脚本,避免每次请求都传输完整脚本文本。
# 部署阶段(执行一次):将脚本文本上传至服务端,服务端返回 SHA1 摘要
SCRIPT LOAD "redis.call('SET', KEYS[1], ARGV[1])"
# 返回:"a1b2c3d4e5f6..."

# 运行阶段(反复调用):仅传输 SHA1 摘要,服务端直接执行已缓存的脚本
EVALSHA a1b2c3d4e5f6... 1 cx:orderdb:order:202401150001:hash paid

六、Hashtag 使用规范

Hashtag 是集群版 KeeWiDB 提供的路由控制机制,通过在 Key 中使用花括号(如 {user}:name)指定哈希计算的子串,将多个 Key 强制分配到同一哈希槽。该机制在 Lua 脚本和多键命令中用于保证多 Key 路由到同一节点,但滥用将引发数据倾斜和请求倾斜,且倾斜一旦形成,无法通过集群扩容缓解。本节界定 Hashtag 的三大风险、使用原则及代码实现规范,用于指导架构设计阶段的路由策略评估。

1. 三大风险

Hashtag 将多个 Key 绑定到同一哈希槽,可能引发以下风险:
风险类型
风险说明
规范建议
数据倾斜
大量 Key 共用同一 Hashtag 时,数据集中在同一节点,该节点内存使用率偏高,可能提前触发告警甚至写满。
禁止使用宽泛 Hashtag(如 {global}{order}),按实体粒度拆分。
请求倾斜
与数据倾斜伴生——所有读写请求集中在同一节点,该节点延迟升高、CPU 使用率上升,拖累集群整体响应时间。
确保 Hashtag 值在整体上均匀分布。
不可扩容
哈希槽分配由 Hashtag 值固定决定,新增节点无法分散倾斜数据。区别于普通热点 Key 问题——扩容无法缓解。
设计阶段评估 Hashtag 基数,确保与节点数匹配。

2. 使用原则

原则
说明
规范建议
仅在必要时使用
仅在 Lua 脚本操作多 Key 或使用 MGETSINTER 等多键命令时才引入 Hashtag。
不涉及跨 Key 操作的场景,保持自然哈希分布,禁止引入 Hashtag。
使用细粒度 Hashtag
按具体实体拆分(如 {order:202401150001}),使不同实体的 Key 分散到不同节点。
禁止使用宽泛 Hashtag(如 {global}{order})。
保证均匀分布
确保 Hashtag 值在整体上均匀分布。
若原始 ID 分布不均匀,可在 ID 后添加后缀(如 {user_id:1})进行人工分片。

3. 代码实现规范

反面示例(宽泛 Hashtag):全部订单共用 {order},百万订单 Key 集中在同一哈希槽,节点内存写满且扩容无法缓解。
# 潜在风险:所有订单 Key 共用 {order},全部落在同一哈希槽
{order}:202401150001:status
{order}:202401150001:amount
{order}:202401150002:status
{order}:202401150002:amount
# 百万订单集中在一个节点,扩容也无法分散
正确示例(细粒度 Hashtag):按订单号使用独立 Hashtag,仅同一订单的属性 Key 落在同一节点,不同订单自然分散。
# 订单 1 的属性 Key 共享 {order:202401150001},落在同一节点
{order:202401150001}:status
{order:202401150001}:amount
# 订单 2 的属性 Key 共享 {order:202401150002},自然分散到其他节点
{order:202401150002}:status
{order:202401150002}:amount
# 每个订单独立 Hashtag,百万订单均匀分布到不同节点