# myrpc **Repository Path**: wobuhuicode/myrpc ## Basic Information - **Project Name**: myrpc - **Description**: 简单rpc框架 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 0 - **Created**: 2023-02-20 - **Last Updated**: 2024-03-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # myrpc --- # 第一部分:基础框架 ## 组件 这一部分是实现 RPC 调用的基础,主要包括以下组件: * `Server`相关组件,负责监听请求并处理返回。 * `Client`相关组件,负责发送请求,处理返回。 * `Proxy`相关组件,负责包装`Client`的请求过程,将远程调用包装成本地调用形式。 ## 逻辑流程 ```mermaid sequenceDiagram autonumber participant User participant Proxy participant Client participant Server Server->>Server: 初始化,注册服务,开始监听 Client->>Client: 初始化,连接服务,监听发送队列 User->>Proxy: 请求包装后的服务实例 Proxy->>User: 返回包装后的服务实例 User->>+Proxy: 调用服务方法,阻塞等待 Proxy->>Client: 请求放入消息队列 Client->>Server: 发送请求 Server->>Client: 返回请求结果 Client->>Proxy: 通知结果已返回 Proxy->>User: 结束阻塞,返回结果 ``` ## 重难点及解决方法 1. 直接使用TCP接收发送数据会有粘包问题,需要进行拆包。这里我用自定义协议方法,在每个请求体前面附上这个请求包含的字节数。在接收请求时,首先检查从buffer中读取到的字节数是否达到协议头的基本字节数,如未达到就放弃本次解析,等待下次 read 事件。如果达到就解析协议头然后按量读取数据,这里如果读取到的数据长度不够则按同样的规则放弃本次读取,同时将 buffer 的索引置于开头。 2. Proxy 层发送请求后如何阻塞又如何被 Client 通知唤醒需要精心设计。这里采用把一个信号量变量和一个返回体对象包装成一个通知体在一起放入一个UUID到通知体的Map中,其中UUID标识了这是哪个请求对象的通知体。在 Proxy 发送请求前,自己 acquire 信号量,然后把请求放入队列,再继续 acquire 就进入阻塞。当 Client 拿到返回结果后拿出通知体,释放拿出通知体,填入返回体,再释放信号量,就完成了 Proxy 的唤醒。 --- # 第二部分:服务发现 ## 关于 Zookeeper 客户端:Apache Curator Curator主要解决了三类问题 1. 封装ZooKeeper client与ZooKeeper server之间的连接处理 2. 提供了一套Fluent风格的操作API 3. 提供ZooKeeper各种应用场景(recipe, 比如共享锁服务, 集群领导选举机制)的抽象封装 ## Zookeeper 结点设计 以`myrpc`作为根节点,`Service Name`作为二级节点,`provider/consumer`作为三级节点,`Address`作为四级节点,用以记录服务提供者或订阅者的网络地址信息。 ```mermaid graph LR ROOT((myrpc)) --- a(Service Name 1) ROOT --- b(Service Name 2) a --- c(provider) a --- d(consumer) c --- e(Application Name:IP:Port) c --- f(Application Name:IP:Port) d --- g(Application Name:IP:Port) ``` ## 服务注册与发现流程 ### 服务注册 ```mermaid graph a(创建服务对象实例) --> b(获取服务接口名, 获取本地地址和监听接口) b --> c(构造 Zookeeper Path, 创建临时节点) ``` ### 服务发现 ```mermaid graph a(记录所有需要订阅的服务名) --> b(根据服务名查询 Zookeeper 节点) b --> c(创建服务订阅者的 Zookeeper 节点) c --> d(与所有查询到的服务提供者建立连接, 保存连接) d --> e(设置 Watcher 观察已订阅的服务提供者孩子节点) ``` + 其中,设置的`Watcher`会在服务提供者孩子节点发生改变时触发,通过对比新的服务提供者地址和现有已连接的服务提供者的地址,删除或新增现有保存的连接。 + 客户端同时保持了所有可用的服务提供者的连接,当发生 RPC 调用时会从中随机选出一个连接发出请求。