kizumi_header_banner_img

Learn. Build. Share.

加载中

文章导读

基于脚手架微服务的视频点播系统-脚手架开发部分-brpc中间件介绍与使用及二次封装


avatar
xiu114514 2025年10月24日 85
基于脚手架微服务的视频点播系统-脚手架开发部分-brpc中间件介绍与使用及二次封装

@TOC

一.介绍

RPC(Remote Procedure Call)远程过程调⽤,简单来说就是客⼾端在不知道调⽤细节的情况下,调⽤远程计算机上的某个功能就像调⽤本地功能⼀样,其主要⽬标就是让构建分布式计算(应⽤)更容易,在提供强⼤的远程调⽤能⼒时不损失本地调⽤的语义简洁性。

二.安装

先安装依赖:

再进行brpc的安装:

三.使用到的类与接口介绍

3.1日志相关

因为brpc自带有日志输出模块,与websocket一样,无法更换除非改库内源码中所有的⽇志输出操作后重新编译库进⾏安装。我们这里主要是要禁用掉不需要的⽇志输出,避免大量日志输出占视线:

3.2protobuf相关类与接口

3.3服务端使用到的接口

3.4http相关类与接口

3.5客户端相关接口

3.6定时任务相关

需要包含如下头文件: bthread/unstable.h , butil/time.h

四.使用样例

4.0编写proto文件

编译后会生成两个文件cal.pb.cc与cal.pb.h

4.1同步服务端

在这里插入图片描述 根据上图我们可以得到服务端创建的一个大致流程: 0.重写Calculator类中的服务函数,在我们的例子中应该是Add与Hello这两个业务处理函数 1.定义重写类对象 2.定义服务器配置对象ServerOptions(我们这里只把idle_timeout_sec连接超时时间设置为-1表示不超时即可) 3.创建brpc服务器对象 4.使用brpc::Server提供的AddService注册我们上面重写的服务类 5.启动服务器 6.等待服务器退出 案例代码如下:

记住业务处理函数比如Add的声明周期是哪里调用done->Run()哪里才算结束,如果不调用就会导致业务函数始终不结束业务处理。

4.2同步客户端

客户端的创建流程大致如下: 1.创建服务端与客户端通信的信道channel 2.使用stub对象通过channel发起rpc调用 3.打印结果 示例代码如下:

运行之后客户端会打印出a+b=30的字样,博主这里便不再演示了。

4.3异步客户端

我们上面使用stub.Add发起远端的Add请求时,最后一个参数填NULL表示同步调用,如果想要异步调用,就需要使用brpc为我们提供的NewCallback来创建一个Closure的done对象。然后将收到请求之后的逻辑写到该done的回调函数中:

需要注意的是,brpc::NewCallback 不允许直接传入一个需要多个参数的 lambda 表达式作为回调。因为brpc::NewCallback 的工作方式类似于 std::bind。你提供一个函数(如你的 callback 函数)和它需要的所有参数(controller, request, response)。NewCallback 会将这些东西“打包”起来。当 RPC 完成后,brpc 框架只会调用这个包的 Run() 方法,然后 Run() 方法内部再用你当初提供的参数去调用你的 callback 函数。 但是实际上我们这样子去调用NewCallback也是不行的,虽然官方给的例子是可行的,但不知道我这里为什么不行:

所以我们自己构建一个方法来支持这种方式的lamda表达式传入:

这其实是我们后面封装的方法,它放在命名空间limerpc中,这时我们这样子写就可以传入上面的一个lamda表达式了:

4.4异步服务端

这其实就很简单了,我们上面说过,业务函数的声明周期是由done->Run()决定的,所以我们可以将原来的业务处理放到一个线程中,在线程处理完业务时调用done->Run()即可完成异步处理的逻辑:

4.5http服务端

我们上面说过,http请求和响应的相关信息都存储在google::protobuf::RpcController*中,所以我们服务端要想能够响应http请求,还是需要先重写对应的http请求处理函数,然后在该重写函数中实现我们的业务逻辑即可:

4.6http客户端

这里相较于上面的远程rpc请求有些不同,它不需要再通过protobuf提供的stub对象发起请求,而是直接通过brpc创建的channel信道中的CallMethod方法发起http请求。请求路由应该与我们在proto中定义的服务类名称一致。比如在我们的示例中如若想要访问服务端的Hello服务,路由应该是这样的:

还有一个比较特殊的点,我们也可以通过http客户端发起rpc请求,我们示例中的rpc服务为Add,首先需要将路由设置为:

其次我们的请求正文格式必须是json格式,请求的json正文格式必须与Add在proto文件中定义的AddRequest格式相同:

请求的json正文示例:

这样便可以访问远端的Add服务,最后服务端会返回json格式的响应内容写到brpc::Controller的response_attachment()中。客户端示例代码如下:

注释部分为普通http请求,非注释部分为http访问rpc服务的请求,读者可自行去掉或加上注释编译运行查看不同结果。 Makefile如下:

五.二次封装

因为brpc一般是使用在分布式系统上的。一个服务可能在不同的机器上都会提供,但是有的时候部分机器可能会挂掉,所以此时就需要将其移除,如果有新的服务器添加了此项服务,那么就需要将其管理起来,所以我们可以设计如下的类:

当然我们的服务不可能单单只有一个,所以我们要将不同服务的RpcChannels管理起来。而且有的时候并不是所有的服务器提供的所有的服务我们都需要关心,我们还需要管理哪些服务是需要关心的:

也就是说,根据上面的两个类我们可以知道,客户端访问远端rpc服务的流程在我们封装下变成了: 1.告诉SvcRpcChannels我客户端想要访问的服务 2.SvcRpcChannels根据客户端提供的消息,查找对应的RpcChannels 3.SvcRpcChannels找到了对应的RpcChannels,让RpcChannels给一个可用服务信道 4.RpcChannels通过RR轮询的方式,遍历自身的可用信道,保证返回效率的同时负载均衡。最后通过SvcRpcChannels的get_channel返回一个可用信道。 5.客户端收到可用服务信道,使用该信道发起http请求或远程rpc服务请求 这是客户端的相关类,当然我们再封装一个解决我们上面说的客户端异步调用无法直接传lamda表达式的工厂类:

最后我们再来封装一个服务端的工厂类:

完整封装如下:

一个简单的使用样例:

cal.proto:

rpc_client.cc

rpc_server.cc

makefile:

 



评论(已关闭)

评论已关闭

日历

2025 年 10 月
 123456
78910111213
14151617181920
21222324252627
282930