前言
sylar 框架的内容挺多的:
- 日志库,配置库
- 协程网络库
- 异步Redis,Mysql Sqlite3 ORM
- HTTP1.1/2.0,gRPC,Rock RPC
- 服务发现,性能监控
- Module动态加载机制(业务和框架分离)
HTTP相关的网络协议,涉及的前置知识过多,且适用性不强(网上也有很多成熟的轮子,比不过)。
Rock RPC
Rock RPC 往往是长连接-短消息,所以此处Rock只是收、发各用一个协程即可满足需求。并不像Http 一样,分配整个worker。
┌─────────────────────────────────────┐
│ 应用层 (Module) │
├─────────────────────────────────────┤
│ 服务层 (RockServer/Client) │
├─────────────────────────────────────┤
│ 流层 (RockStream) │
├─────────────────────────────────────┤
│ 协议层 (RockProtocol) │
├─────────────────────────────────────┤
│ 传输层 (TCP Socket) │
└─────────────────────────────────────┘
协议层 RockProtocol
消息类型体系
Rock 协议基于 protocol.h 中定义的基础消息类型
- Request:sn,cmd,time
- Response:sn,cmd,result(uint32_t),resultStr(str)
- Notify:notify
rock_protocol.h
- RockBody: 消息体,body(str),支持 Protobuf 序列化和反序列化。(Protobuf原理 todo)
- RockRequest : 请求消息,继承自 Request 和 RockBody
- RockResponse : 响应消息,继承自 Response 和 RockBody
- RockNotify : 通知消息,继承自 Notify 和 RockBody
- RockMsgHeader:消息头,magic(0x12 0x21),version(1),flag(标志位,是否gzip压缩),length(消息体长度)
RockMessageDecoder:继承自MessageDecoder抽象类,传入Stream::ptr,具体的读和写方法都在这里,包括 解压缩,序列化,反序列化。 ⭐
服务层 RockServer
- RockServer:RPC服务端,继承自 TcpServer,重写 HandleClient 方法,处理客户端连接。
- 创建
RockSession session会话对象,管理客户端连接。 - 遍历所有类型为 ROCK 的模块,调用其
onConnect()方法,通知各个模块有新的客户端连接成功。 - 相对应的,为
session会话设置 回调函数(foreach 遍历每个模块的onDisconnect)。当客户端断开连接时,会通知所有ROCK类型的模块执行清理工作。 session设置请求RequestHandler处理回调函数。当会话收到客户端发来的请求时,会依次调用所有ROCK模块的handleRequest方法来处理请求,直到某个模块返回 true 表示已处理该请求。session设置通知NotifyHandler处理回调函数。当会话收到客户端发来的通知时,会依次调用所有ROCK模块的handleNotify方法来处理通知,直到某个模块返回 true 表示已处理该通知。
- 创建
- RockSession: 继承自 RockStream
流层 RockStream
这里的 模板方法 设计模式值得学习 ⭐
graph TD
Stream抽象基类 --> |继承| SocketStream
SocketStream --> |包含| Socket
SocketStream --> |继承| AsyncStream
AsyncStream --> |内部struct| SendCtx
SendCtx --> |继承| Ctx
AsyncStream --> |继承| RockStream
RockStream --> |内部struct| RockSendCtx
RockStream --> |内部struct| RockCtx
SendCtx --> |继承| RockSendCtx
Ctx --> |继承| RockCtx
streams
- socket_stream
- 包含 Socket,继承 Stream
- 重写 Stream 的 read() , write() , close() 实际就是调用 Socket 的 read() , write() , close() 方法 (将socket和stream依赖分离,通过socket_stream这种具体的子类实现。⭐)
- zlib_stream
- async_stream ⭐
- 读写分离:读写操作运行在独立的协程中,互不阻塞。
- 内部 struct:
SendCtx预留doSend()纯虚函数;Ctx继承SendCtx,作为消息响应上下文,提供doRsp()把协程重新添加调度(此时得到了完整响应)。
- 核心接口:
doRecv()纯虚函数(接收数据包返回Ctx)。doRead()循环调用doRecv(),得到ctx后调用Ctx::doRsp();doWrite()循环调用,加锁交换queue队列,SendCtx::doSend()发送数据。
async_stream子类需要提供 Ctx doRecv() 实现;SendCtx子类需要提供SendCtx::doSend()实现。
总结:子类提供 接收数据包返回Ctx方法,以及具体Ctx的发送方法。⭐
RockStream
- RockStream 继承自 AsyncSocketStream
- 提供
RockStream::request()方法,用于发送数据。- 创建局部变量
Ctx::ptr,设置sn,cmd,time,body。 - 调用
enqueue()方法,把Ctx添加到发送队列中。 - 添加
定时器,避免协程任务丢失。 - 当接收完数据,
Ctx里的Fiber恢复执行 - 此时 协程的局部变量一直在 ,所以可以得到请求的结果。(见代码理解)
- 创建局部变量
- 重写
doRecv(),提供接收数据的方法。返回Ctx::ptr。(只有RESPONSE才会返回)- 如果是
RESPONSE,在 m_ctxs(发出的请求上下文记录) 中删除 sn 对应的上下文,并返回该上下文。 - 如果是
NOTIFY,调用 handleNotify 回调- 调用
m_notifyHandler回调 (RockServer::handleClient设置的回调),成功后直接结束,无响应。
- 调用
- 如果是
REQUEST,调用handleRequest回调:- 生成相应的
rsp - 调用
m_requestHandler回调,成功后sendMessage(rsp)- 将
RockSendCtx通过enqueue()加入发送队列中。 AsyncSocketStream::doWrite从发送队列里取出RockSendCtx。通过doSend()发送数据。
- 将
- 生成相应的
- 如果是
- 提供
RockSendCtx继承自SendCtx,重写doSend();RockCtx继承自Ctx,重写 doSend()。提供具体的发送逻辑。(序列化-发送数据)
总结:
sequenceDiagram
User->>RockStrem: request()
RockStrem->>RockStrem: 生成ctx,添加定时器,发送任务添加到队列
RockStrem->>AsyncSocketStream: doWrite(),唤醒 队列条件变量。
AsyncSocketStream->>RockStrem: 通过具体的ctx的doSend()发送数据。
Note over AsyncSocketStream, RockStrem: 等待接收数据。
AsyncSocketStream->>AsyncSocketStream: doRead(),不停接收数据。
AsyncSocketStream->>RockStrem: 通过具体的doRecv()接收数据。
RockStrem->>RockStrem: doRecv()判断数据包类型,只有响应包才会返回具体结构。通知、请求都通过回调执行。请求处理完后,sendMessage(rsp)
RockStrem->>AsyncSocketStream: 响应包,通过ctx->doRsp()恢复协程。
AsyncSocketStream->>RockStrem: 协程恢复,处理Ctx::ptr请求结果。
服务发现
数据结构
- NSNode
- 表示单个服务节点,包含 IP、端口、权重信息
- 使用 IP 和端口生成唯一标识 ID
- NSNodeSet
- 按命令字(cmd)组织的节点集合
- 提供添加、删除、获取节点的方法
- 使用读写锁保证线程安全
- NSDomain
- 表示一个域名下的所有服务
- 内部使用命令字到节点集合的映射
- 提供域名级别的服务管理功能
- NSDomainSet
- 管理所有域名
- 提供域名的增删查操作
- NSClientInfo
- 维护客户端会话信息
- 记录客户端注册的节点信息和域名到命令的映射