Closed tigerzhang closed 5 years ago
过奖过奖. (要是写得好的话可能不需要文档吧 :joy: )
先简单说一下吧, 详细的之后看有没有空补上...
Proxy
里负责处理 epoll API (实际上是一组包装在 epoll API 上的函数调用), 几种继承自 Connection
的类型将它们的 fd
交给 epoll. 其中
Acceptor
监听端口并产生 Client
SlotsMapUpdater
更新槽位映射并间接产生 Server
Client
进入 epoll 之后从保持可接受数据的状态, 每次接受输入后解析之并选择相应的 Server
(也就是对应的 Redis 实例) 把命令发出去, 命令都返回之后就把结果顺序写出给 Client
Client
有 3 个 command groups 分别表示一条指令的三个不同阶段: _parsed_groups
刚刚从 buffer 内容中解析出来的命令分组 ; _awaiting_groups
一次处理后会将 _parsed_groups
里的内容转移到 _awaiting_groups
并写出给 Server
, 换言之表示 "指令写出等待返回" ; _ready_groups
指令的结果返回了, 等待将结果写回给 Client
的指令.
相对的 Server
里只有 2 个分组: _commands
表示刚刚从客户端来的, _sent_commands
表示写出了的. 而一旦有命令返回, 就马上把结果给 Client
, 而不会存在 Server
对象里.
而 CommandGroup
则有个函数是 select_remote
表示如何选择对应的 Server
, 对于单一 key 指令 SingleCommandGroup
来说就是选出 key 对应的那个, 而像 MGET
多 key 的 MultipleCommandsGroup
可能会选择多个 Server
.
写出指令之后就等待从 Server
读入结果. 处理结果要稍简单一些, 代码在 core/response.hpp|cpp 中. Response
有个虚函数 rsp_to
其实也只有两种情况: 正常返回, 或发生了 MOVED
之类的集群状态改变, 后者要更新集群映射再重试.
要注意的是, 一些 IO 错误是用异常处理的, 在 Buffer
类中直接 throw
并在 epoll 循环里捕获.
最后, Buffer
的效率其实很挫...
@neuront 谢谢回复。有个问题没太想明白,CommandGroup 这个命名的由来是因为像 MSET 这种命令会被拆分成多个 SET 命令,所有才会用 Group 来命名吗?
@TigerZhang 正是. 从 Client
视角看来只是一个指令, 但是从 Server
看来是一个组.
@neuront 非常感谢,基本都掌握了。 今天一直没有想明白 struct sref 和 struct sptr。我的理解,struct sptr 是为了方便使用 unique_ptr,不过感觉好像可以直接用 std 的相关函数。struct sref 就没太看明白,sref 封装的 unique_ptr::pointer,看起来好像又不能管理指针的生命周期,不能自动释放内存。
@TigerZhang 这个是我的锅, 之前一个项目里移过来的文件.
sptr
就是包了一层 unique_ptr
限制了一些 API. sref
就是 reference_wrapper
, 表示无生命周期控制权的弱引用. 早些的 gcc 版本里还没有 reference_wrapper
, make_unique
, 于是自己来了几个轮子, 顺便把名字缩短了一点. 用习惯了就拉到这个项目里了.
另外在 Command
和 Server
之间中用了 shared_ptr
存待发送的内容, 这是为了在简化这种情况的处理: 这些内容发送之前, 如果客户端断开连接, 那么 Client
实例会析构, 同时其中的 Command
也会间接失效, 如果这些 Command
进入了 Server
的等待队列, 那么接着 Server
就会读取到失效内存; 为了防止这一情况发生, Server
里的输出缓冲区是个 shared_ptr<Buffer>
容器 BufferSet
, 这样客户端单方面退出, 其中的缓冲区内存还不会失效.
@neuront 明白了,后面有时间我准备把这一部分修改成标准库的做法,方便团队其它人上手。谢谢。
在 redis-cerberus 基础上做了一个初始版本 https://github.com/TigerZhang/redis-cerberus , 用来作为一个代理,整合一个 redis cache 和 redis DB (ardb),对外暴露统一的 redis 接口。
最近我们团队也在调研redis proxy,看到了cerberus。安排童鞋了解下实现,可源码中LOG打印好少啊,为此加了大量的TRACE LOG :joy: .作者有时间可写下详细的实现文档啊,这样也有利于推广
我们团队觉得 redis-cerberus 代码质量不错,准备在这个代码基础上开发几个特性。
请问有关于代码里面几个重要的类的描述文档吗?最好有典型的数据流向路径的描述文档。
谢谢