目录

  • 1.往Server里添加Service(业务代码)
  • 2.设置服务器参数
  • 3.启动服务器

平时的工作用到了baidu-rpc搭建rpc服务,作为戈君大神的大作,在没有开源的时候,这个c++ 的rpc框架在厂内就已经好评颇多,无论是性能、文档、还是代码注释都很优秀,内部使用范围特别广,17年开源,开源版本叫做brpc,开源后不少大厂都有使用,目前已经进入Apache孵化器,源码以及文档的地址如下:https://github.com/apache/incubator-brpc。

个人对底层的东西比较感兴趣,因此有结合文档和源码深入学习下这个rpc框架的想法,整个brpc代码量不小,很早就开始看了,实话说一开始看其实挺费劲的,不过越往后看越觉得这个框架的博大精深,所以准备把看过的部分总结成文章,今天整理了一部分先发第一篇,算是看源码的随笔吧,第一次写博客,如有错误,还望指正。

brpc作为一个完整的rpc框架,自然同时支持作为Server和作为Client,这篇文章聊的是作为Server的使用方式以及启动Server、开启相应服务的内部处理过程。bprc面向用户的接口还是挺友好的,调用很简单,这里贴一个官方http的demo:
搭建一个rpc Server,概括起来就是新建一个Server对象,设置好参数,往里面添加自己的Service,然后启动,Server可以包含多个Service,而Service又可以包含多个method,具体的某次请求就是针对某个method的,这个demo里的Server有三个Service。

具体怎么使用bprc这里不多说,官方文档有详细说明。因为是从业务使用开始接触这个框架的,所以我打算首先从和实际应用场景最接近的添加服务、启动服务器这块开始入手看源码。brpc里有个Server类,作为服务器的话均是通过这个类作为入口,从rpc服务器的构造过程来说,主要是如下三个过程:

1.往Server里添加Service(业务代码)

这里所说的Service,指的是继承自proto文件描述的Service的用户Service,brpc是基于protobuf的,protobuf不包含RPC的实现,但却有RPC的相关定义,比如Service,brpc就用到了这个,即便是用不到protobuf消息的http服务,服务接口也得定义在proto文件中,是为了确保所有的服务声明集中在proto文件中。

Addservice函数有多个重载,比如上面官方demo调用的第三个是基于restful mapping字符串的,如下:

各个不同的Addservice重载调用的都是AddServiceInternal这个内部具体实现。总的来说Addservice就是指定哪些服务去处理哪里来的请求。

参数有三个,protofuf Service类型的服务,是否是内部服务(brpc提供了监控之类的内部服务)的标识,以及添加的service的选项。
google::protobuf::Service是一个公共的基类,用户定义在proto文件里的Service会被预处理成继承自这个基类的一个类,用户需要继承这个类去写真正的业务代码(实现method对应的虚函数),框架层面上统一按父类google::protobuf::Service处理。AddServiceInternal就是把Service里的method拿出来映射到指定地址上,首先会调用InitializeOnce() 实现server的初始化(只会初始化一次,用pthread_once调用GlobalInitializeOrDieImpl,保证只执行一次),如下:

brpc是支持多协议的,而且是同一个端口,会有一个协议解析机制来保证相对高的效率,本身内置了各种协议,用户也可以很方便地自己新增协议支持,GlobalInitializeOrDieImpl函数里面,最重要的就是注册了包括http在内的各种各样的协议支持,简单来说就是指定了各协议的消息解析函数、server端用到的request处理函数、client端用到的response处理函数,比如request处理函数,以下图中http协议为例,ProcessHttpRequest就负责处理接收到的http request,这个函数里会处理request后交给用户自定义函数去处理。这里暂时不详细展开,后面的文章再详细说明。

2.设置服务器参数

brpc提供了丰富的参数设置,包括最大并发,是否开启ssl、关闭闲置连接时间等,具体的可以参考官方文档,这里不再赘述,主要是通过Serveroption类型指定参数和直接调用set_xxx来直接设置。

3.启动服务器

调用Start函数来启动服务器,和Addservice一样,start也有多种调用方式的重载,最终都是调用的StartInternal

在StartInternal函数里,首先是一些准备工作,根据option进行了一些设置,包括ssl设置以及是否创建tls数据、提前启动好需要的bthread(brpc用到的m:n线程库的线程,bthread也是bprc性能优异的关键之一,后面的文章再具体介绍)等。然后就是在指定的ip和端口范围(在范围内不断尝试,成功了就停止继续尝试)上启动监听,一个server也只支持监听一个端口。主要代码如下:

Acceptor顾名思义就是消息的接收器,BuildAcceptor也就是构建接收器,如果为NULL则调用BuildAcceptor

在BuildAcceptor里面,最重要的如下:

首先通过ListProtocols拿到所有注册支持的协议,然后遍历这些协议,通过AddHandler添加,handler是处理message的,注意到这里handler.process都是protocols[i]里面的process_request,也就是对应协议在服务端使用用来处理过接收到的请求的,对应的如果是客户端用的则是process_response。

StartAccept核心内容如下:

brpc是采用epoll来处理事件的,用的是边缘触发,options.on_edge_triggered_events是epoll边缘触发事件到来后的处理函数,也就是OnNewConnections作为事件的处理函数,顾名思义也就是新连接到来后使用的处理函数,这里不展开讲OnNewConnections的具体实现,后面的文章再详细介绍。

关于Socket类型,就是对fd等资源的的封装方便再多线程环境下使用,官方介绍是这样的:
和fd相关的数据均在Socket中,是rpc最复杂的结构之一,这个结构的独特之处在于用64位的SocketId指代Socket对象以方便在多线程环境下使用fd。
Socket::Create函数是根据options新建socket并把id存入第二个参数中,内部最重要的操作就是用options.on_edge_triggered_event所指代的函数进行epoll add,在当前服务端start的场景下,也就是在监听fd上用OnNewConnections注册epoll事件处理新过来的连接,至此启动完成,后续等待epoll事件进行相应处理。

