10 基本说明
Posted 蓝风9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10 基本说明相关的知识,希望对你有一定的参考价值。
前言
关于 redis 的一些基本的代码层面上的约束
关于一些规范中介绍的东西, 我们这里可以从代码层面上来直观的了解这些东西
本文的相关代码 拷贝自 redis-6.2.0
代码来自于 https://redis.io/
高级数据结构
这里的数据类型指的是给用户用到的这些数据类型, 也就是我们常用的 STRING, HASH, LIST, SET, SORTEDSET
Redis provides data structures such as strings, hashes, lists, sets, sorted sets with range queries
几种客户端使用的数据结构 : 字符串, 列表, 集合, 有序集合, 哈希
低级数据结构
几种支持高级数据结构的底层数据结构 : 原始指针, 整形, dict, zipmap, linkedlist, ziplist, intset, skiplist, embedded string, quicklist
高级数据结构和低级数据结构之间的关系
字符串 : sds
哈希 : ziplist, dict
列表 : quicklist
集合 : intset, dict
有序集合 : ziplist, skiplist
高级数据结构低级数据结构映射表格
高级数据结构 | 数据结构1 | 数据结构1条件 | 数据结构2 | 数据结构2条件 |
字符2 | sds | true | ||
哈希 | ziplist | len <= hash_max_ziplist_entries (默认为512) | dict | !ziplist |
列表 | quicklist | true | ||
集合 | intset | value could cast longlong | dict | !intset |
有序集合 | ziplist | len < zset_max_ziplist_entries(默认为128) len(value) < zset_max_ziplist_value(默认为64) | dict | !ziplist |
shared 对象
这里主要是一些 享元, 业务中比较常用的一些东西, 使用的同一个对象(不可变)
各个命令以及配置信息的初始化
配置的是命令的相关元素据信息, 命名名称, 命令处理函数, 参数的约束, 一些其他约束
每一个 part 的数据, 都可以看上面的注释的相关的信息
各个配置项的初始化
各个配置项 别名, 是否修改, 默认值, 配置合法的校验, 更新配置的校验
关于网络交互
基于 connection 从客户端读取数据
基于 connection 向客户端读取数据
下面的一系列 high level api, low level api, 都是为了吧 业务的数据写出到 c->buf, c->reply 里面暂存起来
那么什么时候 把数据交互给客户端这边呢?
writeToClient 这里面实现了 基于 c->connection 写出 c->buf, c->reply 里面的数据到 客户端
addReply 系列相关
addReply / addReplySds / addReplyProto
这几个都是 业务这边经常会使用到的一些 high level functions
优先将数据添加到 buf 里面
如果 buf 空间不够 或者 已经使用 reply 列表, 则将数据添加到 reply 列表
addReplyErrorObject / addReplyError / addReplyErrorSds / addReplyErrorFromat / addReplyErrorLength
添加错误信息 返回给客户端, 格式为
-ERRORCODE Error Message<CR><LF>
addReplyStatusLength / addReplyStatus / addReplyStatusFormat
返回状态信息给客户端, 格式为
+Status Message<CR><LF>
addReplyDeferredLen / setDeferredReply / setDeferredAggregateLen / setDeferredArrayLen / setDeferredMapLen / setDeferredSetLen / setDeferredAttributeLen / setDeferredPushLen
addReplyDeferredLen : reply 列表中新增一个 dummy 节点, 来占位
setDeferredReply : 查看 next 节点是否有足够的空间来存储 [s, s+len-1], 如果有 将 next 的已有的数据向后移动 len, 复制 [s, s+len-1] 到 next 头部, 移除 dummy 节点
否则新建一个 replyBlock, 来存储 [s, s+len-1] 的数据, 将 replyBlock 关联到 dummy 节点上面[不再是 dummy 节点了]
setDeferredAggregateLen : 添加指定前缀 + [s, s+len-1] 的内容到 reply 列表中
在 protocol 2 中, 长度均使用 "*"
在 protocol 3 中, ArrayLength 使用 "*", MapLength 使用 "%", SetLength 使用 "~", AttributeLength 使用 "|", PushLength 使用 ">"
addReplyDouble / addReplyHumanLongDouble
addReplyDouble : 如果 d 是 infinite, 根据 protocol 做不通的响应, 大致的内容为 "inf", "-inf"
如果是 protocol2, 添加 "\\$$len\\r\\n$data\\r\\n" 到 buffer
如果是 protocol3, 添加 ",$data\\r\\n" 到 buffer
addReplyHumanLongDouble : 如果是 protocol2, 添加 "\\$$len\\r\\n$data\\r\\n" 到 buffer
如果是 protocol3, 添加 ",$data\\r\\n" 到 buffer
addReplyLongLongWithPrefix / addReplyLongLong / addReplyAggregateLen / addReplyArrayLen / addReplyMapLen / addReplySetLen / addReplyAttributeLen / addReplyPushLen
addReplyLongLongWithPrefix : 如果 prefix 是 "*", ll 位于 [0, OBJ_SHARED_BLUKHDR_LEN], 使用 共享变量 "*$ll" 到 buffer
如果 prefix 是 "$", ll 位于 [0, OBJ_SHARED_BLUKHDR_LEN], 使用 共享变量 "\\$$ll" 到 buffer
添加 "$prefix\\r\\n$data\\r\\n" 到 buffer
addReplyLongLong : 如果是 0, 1 使用共享变量, 否则添加 ":$ll" 到 buffer
addReplyAggregateLen / addReplyArrayLen / addReplyMapLen / addReplySetLen / addReplyAttributeLen / addReplyPushLen : 就是根据协议选择前缀 + 数据添加到 buffer
addReplyNull / addReplyBool / addReplyNullArray
addReplyNull : 如果是 protocol2, 添加 "$-1\\r\\n" 到 buffer, 如果是 protocol3, 添加 "_\\r\\n" 到 buffer
addReplyNullArray : 如果是 protocol2, 添加 "$-1\\r\\n" 到 buffer, 如果是 protocol3, 添加 "_\\r\\n" 到 buffer
addReplyBool : 如果是 protocol2, 添加 ":1", ":0" 到 buffer, 如果是 protocol3, 添加 "#t\\r\\n", "#f\\r\\n" 到 buffer
addReplyBulkLen / addReplyBulk / addReplyBulkCBuffer / addReplyBulkSds / addReplyBulkString
以 bulk 的格式来返回数据, 格式协议为 "\\$$len\\r\\n$data\\r\\n"
addReplyVerbatim
如果是 protocol2, 直接以 bulk 的格式返回 "\\$$len\\r\\n$data\\r\\n"
如果是 protocol3, 添加 "=($len+4)\\r\\n$ext:$data\\r\\n" 到 buffer
_addReplyToBuffer / _addReplyProtoToList
写出给定的 [s, s+len-1] 到 buffer 或者 reply
业务上调用的一系列的 addApplyXX 都是基于这里的 _addReplyToBuffer 或者 _addReplyProtoToList
一次命令交互的数据
我们以 如下命令为例 来进行抓包
请求概览
概览一下发现四个请求, 我们这里核心关注 交互数据的这两个请求[第一个 和 第三个]
第一个请求为 redis-cli 向 redis-server 发送的请求的数据
第二个请求为 redis-server 向 redis-cli 发送的一个收到数据的 ack 包
第三个请求为 redis-server 向 redis-cli 发送的响应的数据
第四个请求为 redis-cli 向 redis-server 发送的一个收到数据的 ack 包
get name 的请求
前面的 tcp 协议元数据, ip 协议, ethernet 协议 这部分的数据 我们暂时不关注, 我们主要关注 tcp 协议传递的数据
数据部分主要有 23 个字节, 内容为 "*2\\r\\n$3\\r\\nget\\r\\n$4\\r\\nname\\r\\n", 合计 23 bytes
这个就是 redis-cli 这边 传递给 redis-server 的数据, redis-server 拿到数据之后封装到 c->querybuf 里面, 后面进而解析参数 放到 c->argc, c->argv 里面
比如这里最终解析之后 c->argc 为 2, c->argv[0] 为 "get" 对应的 robj, c->argv[1] 为 "name" 对应的 robj
get name 的响应
前面的 tcp 协议元数据, ip 协议, ethernet 协议 这部分的数据 我们暂时不关注, 我们主要关注 tcp 协议传递的数据
数据部分主要有 11 个字节, 内容为 "$5\\r\\nzerry\\r\\n", 合计 11 bytes
这个就是 redis-server 这边 传递给 redis-cli 的数据, redis-cli 拿到响应数据之后, 展示在 cmd 里面
完
以上是关于10 基本说明的主要内容,如果未能解决你的问题,请参考以下文章