ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Garnet 专属命令完全指南:ETag 条件更新、成员级过期与运维扩展命令详解

Garnet 专属命令完全指南:ETag 条件更新、成员级过期与运维扩展命令详解 Garnet 专属命令完全指南ETag 条件更新、成员级过期与运维扩展命令详解【免费下载链接】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 中独有的、标准 RESP 服务器不具备的专属命令Garnet-specific commands涵盖 AOF 手动提交COMMITAOF、按需过期清理HCOLLECT/ZCOLLECT/EXPDELSCAN、自定义对象扫描COSCAN、自定义命令与事务注册REGISTERCS/RUNTXP/MODULE LOADCS、ETag 条件读写命令族SETWITHETAG/SETIFMATCH等以及 Sorted Set 成员级过期命令族ZEXPIRE/ZTTL/ZPERSIST等。读完本文你将掌握这些命令的完整语法、返回语义、源码级实现原理与正确使用边界可直接在现有 Redis 客户端接入的 Garnet 实例中实战使用。说明本文以 garnet-specific.md 为骨架结合仓库源码与测试如 BasicEtagCommands.cs、AdminCommands.cs、SortedSetCommands.cs进行原理级扩充。除 服务器扩展 机制外Garnet 还支持大量其他 RESP 服务器没有的 API 调用下面逐一介绍。一、运维与持久化类命令COMMITAOF手动提交追加日志语法COMMITAOF [DBID]COMMITAOF对 Garnet 实例中所有活跃数据库的追加式文件append-only-file, AOF发起一次手动提交。当自动提交被关闭时若你需要在特定时间点强制系统落盘此命令非常有用。如果指定了DBID则只对该指定数据库的 AOF 发起手动提交。Resp 回复Simple string replyOK实现层面实际写回的是AOF file committed简单字符串。实现细节从源码看NetworkCOMMITAOF 的逻辑非常直接参数最多接受 1 个默认dbId -1表示提交所有活跃数据库若指定了 DBID 则通过TryParseDatabaseId解析。由于该操作在网络线程上执行源码中通过AsyncUtils.BlockingWait(CommitAofAsync(dbId))阻塞等待异步提交完成后再返回。因此COMMITAOF返回即代表对应 AOF 提交已真正完成适合在测试、备份或关闭前的确定性落盘场景使用。EXPDELSCAN按需扫描并删除过期键语法EXPDELSCAN [dbid]EXPDELSCAN扫描存储的 mutable region并按需删除所有已过期键。它的典型价值在于你可以自己掌控过期删除的时机例如接入一个与你的工作负载模式匹配的调度器而不必依赖后台扫描线程。dbid选择要扫描的逻辑数据库默认0。重要限制当后台过期键删除扫描被启用时本命令会被拒绝——即当ExpiredKeyDeletionScanFrequencySecs命令行参数--expired-key-deletion-scan-freq大于0时不可用。也就是说EXPDELSCAN与后台过期扫描是互斥的两种模式。Resp 回复Array reply两个整数——第一个是已删除的过期记录数第二个是被扫描的记录数。Error replyERR Cannot execute EXPDELSCAN with background expired key deletion scan enabled。实现细节源码 NetworkEXPDELSCAN 首先检查运行时配置ServerConfigType.EXPIRED_KEY_DELETION_SCAN_FREQ是否大于 0大于 0 则直接以RESP_ERR_EXPDELSCAN_INVALID报错否则调用storeWrapper.ExpiredKeyDeletionScan(dbId)执行扫描并将(recordsExpired, recordsScanned)以长度 2 的数组回复。该命令与配置项ExpiredKeyDeletionScanFrequencySecs--expired-key-deletion-scan-freq的联动行为在 ExpiredKeyDeletionTests.cs 中有完整测试覆盖。SECONDARYOF配置主从关系SECONDARYOF将一个服务器配置为另一台服务器的 secondary从或将其提升为主节点primary。其语义与标准命令REPLICAOF完全一致详见 server.md。在主从复制或集群运维脚本中两者可互换使用。二、集合过期成员清理命令Garnet 的 Hash 与 Sorted Set 对象支持字段/成员级过期因此提供了按需清理过期字段/成员的专属命令。HCOLLECT手动清理 Hash 中过期字段语法HCOLLECT key [key ...]手动触发对指定 Hash 键中过期字段field的内存清理。使用*作为 key 可以对所有 Hash 键执行收集清理。Resp 回复Simple replyOKError replyERR HCOLLECT scan already in progress实现细节从 NetworkHCOLLECT 可以看出该命令构建RespInputHeader(GarnetObjectType.Hash) { HashOp HashOperation.HCOLLECT }输入并调用storageApi.HashCollect(keys, ref input)。根据返回状态分别回复OK、WRONGTYPE或“扫描已在进行中”错误。它本质上是利用 Hash 对象的 RMW 逻辑对过期 field 做批量收集与HSCAN等扫描命令配合可用于维护大 Hash 键的内存占用。ZCOLLECT手动清理 Sorted Set 中过期成员语法ZCOLLECT key [key ...]手动触发对指定 Sorted Set 键中过期成员member的内存清理。使用*作为 key 可以对所有 Sorted Set 键执行收集清理。Resp 回复Simple replyOKError replyERR ZCOLLECT scan already in progress实现细节与HCOLLECT对称NetworkZCOLLECT 使用SortedSetOperation.ZCOLLECT操作码并调用storageApi.SortedSetCollect(keys, ref input)。对应的成员过期元数据管理逻辑位于 SortedSetObject.cs在 SortedSetOps.cs 中完成过期成员的批量移除。注意HCOLLECT/ZCOLLECT的文档原文对两种集合的说明存在笔误互相复制了描述实际行为与命令名一一对应H*处理 HashZ*处理 Sorted Set。三、COSCAN自定义对象扫描语法COSCAN key cursor [MATCH pattern] [COUNT count] [NOVALUES]COSCANCustom Object Scan与 HSCAN、SSCAN 类似用于迭代遍历存储在指定 key 下的自定义对象custom object的字段与值。MATCH pattern对从集合中取回的元素应用模式过滤。COUNT count限制服务器单次返回给客户端的最大元素数量该限制还会与全局服务器设置中的object-scan-count-limit一起共同生效即取两者中的约束。NOVALUES只返回字段/键而不返回对应的值。该命令与 Garnet 的自定义对象扩展体系紧密相关自定义对象通过 CustomObjectBase.cs 及CustomObjectCommand注册后即可被COSCAN迭代。其解析逻辑可在 RespCommandHashLookupData.cs 与 RespCommand.cs 的命令哈希查找表中查到COSCAN的注册信息。四、自定义命令与事务扩展命令Garnet 允许以 C# 实现自定义命令custom commands与自定义事务custom transactions并以服务器端 DLL 形式动态加载这一族命令与扩展机制配套使用详见 自定义命令开发指南。REGISTERCS注册 C# 实现的命令与事务REGISTERCS用于把实现在 C# 中的特定自定义命令和事务注册进服务器端的 DLL 库中。开发者在扩展程序集中用CustomRawStringCommand、CustomObjectCommand或CustomTransactionProcedure等基类实现逻辑后通过REGISTERCS加载注册之后即可像内置命令一样被 RESP 客户端调用。具体流程与示例见 custom-commands.md。RUNTXP按 ID 运行自定义事务语法RUNTXP txid [args]运行由txid标识的特定自定义事务过程transactional procedure。txid即注册时分配的事务 ID后续参数args会透传给事务过程。在 RespServerSession.cs 中可以看到RespCommand.RUNTXP NetworkRUNTXP()的调度入口事务过程最终由事务管理器 TransactionManager.cs 执行。RUNTXP是构建多键原子操作如样例扩展 ReadWriteTxn.cs、SampleUpdateTxn.cs的运行时调用入口。MODULE LOADCS加载自包含模块MODULE LOADCS是 RESP 协议中MODULE LOAD的 Garnet 等价物。它加载一个自包含模块self-contained module模块的初始化代码会自动注册其中所有相关的命令与事务无需再逐个REGISTERCS。从 AdminCommands.cs 的实现可以看到加载流程为ModuleUtils.LoadAssemblies加载程序集 →ModuleRegistrar.Instance.LoadModule触发模块初始化并自动注册命令成功后返回OK。模块化开发细节同样见 custom-commands.md 与 ModuleRegistrar.cs。五、事务辅助命令WATCHMS 与 WATCHOSGarnet 为WATCH提供了两种类型化变体用于在事务MULTI/EXEC中显式声明被监视键的存储类型让存储层做出更精确的优化WATCHMS语法WATCHMS key [key ...]与 WATCH 语义相同但声明这些 key 持有的是原始字符串值raw string。WATCHOS语法WATCHOS key [key ...]与 WATCH 语义相同但声明这些 key 持有的是对象值object如 Hash、Sorted Set 等。两者的实现通过监视键版本机制见 WatchVersionMap.cs 与 WatchedKeySlice.cs在事务执行前校验版本一致性避免脏写。六、ASYNC大数据访问的异步接口ASYNC是 Garnet 面向大于内存数据larger-than-memory data访问场景提供的异步接口机制。当数据集超过内存容量、需要从磁盘存储层Tsavorite按需读取时传统同步阻塞模型会浪费网络线程Garnet 通过异步处理管线见 AsyncProcessor.cs实现非阻塞的读写提升大内存数据集场景下的吞吐与延迟表现。它更多是一种客户端/服务器协同的接口约定适合大 Value 与冷热数据分层场景。七、Native ETag 支持字符串键值对的条件更新协议Garnet 为原始字符串提供了原生的 ETag 支持任何以字符串为基础结构的 key-value 对插入后都可以关联一个自动更新的 ETag初始为 1此后每次覆盖写入递增。ETag 的核心价值是实现无锁的乐观并发控制optimistic concurrency control——客户端先读取 value 与 ETag再携带该 ETag 做条件更新只有 ETag 匹配时才写成功从而避免“读取-修改-写入”期间的竞态。初始化方式使用SETWITHETAG初始化带 ETag 的键值对也可以对任意已存在的键值对调用SETIFMATCH并传入 ETag 参数0任何未显式关联 ETag 的键值对其隐式 ETag 都是 0。关于 ETag 的使用场景与设计模式缓存失效、乐观锁、Web 语义映射等可参阅博客 etags-when-and-how。7.1 SETWITHETAG带 ETag 写入语法SETWITHETAG key value [EX seconds | PX milliseconds]将key设为字符串value并关联一个 ETag。若 key 已存在则覆盖原值若原值已有 ETag则ETag 自增 1否则赋予新 ETag1。选项EX seconds以秒为单位设置过期时间正整数。PX milliseconds以毫秒为单位设置过期时间正整数。Resp 回复Integer reply与该 value 关联的 ETag。实现细节NetworkSETWITHETAG 对参数个数有严格校验24 个EX/PX过期值必须为正整数否则分别返回语法错误、非整数错误或RESP_ERR_GENERIC_INVALIDEXP_IN_SET。随后由共享实现 ExecuteETagSetCommand 完成写入过期时间为 0 表示不过期否则按DateTimeOffset.UtcNow.Ticks加秒/毫秒换算成绝对过期时刻底层通过storageApi.SET_ETagConditional落库。若目标 key 已被对象类型占用WRONGTYPE实现会先用事务提升到排他锁、删除旧对象再执行条件写入保证类型正确性。7.2 GETWITHETAG带 ETag 读取语法GETWITHETAG key返回指定 key 的 value 及其关联的 ETag。回复Array reply成功时返回两个元素——第一个是整数 ETag第二个是 key 的 bulk string value。若该键值对未关联过 ETag则 ETag 为0。Nil replykey 不存在。7.3 SETIFMATCHETag 匹配才更新语法SETIFMATCH key value etag [EX seconds | PX milliseconds] [NOGET]仅当满足以下任一条件时才以给定的etag写入/更新键值对(1) 请求中的 etag 与已存在的 etag 匹配(2) 原本不存在该值(3) 已存在的值未关联任何 etag 且请求 etag 为0。这正是“比较并交换”compare-and-swap语义是乐观锁的核心原语。选项EX seconds以秒为单位设置过期时间正整数。PX milliseconds以毫秒为单位设置过期时间正整数。NOGET即使 etag 不匹配也不返回当前值节省带宽。回复Array reply若请求 etag 与现有 etag 匹配返回数组第一个元素是更新后的 etag第二个元素为 nil若不匹配数组依次为最新 etag 与最新 value。7.4 SETIFGREATERETag 更大才更新语法SETIFGREATER key value etag [EX seconds | PX milliseconds] [NOGET]仅当以下任一条件成立时才写入(1) 请求 etag大于已存在的 etag(2) 原本不存在该值(3) 已存在的值未关联 etag 且请求 etag 大于0。这提供了单调递增的“版本推进”语义适合时钟或序号驱动的同步场景。选项EX seconds/PX milliseconds同上。NOGET即使请求 etag 不大于现有 etag也不返回当前值。回复Array reply若请求 etag 大于现有 etag返回数组第一个元素是更新后的 etag第二个为 nil若小于等于现有 etag则数组为最新 etag 与最新 value。条件更新族SETIFMATCH/SETIFGREATER在 NetworkSetETagConditional 中统一实现允许 36 个参数依次解析NOGET、EX/PX组合且 etag 必须为不小于 0 的长整数否则返回RESP_ERR_INVALID_ETAG。两个命令共用ExecuteETagSetCommand与SET_ETagConditional存储路径仅条件判定方向不同。7.5 GETIFNOTMATCHETag 变化才返回语法GETIFNOTMATCH key etag若 key 关联的 ETag 已变化则返回 value否则返回“无变化”指示。这是高效的“拉取变更”原语客户端携带已知 ETag服务端只在版本推进时回传数据避免重复传输未变更内容。回复Array reply若 ETag 不匹配返回两个元素——第一个是最新 ETag第二个是该 key 的 value若 ETag 匹配未变化第一个元素为当前 etag第二个为 nil。Nil replykey 不存在。7.6 DELIFGREATERETag 更大才删除语法DELIFGREATER key etag仅当提供的 ETag严格大于该 key 现有 ETag 时才删除该 key。回复Integer reply删除成功返回1否则返回0。实现细节NetworkDELIFGREATER 中条件删除并非存储层原生能力而是借助StringInput构造条件 DEL 请求调用storageApi.DEL_ETagConditional走 RMWRead-Modify-Write路径在读取阶段完成 etag 比较后再决定是否删除返回删除计数 1 或 0。etag 为负数时返回RESP_ERR_INVALID_ETAG。7.7 与普通命令的兼容性约束重要当前限制Cluster集群模式下暂不支持 ETag 命令官方计划后续支持。:::warning 关键必须做键分区 所有非 ETag 命令SET、GET、APPEND、INCR、MSET、BITOP、RENAME等对 ETag 是完全无感知的它们不读取、不校验、不更新、也不保留 ETag。用户必须对键做分区管理ETag 管理的键上只能使用ETag 命令SETWITHETAG、GETWITHETAG、SETIFMATCH、SETIFGREATER、GETIFNOTMATCH、DELIFGREATER。对同一个键混用 ETag 与非 ETag 命令例如对SETWITHETAG创建的键再执行SET会导致未定义的 ETag 行为——ETag 可能丢失、过期或损坏。这是出于极致性能的设计取舍非 ETag 命令为 ETag 功能付出零开销。 :::正确用法# ETag 键 —— 只用 ETag 命令 SETWITHETAG etag:user:1 data # 初始化并写入 ETag GETWITHETAG etag:user:1 # 带 ETag 读取 SETIFMATCH etag:user:1 new 1 # 基于 ETag 的条件更新 # 非 ETag 键 —— 用普通命令 SET user:2 data GET user:2 APPEND user:2 more错误用法未定义行为SETWITHETAG mykey data # 写入 ETag SET mykey other # ETag 行为未定义 GETWITHETAG mykey # 可能返回过期/缺失的 ETag建议以明确的键前缀如etag:隔离两类键空间。ETag 命令族的完整行为在 RespEtagTests.cs 中有系统化测试涉及读写、条件匹配/不匹配、过期、类型错误等场景。八、Sorted Set 成员级过期命令族Garnet 为 Sorted Set成员提供独立的过期控制区别于键级过期可以精确到单个 member。所有命令都以MEMBERS关键字声明后续成员数量与成员列表一次可批量操作多个成员。8.1 ZEXPIRE / ZPEXPIRE / ZEXPIREAT / ZPEXPIREAT设置成员过期语法ZEXPIRE key seconds [NX | XX | GT | LT] MEMBERS nummembers member [member ...] ZEXPIREAT key unix-time-seconds [NX | XX | GT | LT] MEMBERS nummembers member [member ...] ZPEXPIRE key milliseconds [NX | XX | GT | LT] MEMBERS nummembers member [member ...] ZPEXPIREAT key unix-time-milliseconds [NX | XX | GT | LT] MEMBERS nummembers member [member ...]为 Sorted Set key 的一个或多个成员设置超时ZEXPIRE/ZPEXPIRE为相对时间秒/毫秒ZEXPIREAT/ZPEXPIREAT为绝对时间Unix 时间戳秒/毫秒。超时到期后成员会被自动删除。条件选项四者互斥NX仅对没有过期时间的成员设置过期。XX仅对已有过期时间的成员设置过期。GT仅当新过期时间大于当前过期时间时设置。LT仅当新过期时间小于当前过期时间时设置。Resp 回复Array reply对每个成员分别返回——1成功设置超时0成员不存在-1因条件不满足而未设置超时。实现细节SortedSetExpire 是这四个命令的统一实现严格校验参数结构MEMBERS关键字必须出现、nummembers必须与后续成员数量一致将相对时间换算为绝对过期时刻ZEXPIRE用UtcNow.AddSeconds、ZPEXPIRE用AddMilliseconds、ZEXPIREAT/ZPEXPIREAT用 Unix 时间戳转 ticks连同条件选项一起编码进ExpirationWithOption最终通过SortedSetOp.ZEXPIRE操作码与storageApi.SortedSetExpire写入对象存储。成员不存在NOTFOUND时按成员数量返回对应个数的-2。8.2 ZTTL / ZPTTL查询成员剩余存活时间语法ZTTL key MEMBERS nummembers member [member ...] ZPTTL key MEMBERS nummembers member [member ...]返回指定 Sorted Set 成员的剩余存活时间ZTTL以秒为单位ZPTTL以毫秒为单位。Resp 回复Array reply对每个成员返回——剩余 TTL秒或毫秒成员存在且有过期时间-1成员存在但未设置过期时间-2成员不存在。8.3 ZEXPIRETIME / ZPEXPIRETIME查询成员过期时刻语法ZEXPIRETIME key MEMBERS nummembers member [member ...] ZPEXPIRETIME key MEMBERS nummembers member [member ...]返回指定 Sorted Set 成员的绝对过期时间Unix 时间戳ZEXPIRETIME以秒为单位ZPEXPIRETIME以毫秒为单位。Resp 回复Array reply对每个成员返回——过期时刻的 Unix 时间戳秒或毫秒-1成员存在但未设置过期时间-2成员不存在。8.4 ZPERSIST移除成员过期时间语法ZPERSIST key MEMBERS nummembers member [member ...]移除指定 Sorted Set 成员的过期时间使其持久化永不过期。Resp 回复Array reply对每个成员返回——1成功移除超时0成员存在但本就没有超时-1成员不存在。ZTTL/ZPTTL/ZEXPIRETIME/ZPEXPIRETIME由 SortedSetTimeToLive 统一实现通过参数arg1是否毫秒与arg2是否返回时间戳区分四种语义底层走SortedSetOp.ZTTL操作码ZPERSIST则由 SortedSetPersist 实现使用独立的SortedSetOp.ZPERSIST。这组命令与 Hash 对象上的HEXPIRE/HTTL/HPERSIST等命令族相对应是构建带成员级 TTL 的排行榜、缓存、任务队列的利器。九、源码与测试索引如果你想深入验证或扩展这些命令可在仓库中关注以下路径主题源码/测试位置ETag 命令族实现BasicEtagCommands.cs、ReadMethods.Etags.cs、RMWMethods.Etags.csETag 行为测试RespEtagTests.cs运维/扫描命令实现AdminCommands.csCOMMITAOF、HCOLLECT、ZCOLLECT、EXPDELSCAN、MODULE LOADCS过期键删除测试ExpiredKeyDeletionTests.csSorted Set 成员过期实现SortedSetCommands.cs、SortedSetOps.cs自定义命令/事务与模块custom-commands.md、ModuleRegistrar.cs命令注册表RespCommand.cs、RespCommandHashLookupData.cs十、总结Garnet 的专属命令从四个维度扩展了标准 RESP 的能力确定性运维COMMITAOF、EXPDELSCAN、SECONDARYOF、按需内存治理HCOLLECT、ZCOLLECT、COSCAN、扩展体系REGISTERCS、RUNTXP、MODULE LOADCS、WATCHMS/WATCHOS以及协议级新语义ETag 条件读写族与 Sorted Set 成员级过期族。其中 ETag 命令族提供了零额外开销对非 ETag 命令的原生乐观并发控制而成员级过期命令族把 TTL 的粒度从键推进到了集合成员。使用这些命令时务必遵守键分区原则ETag 键与非 ETag 键隔离以及EXPDELSCAN与后台过期扫描互斥的约束即可在兼容现有 Redis 客户端的前提下获得远超标准 RESP 服务器的精细化控制能力。【免费下载链接】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),仅供参考
返回列表