负责第一步处理epoll事件的则是EventDispatcher,是分发epoll event的模块,负责把fd上边缘触发的事件分发给消费者(具体的业务处理函数),可以有多个,分别运行在不同的bthread上,具体的数量取决于参数,它所做的事情就是启动后不断去epoll_wait,获得epoll事件后交由相应函数处理,如果是epoll_in事件,调用Socket::StartInputEvent,如果是epoll_out,调用Socket::HandleEpollOut,简化后的核心代码如下:

StartAccept后,服务器基本就启动完成了。再回到最开始的实例里,最后会调用server.RunUntilAskedToQuit()


RegisterQuitSignalOrDie里主要是用signal函数注册了退出信号,一旦有退出信号s_signal_quit会为true,从而跳出循环并停止server。

brpc作为服务端整个启动过程基本就是这样,后面再写文章继续介绍一下brpc里一些关键的机制和类,以及在fd上收发请求的一些细节。

brpc源码解析(一)—— rpc服务添加以及服务器启动主要过程相关推荐

  1. (Nacos源码解析五)Nacos服务事件变动源码解析

    Nacos源码解析系列目录 Nacos 源码编译运行 (Nacos源码解析一)Nacos 注册实例源码解析 (Nacos源码解析二)Nacos 服务发现源码解析 (Nacos源码解析三)Nacos 心 ...

  2. Myth源码解析系列之五- 服务启动源码解析

    通过前面几篇文章,我们搭建了环境,也进行了分布式事务服务的体验,相信大家对myth也有了一个大体直观的了解,接下来我们将正式步入源码解析之旅~~ order服务启动源码解析(myth-demo-spr ...

  3. Flink源码解析 | 从Example出发:理解Flink启动流程

    从<Apache Flink本地部署>这篇文章中可以看到,我们启动集群都是通过脚本start-cluster.sh开始执行. 我们的源码解析之路就从flink的bash脚本入手. star ...

  4. brpc源码解析(二)—— brpc收到请求的处理过程

    文章目录 一.基本设计思路 二.实现细节 三.总结 作为rpc服务器,在启动过后,最主要的一个过程就是收到请求后的处理,而这就牵涉到一个网络编程相关最基本的部分:如何有效地处理socket传过来地数据 ...

  5. brpc源码解析(四)—— Bthread机制

    目录 一.概述 二.启动入口函数 三.内部启动函数 四.worker工作入口 五.总结 Bthread是brpc用到的一个线程库,也是brpc的核心之一,默认情况下,包括用户代码在内的绝大部分代码都是 ...

  6. brpc源码解析(七)—— worker基于ParkingLot的bthread调度

    前面已经介绍过了bthread的主要机制,但对于具体的调度细节没有过多涉及,本篇将在着重介绍下bhtread在各个worker(taskgroup)之间的调度方式. 在brpc里,有个和调度相关的重要 ...

  7. dubbo源码解析(二)

    大家好,我是烤鸭: dubbo 源码解析: 1.服务导出 介绍: Dubbo 服务导出过程始于 Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑.整个逻辑大致可分为三 ...

  8. Dubbo 实现原理与源码解析系列 —— 精品合集

    摘要: 原创出处 http://www.iocoder.cn/Dubbo/good-collection/ 「芋道源码」欢迎转载,保留摘要,谢谢! 1.[芋艿]精尽 Dubbo 原理与源码专栏 2.[ ...

  9. Spring源码解析:自定义标签的解析过程

    2019独角兽企业重金招聘Python工程师标准>>> spring version : 4.3.x Spring 中的标签分为默认标签和自定义标签两类,上一篇我们探究了默认标签的解 ...

最新文章

  1. How to attack a windows domain
  2. Windows系统调用学习笔记(三)—— 保存现场
  3. SOP,TSSOP,PLCC,BGA这些封装的中英文解释
  4. CSDN博客文章阅读模式插件(附源码)
  5. 获取指定存储过程的参数定义
  6. 多元统计分析matlab,matlab与应用多元统计分析..doc
  7. UE编辑器中的快捷键(一)
  8. 企业使用邮箱的重要性
  9. CSP 201903-2 二十四点 python (python有如神助)
  10. Effective Java 2.0_中英文对照_Item 6
  11. SDN南向接口和北向接口
  12. Mac安装clion教程
  13. android移动日记代码,Android开源项目-小熊日记源码
  14. 设计模式之代理模式(第二篇)
  15. 单片机开发不可避免会遇到很多头疼的问题
  16. 手机上最简单的计算机,怎么把手机文件传到电脑,才最简单又快速?
  17. 用批处理删除N天前或指定日期时间(前后)创建(或修改)的文件
  18. Artemis集群(18)
  19. 04 数据控制语言DCL
  20. unity网络实战开发(丛林战争)-前期知识准备(012-UI框架开发)

热门文章

  1. MIT博士研发绘画机器人Utensil,精通绘画和激光切割
  2. ElasticSearch的安装以及与springboot的集成
  3. ROMP:Monocular, One-stage, Regression of Multiple 3D People
  4. 【松岩论道】一个道理说明股市人的发展不是靠江湖式的随机跳跃分析!
  5. laravel tcg/voyager 安装问题记录
  6. TCP/IP前端面试
  7. 5个超经典实验,老杨带你高效进阶OSPF
  8. 【安全狗高危安全通告】OpenSSL存在远程代码执行漏洞和拒绝服务漏洞
  9. 不安分的管家——Jenkins
  10. 生成带有红黄绿码的二维码,并转base64