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条件
字符2sdstrue
哈希ziplist

len <= hash_max_ziplist_entries (默认为512)

dict!ziplist 
列表quicklisttrue
集合intsetvalue 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 基本说明的主要内容,如果未能解决你的问题,请参考以下文章

Shader HLSL片段说明

10 基本说明

c_cpp Robolution基本代码片段

html PHP代码片段: - AJAX基本示例:此代码演示了使用PHP和JavaScript实现的基本AJAX功能。

VSCode自定义代码片段10—— 数组的响应式方法

注释的基本使用与文档注释的特殊功能