Garnet Raw String 命令全指南:从 GET/SET 到 INCR、LCS 的源码级解析

发布时间:2026/9/15 18:53:09
Garnet Raw String 命令全指南:从 GET/SET 到 INCR、LCS 的源码级解析 Garnet Raw String 命令全指南从 GET/SET 到 INCR、LCS 的源码级解析【免费下载链接】garnetGarnet is a remote cache-store from Microsoft Research that offers strong performance (throughput and latency), scalability, storage, recovery, cluster sharding, key migration, and replication features. Garnet can work with existing Redis clients.项目地址: https://gitcode.com/GitHub_Trending/garnet4/garnet导读本文以 Garnet 官方命令文档 website/docs/commands/raw-string.md 为骨架系统梳理 Garnet微软研究院出品的远程缓存存储所支持的 22 个 Raw String字符串命令包括读写类GET/SET/SETEX/SETNX/PSETEX/MSET/MSETNX/MGET/GETSET/GETDEL/GETEX、区间与子串类GETRANGE/SUBSTR/SETRANGE/STRLEN/APPEND、自增自减类INCR/DECR/INCRBY/DECRBY/INCRBYFLOAT以及最长公共子序列 LCS。读者读完将掌握每个命令的语法、RESP 返回类型、边界行为与错误语义并能结合 BasicCommands.cs 等源码理解 Garnet 内部的参数解析、过期时间计算与原子性保证机制从而在生产环境中正确选用这些命令。一、为什么需要单独理解 Raw String 命令字符串是缓存与存储系统中最基础的数据类型几乎所有业务都从GET/SET开始。Garnet 与 Redis 命令协议RESP兼容因此这些命令的语法与语义对存量 Redis 客户端完全透明。但在 Garnet 中字符串命令的实现路径并非直接读写内存对象而是经过会话层解析RespServerSession/BasicCommands后路由到存储层的 Tsavorite 主存储最终由 libs/server/Storage/Functions/MainStore 中的函数完成实际读写。理解 Raw String 命令除了掌握用法本身还有两个实际收益正确选择命令变体例如SET key value GET可以原子地“取旧值写新值”替代已废弃的GETSETSETNX应迁移到SET ... NXSUBSTR应迁移到GETRANGE。理解过期时间精度SETEX秒与PSETEX毫秒在 Garnet 内部都换算为DateTimeOffset.UtcNow.Ticks写入值元数据见下文源码分析精度差异会直接影响过期判定的粒度。二、字符串读写基础命令GET / SET语法GET key SET key value [NX | XX] [GET] [EX seconds | PX milliseconds] [KEEPTTL]GET返回 key 对应的字符串值key 不存在时返回 nil。SET无条件覆盖旧值无论旧值类型并且在成功写入后会丢弃 key 原有的过期时间。选项说明SET选项含义约束EX seconds以秒为单位设置过期时间必须为正整数PX milliseconds以毫秒为单位设置过期时间必须为正整数NX仅当 key 不存在时才设置与XX互斥XX仅当 key 已存在时才设置与NX互斥KEEPTTL保留 key 原有的过期时间与EX/PX互斥GET返回 key 的旧值可与其他选项组合RESP 返回场景返回未给GET操作因NX/XX冲突被中止Nil未给GETkey 成功写入OKSimple string给定GET写入前 key 不存在Nil给定GET写入前 key 存在Bulk string旧值源码级解析SET 的完整选项解析实现在 BasicCommands.cs 的NetworkSETEXNX中。值得注意的几个实现细节过期时间换算无论EX秒还是PX毫秒最终都转为绝对时间戳DateTimeOffset.UtcNow.Ticks TimeSpan...Ticks作为值的元数据见 NetworkSET_EX。选项校验EX/PX/KEEPTTL三者只能出现一个NX/XX只能出现一个EX/PX后必须跟一个正整数值否则返回语法错误或value is not an integer or out of range。大小写不敏感命令选项会被AsciiUtils.ToUpperInPlace就地转大写后匹配。类型冲突处理若 key 已存在但类型非字符串如 Hash/ListSET不会报错而是先删除旧类型值再写入字符串WRONGTYPE 分支会通过事务提升PromoteToTransaction删除旧值后重试。条件写入SET ... NX/XX走 NetworkSET_Conditional内部调用storageApi.SET_Conditional利用GarnetStatus.NOTFOUND区分“key 不存在/存在”来决定返回OK还是 nilSETEXNX即SET NX的语义是“key 不存在才写”所以 happy path 恰恰是NOTFOUND源码中对此做了标志翻转ok !ok。SETEX / PSETEX语法SETEX key seconds value PSETEX key milliseconds valueSETEX等价于“SET 以秒计过期”PSETEX除过期时间以毫秒计外行为完全一致用于更高精度的过期控制。RESP 返回OK。源码级解析二者共用 NetworkSETEXhighPrecision区分秒/毫秒校验过期值必须为正整数expiry 0返回invalid expire time in set command随后同样换算为 Ticks 元数据并调用storageApi.SET。若命中 WRONGTYPE会在事务内先DELETE再SET保证最终一定写入字符串类型。SETNX / GETSET已废弃推荐迁移语法SETNX key value GETSET key valueSETNX仅当 key 不存在时写入成功返回 1否则返回 0 且不做任何操作。GETSET原子地将 key 设为新值并返回旧值。原文档明确标注两者为废弃命令迁移建议SETNX→SET key value NXGETSET→SET key value GET源码级解析SETNX在 NetworkSETNX 中通过SET_Conditional实现注释明确指出“SETNX 返回的NOTFOUND正是 happy path 的期望状态”因此retVal status GarnetStatus.NOTFOUND ? 1 : 0。GETSET则不再有独立实现路径直接由SET ... GET覆盖。MSET / MSETNX / MGET语法MSET key value [key value ...] MSETNX key value [key value ...] MGET key [key ...]MSET批量写入多对 key/value逐对覆盖旧值与单个SET语义一致。MSETNX仅当所有key 都不存在时才全部写入只要有一个 key 已存在则一个都不写原子“全有或全无”。返回 1 表示全部写入0 表示至少一个 key 已存在、操作整体中止。MGET批量读取多个 key 的值不存在的 key 返回 nil。RESP 返回命令返回MSETOKMSETNXInteger1全部写入/ 0存在冲突全部不写MGETArray按参数顺序排列的值列表缺失 key 为 nil实战要点MSETNX的“全有或全无”语义适合多键一致性初始化场景如一次性建立一组默认配置MGET是减少网络往返的关键命令Garnet 端对MGET有专门优化的批读路径见 libs/server/Resp/MGetReadArgBatch.cs。三、子串与区间操作GETRANGE / SUBSTR / SETRANGE / STRLEN / APPENDGETRANGE / SUBSTR语法GETRANGE key start end SUBSTR key start end两者均返回字符串值在[start, end]闭区间均含范围内的子串。SUBSTR是废弃命令官方建议迁移到GETRANGE。RESP 返回Bulk string截取出的子串空串也可能返回。源码级解析GETRANGE与SUBSTR共用 NetworkGetRange并通过Debug.Assert(cmd is RespCommand.GETRANGE or RespCommand.SUBSTR)强制两者共享同一实现。命令要求恰好 3 个参数start/end必须可解析为整数否则返回value is not an integer or out of range。命中 WRONGTYPE 时返回类型错误key 不存在或命中空值时写回 RESP 空串RESP_EMPTY。注意文档与实现均支持负偏移负偏移表示从字符串末尾倒数这是GETRANGE比普通切片更灵活的地方。SETRANGE语法SETRANGE key offset value从offset起用value覆盖字符串的对应部分返回修改后的字符串长度。若offset大于当前长度中间缺口以零字节\x00填充。RESP 返回Integer修改后的字符串长度。源码级解析NetworkSetRange 包含两层防护offset 0时返回offset is out of range当offset value.Length超过BitmapManager.MaxBitmapPayloadBytes时直接返回string exceeds maximum allowed size (proto-max-bulk-len)避免底层存储抛异常导致连接被断开——这是 Garnet 对超限输入做的显式兜底校验。STRLEN语法STRLEN key返回 key 对应字符串值的字节长度key 不存在时返回 0。RESP 返回Integer字符串长度key 不存在时为 0。APPEND语法APPEND key value若 key 已存在且为字符串则将value追加到原值末尾若 key 不存在则先创建为空串再写入value。返回追加后字符串的总长度。RESP 返回Integer追加操作后字符串的长度。源码级解析实现在 NetworkAppend。APPEND是典型的 Read-Modify-Write 操作Garnet 通过 Tsavorite 的 RMWread-modify-write函数在存储层原子完成“读旧值→拼新值→写回”无需客户端做 CAS 循环。测试覆盖见 RespTests.cs 中的AppendTest、AppendLargeStringValueTest验证大值追加与AppendWithExpirationTest验证追加后过期时间语义。四、自增自减INCR / DECR / INCRBY / DECRBY / INCRBYFLOAT语法INCR key DECR key INCRBY key increment DECRBY key decrement INCRBYFLOAT key incrementINCR/DECR对 key 存储的整数 ±1key 不存在时先视为 0 再操作。INCRBY/DECRBY按指定量 ±正负皆可decrement传负数等效于自增。INCRBYFLOAT对存储的浮点数字符串做增量传负增量即实现递减key 不存在时先视为 0。RESP 返回命令返回INCR/DECR/INCRBY/DECRBYInteger操作后的值INCRBYFLOATBulk string操作后的浮点数值错误语义若 key 存在但值类型错误或值无法解析为整数/浮点数返回错误例如INCR一个内容为abc的字符串会报value is not an integer or out of range。源码级解析整数四兄弟共用 NetworkIncrementDebug.Assert(cmd is INCRBY or DECRBY or INCR or DECR)通过parseState.TryGetLong解析增量用stackalloc byte[NumUtils.MaximumFormatInt64Length 1]栈上缓冲格式化结果后直接写出 Integer 回复避免堆分配。INCRBYFLOAT单独实现在 NetworkIncrementByFloat。两者的 WRONGTYPE 分支都会返回WRONGTYPE Operation against a key holding the wrong kind of value。实战场景计数器、限流令牌、点赞数、库存扣减等场景。INCRBYFLOAT则适合金额、评分等需要小数的累加注意其结果以字符串形式返回再次运算时无需类型转换。五、读后即删与读后设置过期GETDEL / GETEXGETDEL语法GETDEL key返回 key 的值并删除该 key。仅当 key 存在且值类型为字符串时才删除key 不存在或类型不符时返回 nil 且不删除。RESP 返回Bulk stringkey 的值Nilkey 不存在或值类型非字符串。源码级解析GETDEL是“读取 删除”的原子组合测试见 RespTests.cs 的GetDelTest。典型用途是一次性消费语义如一次性令牌、验证码、限时任务避免“先 GET 再 DEL”两次往返之间的竞态。GETEX语法GETEX key [EX seconds | PX milliseconds | EXAT unix-time-seconds | PXAT unix-time-milliseconds | PERSIST]读取 key 的值并可选地设置/清除其过期时间。GETEX与GET相似但它是写命令支持以下选项选项含义EX seconds以秒设置相对过期时间PX milliseconds以毫秒设置相对过期时间EXAT unix-time-seconds以秒设置绝对 Unix 时间戳过期点PXAT unix-time-milliseconds以毫秒设置绝对 Unix 时间戳过期点PERSIST移除 key 的过期时间TTLRESP 返回Bulk stringkey 的值Nilkey 不存在或值类型非字符串。实战场景缓存“读取并续期”——每次访问时读取值并刷新过期窗口配合PERSIST可将临时 key 永久化。六、LCS最长公共子序列语法LCS key1 key2 [LEN] [IDX] [MINMATCHLEN len] [WITHMATCHLEN]返回key1与key2两个字符串值的最长公共子序列Longest Common Subsequence注意不要求连续与最长公共子串不同。选项说明选项含义LEN只返回最长公共子序列的长度IDX返回最长公共子序列的匹配位置match rangesMINMATCHLEN len只返回长度 ≥len的匹配片段WITHMATCHLEN在IDX模式下附带返回各匹配片段的长度RESP 返回默认Bulk string——最长公共子序列本身指定LENInteger——最长公共子序列的长度指定IDXArray——匹配位置集合可含matchlen子数组。实战场景文本 diff、基因序列比对、代码相似度分析、去重等算法型应用。LEN模式开销最小适合先做粗筛IDX/WITHMATCHLEN提供逐段定位能力。七、从源码看 Garnet 字符串命令的通用机制结合上文各实现可以总结出 Garnet Raw String 命令的几个共性工程点参数数量校验先行每个命令入口都先做parseState.Count检查不满足则调用AbortWithWrongNumberOfArguments返回wrong number of arguments for cmd command。错误响应集中在CmdStrings如RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER、RESP_ERR_GENERIC_INVALIDEXP_IN_SET、RESP_ERR_WRONG_TYPE等统一在 libs/server/Resp/CmdStrings.cs 中定义保证协议错误文案与 Redis 兼容。存储层 RMW 原子性APPEND、INCR系列等读改写命令通过 Tsavorite 的 RMW 函数在存储层原子完成源码见 libs/server/Storage/Functions/MainStore/RMWMethods.cs这也是 Garnet 高吞吐的根基之一。WRONGTYPE 的兜底与事务提升当 key 被其他类型占用时写命令要么报WRONGTYPE如INCR、GETRANGE要么通过PromoteToTransaction先删后写如SETEX、SET保证最终类型一致性。八、命令速查表与迁移清单命令语法返回类型备注GETGET keyBulk/Nil不存在返回 nilSETSET key value [NX\|XX] [GET] [EX\|PX] [KEEPTTL]OK/Nil/Bulk覆盖写丢弃旧 TTLSETEXSETEX key seconds valueOK秒级过期PSETEXPSETEX key ms valueOK毫秒级过期SETNXSETNX key value0/1废弃用SET NXGETSETGETSET key valueBulk/Nil废弃用SET GETGETDELGETDEL keyBulk/Nil原子取删GETEXGETEX key [EX\|PX\|EXAT\|PXAT\|PERSIST]Bulk/Nil原子取改过期GETRANGEGETRANGE key start endBulk闭区间SUBSTRSUBSTR key start endBulk废弃用 GETRANGESETRANGESETRANGE key offset valueInteger超限返回错误STRLENSTRLEN keyInteger不存在为 0APPENDAPPEND key valueIntegerRMW 原子追加INCRINCR keyInteger不存在视为 0DECRDECR keyInteger不存在视为 0INCRBYINCRBY key incrementInteger可传负值DECRBYDECRBY key decrementInteger可传负值INCRBYFLOATINCRBYFLOAT key incrementBulk浮点增量LCSLCS key1 key2 [LEN\|IDX\|MINMATCHLEN\|WITHMATCHLEN]Bulk/Int/Array最长公共子序列MGETMGET key [key ...]Array缺失为 nilMSETMSET key value [key value ...]OK批量覆盖写MSETNXMSETNX key value [key value ...]0/1全有或全无迁移清单原文档明确建议GETSET→SET key value GETSUBSTR→GETRANGE key start endSETNX→SET key value NX九、补充相关资源与延伸阅读官方命令文档原文website/docs/commands/raw-string.md命令总览与数据结构概览website/docs/commands/overview.md、website/docs/commands/data-structures.mdGarnet 与 Redis 命令兼容性说明website/docs/commands/api-compatibility.md会话层命令分发RespCommand.APPEND NetworkAppend等libs/server/Resp/RespServerSession.cs字符串命令参数解析与校验实现libs/server/Resp/BasicCommands.cs自动化测试覆盖Append/GetDel/GetRange/SetRange/GetSet 等test/standalone/Garnet.test/RespTests.cs需要提醒的是以上行为均以当前仓库代码与官方文档为准SETEX的秒/毫秒换算、SETRANGE的超限防护等细节可能随版本演进调整生产使用前请以所部署版本的源码为准。【免费下载链接】garnetGarnet is a remote cache-store from Microsoft Research that offers strong performance (throughput and latency), scalability, storage, recovery, cluster sharding, key migration, and replication features. Garnet can work with existing Redis clients.项目地址: https://gitcode.com/GitHub_Trending/garnet4/garnet创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询