拓冰建站拓冰建站
首页 / 资讯中心 / 正文

DiceDB 命令深度解析:GET 键值读取的原理、类型转换与 Watch 订阅实战

DiceDB 命令深度解析GET 键值读取的原理、类型转换与 Watch 订阅实战【免费下载链接】dicedbOpen-source, low-latency key/value engine built on Valkey with query subscriptions and hierarchical storage tiers.项目地址: https://gitcode.com/GitHub_Trending/dic/dicedb本篇文章围绕 DiceDB 的GET命令展开讲解其语法、返回值约定、典型使用方式并结合仓库源码剖析它如何在分片存储中查找键、如何将内部对象转换为字符串返回以及与GET.WATCH查询订阅能力的联动。读完本文你将掌握GET的完整行为边界含类型转换、过期键处理与错误场景并能在此基础上构建实时键值推送应用。GET 命令速览GET是 DiceDB 中最基础的读取命令给定一个 key返回该 key 对应的值以字符串形式。其完整定义位于 internal/cmd/cmd_get.go命令名GET语法GET key是否可订阅IsWatchabletrue意味着它可以直接支撑GET.WATCH查询订阅返回值成功时返回键对应的字符串值键不存在时返回空字符串对应的命令文档为 docs/src/content/docs/commands/GET.md文档由scripts/generate-docs从源码中的CommandMeta自动生成因此源码中的HelpLong与Examples与文档保持一致任何对文档的修改都可能被重新生成覆盖这一点在文档文件头部的注释中亦有说明。语法与返回值语义语法GET keyGET只接受一个参数key。参数数量校验在 internal/cmd/cmd_get.go 的evalGET中完成若len(c.C.Args) ! 1则返回errors.ErrWrongArgumentCount(GET)即错误信息wrong number of arguments for GET command。返回值约定GET的返回值遵循以下约定键存在返回该键的当前值以字符串形式呈现键不存在返回空字符串不产生错误。这一点与传统 Redis 返回nil的语义不同是 DiceDB 的特定行为使用时需要留意。行为在 internal/cmd/cmd_get.go 的evalGET中有直接体现func evalGET(c *Cmd, s *dstore.Store) (*CmdRes, error) { if len(c.C.Args) ! 1 { return GETResNilRes, errors.ErrWrongArgumentCount(GET) } key : c.C.Args[0] obj : s.Get(key) return newGETRes(obj), nil }当s.Get(key)返回nil键不存在时newGETRes(nil)会走到getWireValueFromObj的obj nil分支返回空字符串与OK状态。从 SET 到 GET 的完整闭环GET通常与SET配合使用。SET命令的语法与选项见 docs/src/content/docs/commands/SET.mdSET key value [EX seconds | PX milliseconds] [EXAT timestamp | PXAT timestamp] [XX | NX] [KEEPTTL]SET支持以下选项EX seconds以秒为单位设置过期时间PX milliseconds以毫秒为单位设置过期时间EXAT timestamp以 Unix 秒级时间戳设置过期时间PXAT timestamp以 Unix 毫秒级时间戳设置过期时间XX仅当 key 已存在时写入NX仅当 key 不存在时写入KEEPTTL保留 key 已有的 TTL文档给出的完整示例同样来自 internal/cmd/cmd_set.go 中CommandMeta.Exampleslocalhost:7379 SET k 43 OK localhost:7379 SET k 43 EX 10 OK localhost:7379 SET k 43 PX 10000 OK localhost:7379 SET k 43 EXAT 1772377267 OK localhost:7379 SET k 43 PXAT 1772377267000 OK localhost:7379 SET k 43 XX OK localhost:7379 SET k 43 NX OK localhost:7379 SET k 43 KEEPTTL OK官方 GET 示例GET官方文档给出了如下可直接在客户端执行的示例localhost:7379 SET k1 v1 OK localhost:7379 GET k1 OK v1 localhost:7379 GET k2 OK 这里的localhost:7379是 DiceDB 默认监听地址与端口——默认端口 7379 定义于 config/config.go 中的Port配置项。示例包含三个关键点SET k1 v1写入成功后返回OKGET k1读取到字符串v1GET k2从未写入的键返回空字符串印证了键不存在返回空串的语义。源码级原理GET 如何取值执行路径与分片定位GET的执行分为两层executeGET面向分片管理器ShardManager的入口通过sm.GetShardForKey(key)依据 key 哈希定位到对应的分片再调用分片线程持有的StoreevalGET面向单个Store的求值函数完成参数校验与取值逻辑。从 internal/cmd/cmd_get.go 可以看到evalGET的核心只是s.Get(key)——所有存储细节都被封装在Store中。Store的实现位于 internal/store/store.go其内部使用基于sync.Map的RegMap作为键值容器见NewStoreRegMap。过期键的惰性删除Store.Get底层走getHelperinternal/store/store.go其行为值得注意func (store *Store) getHelper(k string, touch bool) *object.Obj { obj, ok store.store.Get(k) if ok { if hasExpired(obj, store) { store.deleteKey(k, obj) obj nil } else if touch { ... } } return obj }当 key 已存在但已过期时GET会触发惰性删除lazy deletion立即删除该过期键并返回空对象最终表现与键不存在一致。这意味着带 TTL 的键一旦过期GET读到的就是空字符串。这一点在 tests/commands/ironhawk/get_test.go 的测试用例Get with expiration中得到了验证SET k978 v EX 2 - OK GET k978 - v GET k978 - 等待 5 秒后内部对象类型与字符串转换DiceDB 的存储对象Obj定义于 internal/object/object.go包含Type、Value与LastAccessedAt字段其中Value是interface{}可以承载多种类型。SET在写入时会尝试将值解析为原生类型见 internal/cmd/cmd_set.go 的CreateObjectFromValue能解析为int64→ 以ObjTypeInt存储能解析为float64→ 以ObjTypeFloat存储否则 → 以ObjTypeString存储。GET返回时必须把这些内部类型统一转为字符串该转换由getWireValueFromObj完成func getWireValueFromObj(obj *object.Obj) (string, error) { if obj nil { return , nil } switch obj.Type { case object.ObjTypeInt: return fmt.Sprintf(%d, obj.Value.(int64)), nil case object.ObjTypeString: return obj.Value.(string), nil case object.ObjTypeByteArray, object.ObjTypeHLL: return string(obj.Value.([]byte)), nil case object.ObjTypeFloat: return fmt.Sprintf(%f, obj.Value.(float64)), nil default: return , errors.ErrUnknownObjectType } }由此可以总结出GET的类型行为内部对象类型场景GET 返回ObjTypeInt写入的值为整数十进制整数字符串ObjTypeString写入的值为普通字符串原字符串ObjTypeFloat写入的值为浮点数六位小数格式如123.123000ObjTypeByteArray/ObjTypeHLL字节数组 / HyperLogLog按 UTF-8 字节串输出其他对象类型如 hash、set 等返回unknown object type错误浮点数的输出格式在 tests/commands/ironhawk/get_test.go 的用例Set Floating Point Value中可以看到SET fp 123.123后GET fp返回123.123000——这是因为 Go 的fmt.Sprintf(%f, ...)默认输出六位小数。错误场景与类型防护参数数量错误GET不带任何参数时返回wrong number of arguments for GET command类型错误对一个ObjTypeString/ObjTypeInt之外的复杂类型如HSET写入的 hash 对象执行GET会返回unknown object type错误而不会返回底层结构体内容。这一点在get_test.go的Get on other ObjType should give error用例中有明确断言。也就是说GET只对字符串类、数值类及字节类对象友好对 hash、set、sorted set、bloom filter 等复合类型并不适用——读取这些结构需要对应类型的命令如HGET、ZRANGE。进阶GET.WATCH 查询订阅GET声明了IsWatchable: true这是 DiceDB 的核心特色能力之一。基于GET的查询订阅命令为GET.WATCH文档见 docs/src/content/docs/commands/GET.WATCH.md实现见 internal/cmd/cmd_get_watch.go。GET.WATCH的行为与普通GET不同它建立一次查询订阅当被观察的 key 值在任意客户端发生更新时订阅客户端会持续收到GET命令的输出结果而不只是变更通知。GET.WATCH 官方示例client1:7379 SET k1 v1 OK client1:7379 GET.WATCH k1 entered the watch mode for GET.WATCH k1 client2:7379 SET k1 v2 OK client1:7379 ... entered the watch mode for GET.WATCH k1 OK [fingerprint2356444921] v2流程拆解客户端 1 先SET k1 v1再执行GET.WATCH k1进入订阅模式客户端 2 对k1执行SET k1 v2更新值客户端 1 收到推送OK [fingerprint2356444921] v2——不仅收到变更通知还直接拿到了更新后的值v2。底层实现要点从 internal/cmd/cmd_get_watch.go 可以看到GET.WATCH的实现非常简洁func evalGETWATCH(c *Cmd, s *dstore.Store) (*CmdRes, error) { r, err : evalGET(c, s) if err ! nil { return GETWATCHResNilRes, err } r.Rs.Fingerprint64 c.Fingerprint() return r, nil }即GET.WATCH完全复用evalGET的求值逻辑只是在结果上附加了命令指纹Fingerprint64供客户端标识订阅来源。指纹计算使用farm.Fingerprint64见 internal/cmd/cmds.go 的Cmd.Fingerprint()。与此同时Store的写入路径会在每次Put时通过cmdWatchChan通知 watch 管理器见 internal/store/store.go 的putHelper从而驱动订阅客户端收到新的GET结果。这套机制让 DiceDB 可以用类似 SQL 实时查询的体验去订阅一个键的最新值。测试验证与行为清单GET的集成测试位于 tests/commands/ironhawk/get_test.go覆盖的行为可以作为权威行为清单测试用例输入期望输出Get with expirationSET k978 v EX 2后立即GET再等 5 秒GET先v后过期惰性删除Get without expirationSET k v后GET kvSet Floating Point ValueSET fp 123.123后GET fp123.123000Get on other ObjTypeHSET map k1 v1后GET map错误unknown object typeGet with non existent keyGET nekGET with no keys or argumentsGET错误wrong number of arguments for GET command总结GET虽简单却是理解 DiceDB 架构的绝佳入口取值语义GET key返回字符串值键不存在返回空字符串参数不符或类型不匹配则报错底层存储经由executeGET → evalGET → Store.Get的分片定位与惰性过期删除链路类型系统内部对象按 int / float / string / bytearray 等类型存储GET负责统一的字符串化输出可订阅通过IsWatchable: true支撑GET.WATCH为实时键值推送、缓存事件监听等场景提供基础。如需深入源码推荐顺序阅读internal/cmd/cmd_get.go → internal/store/store.go → internal/object/object.go → internal/cmd/cmd_get_watch.go再配合 tests/commands/ironhawk/get_test.go 验证各边界行为。【免费下载链接】dicedbOpen-source, low-latency key/value engine built on Valkey with query subscriptions and hierarchical storage tiers.项目地址: https://gitcode.com/GitHub_Trending/dic/dicedb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门