程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

腾讯开源框架TarsCpp-rpc设计分析-client(一)

balukai 2025-08-01 15:39:24 文章精选 1 ℃

前言

Tars是腾讯开源的微服务平台,包含了一个高性能的rpc框架和服务治理平台,TarsCpp是其C++版本。对于以C++为主要开发语言,同时还想深入了解rpc和微服务框架具体实现的同学来说,Tars是一个极佳的选择。

想像一下,如果你自己来设计一个rpc-client,都应该考虑哪些因素?

  • 一个高效、可靠的调度器(epoll模型)
  • 如何设计同步调用、异步调用
  • 使用适当的协议来发送请求、解析结果
  • 提供不同的选择服务节点的策略,包括但不限于轮询、hash、权重等
  • 管理服务节点状态,包括不限于节点是否已经连接,是否正在连接中,连接是否超时,是否需要重连,连接超时时间设置,连接重连时间设置等
  • 如何可靠的接收请求、发送结果,请求量怎么控制,接收到1.5个请求怎么办,请求发送完迟迟没收到结果怎么办

这些问题都可以从tars-rpc-client中寻找到实现答案

1 rpc-client概要设计

学习源码的一个重要目的是学习“别人家”模块或项目的设计思路,设计思路的珍贵之处在于其超脱了项目甚至语言的层次,可以迁移到其他地方。

tar-rpc-client主要由4个组件构成:ServantProxy,ObjectProxy,CommunicatorEpoll,AsyncProcThread,其中:

  • ServantProxy:直接与使用者交互,提供简便易用接口
  • ObjectProxy:封装网络层收发细节
  • CommunicatorEpoll:提供收发调度功能
  • AsyncProcThread:提供异步调用功能

四个组件的关系见图1。


  • 在主线程里,ServantProxy是工头,它承接客户需求并加以整理,然后按照一定顺序分给众小弟们(一个小弟是一个ObjectProxy)
  • 小弟ObjectProxy在调度线程中依赖CommunicatorEpoll中的epoll模型高效有序的干活
  • 如果是同步调用,ServantProxy会在主线程中等待,直到ObjectProxy在调度线程中完成请求发送和结果接收
  • 如果是异步调用,主线程不会阻塞,主线程中注册的回调函数在回调线程AsyncProcThread中被执行
  • 一个小弟ObjectProxy对应一个CommunicatorEpoll,一个ServantProxy可以对应多个ObjectProxy
  • 一个CommunicatorEpoll可以对应多个AsyncProcThread
  • 2 CommunicatorEpoll概要设计

    CommunicatorEpoll在rpc-client设计中处于核心地位,它确认了client信息流的调度方式。

    CommunicatorEpoll是一个封装后的epoll模型,CommunicatorEpoll设计巧妙之处在于将客户调用函数的动作也作为了epoll的触发条件。下面以图2说明CommunicatorEpoll的设计架构


    CommunicatorEpoll将epoll_wait中得到的消息分为两类,一类是处理ObjectProxy消息,另外一类是处理EPOLLIN、EPOLLOUT、EPOLLERR消息。

    最核心的系统调用函数也列在了图2上,包括紫色的epoll_wait和epoll_ctl、绿色的connect、send和readv。

    图2中展示了一个最简单的函数调用流程,下面的序号对应了图2中箭头里的序号

    1. 当用户调用ServantProxy::Hello方法时候,ServantProxy将这个方法包含的内容组成一个msg
    2. 通过ObjectProxy将msg注册到CommunicatorEpoll中。
    3. epoll_wait获取了通知,处理msg
    4. 链接server端,成功后获取connent fd
    5. 将connect fd注册到CommunicatorEpoll中
    6. 发送请求
    7. 接收结果

    2.1 同步call

    rpc_client一般有两种基本的调用方式,sync_call和async_call,即同步call和异步call。先看下同步call的实现机制。

    同步call实现机理较简单,只需要主线程、调度线程配合就能实现。见图3.


  • 主线程调用函数后阻塞等待调度线程的信号通知,
  • 调度线程收到结果后,主备发送信号通知
  • 发送信号通知
  • 主线程接收到信号后,本次调用结束
  • 2.2 异步call

    异步call需要主线程、调度线程、回调线程三个组件,见图4


  • 主线程调用完方法后直接结束
  • 调度线程接收到结果后,放入回调线程的队列\_msgQueue中
  • 回调线程循环等待\_msgQueue中的msg,当有msg进入时,会使用pop\_front取出
  • 调用回调函数处理msg
  • 未完-待续

    Tags:

    最近发表
    标签列表