首页/新闻资讯/正文详情

rurpc

发布时间:2026/11/3 10:06:16 来源:云帆数科 栏目:资讯中心
rurpc
rurpc 工程讲解src/rurpc是 ruwebframe 框架的RPC 模块基于字节跳动开源的 Volo-gRPC 实现远程过程调用。它同时内置了服务端、客户端、服务发现注册三块能力。代码生成依赖独立 cratevolo-gen后者在build.rs中依据idl/*.proto编译期生成桩代码rurpc通过volo_gen::volo_gen::...路径引用。目录结构src/rurpc/ ├── mod.rs # 模块声明入口 ├── main.rs # 独立演示 bin 入口装配并启动 RPC 及其它插件 ├── rpcplugin/ # RPC 生命周期插件真正拉起 gRPC 服务 │ ├── rpc_plugin.rs # RpcPlugin实现 Plugin traitstart 时注册并启动服务 │ ├── rpc_plugin_init.rs # #[ctor] 自动注册单例 Bean │ └── rpc_plugin_test.rs ├── rpcreg/ # RPC 服务注册etcd 服务发现参考 webreg │ ├── rpc_etcd_reg.rs # RpcEtcdReg / RpcRegValue │ ├── rpcreg_plugin.rs # RpcregPluginstart 注册、stop 注销 │ └── rpcreg_plugin_init.rs ├── rpcrouter/ # 注册汇总入口插件层调用的唯一入口 │ ├── mod.rs │ └── register_rpc.rs # register_rpc()Once 幂等转调 rpcservice::register_rpc() ├── rpcservice/ # 业务服务实现 │ ├── mod.rs # 子模块声明 │ ├── register_rpc.rs # 依次触发三个服务自注册 │ └── voloservice/ # 每个服务一个文件 │ ├── item_service.rs # 商品服务codec impl ItemService 自注册 │ ├── hello_service.rs # 问候服务codec impl HelloService 自注册 │ └── mail_service.rs # 邮件服务codec impl MailService 自注册 ├── voloclient/ # Volo-gRPC 客户端 │ ├── rpc_client.rs # RpcClientC 通用客户端 RpcClients 业务门面 │ ├── rpc_client_init.rs │ └── rpc_client_test.rs └── voloserver/ # Volo-gRPC 服务端 ├── mod.rs # register_rpc! 宏 模块声明 re-export ├── rpc_server.rs # RpcServer启动/绑定/注入路由 ├── rpc_container.rs # RpcContainer注册函数表 serve ├── volo_routes.rs # VoloRoutes 路由容器 RpcRouterLayer register_service ├── rpc_server_init.rs # RpcServer 的 DI Bean 注册 ├── rpc_container_init.rs # RpcContainer 的 DI Bean 注册 └── rpc_server_test.rs一、代码生成地基接口定义在idl/*.protoproto 文件package逻辑服务名volo_example.protovolo.examplevolo.example.ItemServicevolo_hello.protohellohello.HelloServicevolo_mail.protomailmail.MailServicevolo-gen/build.rs编译这些 proto 生成volo_gen.rs为每个服务生成*Servicetrait服务端需实现、*ServiceServer*RequestRecv/*ResponseSend*ServiceClientBuilder、*ServiceClient二、服务端 voloserver2.1 启动骨架RpcServerRpcServer是单例 Bean负责启动与注入不点名任何具体服务启动RpcServer::start()开独立线程 自建 tokio 运行时避免占用主线程。绑定serve()读取RpcConfigenable / serverName / serverPort绑定0.0.0.0:port并用local_addr()打印实际端口。注入路由build_server()把路由容器整体作为内层Layer注入Serverpubfnbuild_serverIL,OL(self,server:ServerIL,OL,)-ServerStackRpcRouterLayer,IL,OL{server.layer(RpcRouterLayer(VoloRoutes::global().router()))}2.2 路由容器VoloRoutesvolo_routes.rs对齐 web 的RouteContainer各服务自行登记 codec容器统一持有启动时一次性注入。内部RwLockRouterRouter是 volo 公开类型内部用BoxCloneService装箱因此类型各异的 codec 能收敛进同一容器。global()提供惰性单例Once OnceLockregister(codec)写入router()取出供注入。RpcRouterLayer把取出的Router直接作为Server的内层ServiceLayer::layer忽略 inner。同文件导出自由函数register_service(codec)作为各服务的自注册入口。pubstructVoloRoutes{router:RwLockRouter,}implVoloRoutes{pubfnglobal()-staticVoloRoutes{/* Once OnceLock */}pubfnregisterC(self,codec:C){/* take add_service put back */}pubfnrouter(self)-Router{/* read().clone() */}}pubfnregister_serviceC(codec:C){VoloRoutes::global().register(codec);}2.3 服务容器RpcContainerrpc_container.rs单例 Bean持有注册函数表RwLockVecfn()并提供运行入口register(registrar)把一个fn()型注册函数压入表。register_all_services()Once保护下遍历执行表内注册函数幂等避免同路径重复挂载导致 voloRouterpanic。serve(incoming, signal)先register_all_services()再RpcServer::build_server(Server::new())最后run_with_shutdown。两条注册路径说明重要路径 A当前默认生效RpcPlugin::register→rpcrouter::register_rpc()→rpcservice::register_rpc()→ 各xxx_service::register_rpc()→voloserver::register_service(codec)→ 直接写入VoloRoutes。不经过RpcContainer的函数表。路径 B预留自由函数rpc_server::register_rpc(fn())把注册函数压入RpcContainer再由register_all_services()统一触发。当前只有路径 A 被接入因此RpcContainer.registrars实际为空register_all_services()是无副作用的空遍历路由仍能正常注入因为build_server读取的是VoloRoutes。两条路径都受Once幂等保护。2.4 业务实现rpcservice/voloservice每个服务一个文件codec 构建、业务实现、自注册三件事都在同一文件里。统一由宏register_rpc!#[macro_export]定义在voloserver/mod.rs生成 codec 函数与自注册函数// voloserver/mod.rsmacro_rules!register_rpc{($name:ident,$srv:ident,$recv:ty,$send:ty,$doc:expr){#[doc $doc]fn$name()-implService...NamedServiceCloneSendSyncstatic{ServiceBuilder::new($srv::new(RpcServer::new())).build::$recv,$send()}/// 登记本服务到全局路由容器。pubfnregister_rpc(){crate::rurpc::voloserver::register_service($name());}};}服务文件里只需一行宏调用 一段impl// rpcservice/voloservice/hello_service.rsusecrate::{register_rpc,rulog};register_rpc!(codec,HelloServiceServer,HelloServiceRequestRecv,HelloServiceResponseSend,构建问候服务 HelloService 的编解码器。);implHelloServiceforRpcServer{/* say_hello ... */}业务实现示例impl MailServiceRpc for RpcServer把请求转成SendMailDto再代理给业务 BeanMailService::send。2.5 汇总入口rpcrouterrpcrouter::register_rpc::register_rpc()是插件层调用的唯一注册入口Once保证幂等内部转调rpcservice::register_rpc()// rpcrouter/register_rpc.rspubfnregister_rpc(){staticONCE:std::sync::Oncestd::sync::Once::new();ONCE.call_once(||{rpcservice::register_rpc();});}// rpcservice/register_rpc.rspubfnregister_rpc(){item_service::register_rpc();hello_service::register_rpc();mail_service::register_rpc();}2.6 新增一个 gRPC 服务在rpcservice/voloservice/新建xxx_service.rs写一行register_rpc!(...)再写impl XxxService for RpcServer。在rpcservice/voloservice/mod.rs加pub mod xxx_service;。在rpcservice/register_rpc.rs加一行xxx_service::register_rpc();。无需改动rpc_server.rs——服务端骨架与注册机制完全与服务数量解耦。命名提示voloserver/mod.rs的宏名为register_rpc!它生成的函数也叫register_rpc()voloserver::rpc_server另有自由函数register_rpc(fn())rpcrouter::register_rpc与rpcservice::register_rpc各有一个同名函数。它们处于不同模块作用域调用时需写全路径以免混淆。三、客户端 voloclientRpcClientC是通用客户端C为某服务生成的 client 类型一套逻辑服务所有服务pubstructRpcClientC{service_name:staticstr,// 逻辑服务名build:fn(staticstr,SocketAddr)-C,// client 构建函数cell:OnceLockC,// 懒加载缓存}implC:CloneRpcClientC{pubfnnew(service_name:staticstr,build:fn(staticstr,SocketAddr)-C)-Self;pubfnclient(self)-ResultC,String;// 取缓存或按配置构建}地址解析收敛为一个自由函数resolve_target()读全局配置serverName/serverPort非法地址回退127.0.0.1OnceLock缓存每个服务只建一次新增服务只需RpcClient::new(服务名, |n, a| XxxServiceClientBuilder::new(n).address(a).build())RpcClients是业务门面单例 Bean为每个服务持有一个RpcClient并暴露业务友好方法字段通用客户端业务方法itemRpcClientItemServiceClientget_item(item_id)helloRpcClientHelloServiceClientsay_hello(name)mailRpcClientMailServiceClientsend_mail(SendMailDto)业务方法内部完成 DTO ↔ proto 消息互转并统一把构建失败转成Status::Unavailable。四、生命周期插件 rpcpluginRpcPlugin实现框架Plugintraitstart()依次执行init()→plugin_default_init()register()→rpcrouter::register_rpc::register_rpc()登记各服务RpcServer::new().start()拉起 gRPC 服务由#[ctor]自动注册为单例在src/main.rs通过ctx.add(get_bean_unwrap!(RpcPlugin))纳入统一启动流程。五、服务发现 rpcregRpcregPlugin把当前 RPC 服务注册到etcd复用 webreg 的EtcdReg底层key/ruwebframe/rpc/{serverName}valueRpcRegValue含urlgrpc://host:port、serviceTyperpc等start_register()异步注册并持续续期stop_register()注销如此服务端启动后在 etcd 注册客户端/网关可据此做服务发现与路由而不必写死地址。模块职责小结模块角色关键类型rpcplugin生命周期驱动RpcPluginrpcreg注册中心RpcregPlugin/RpcEtcdRegrpcrouter注册汇总入口register_rpc()rpcservice业务实现每服务一文件register_rpc!生成的服务实现_c voloclient调用方RpcClientC/RpcClientsvoloserver提供方骨架 容器RpcServer/RpcContainer/VoloRoutesmain.rs演示入口装配各插件注册机制对比与 web 路由对齐环节webrurpc容器RouteContainerVoloRoutes登记项路由配置服务 codec自注册各 controller 调用reg_route各服务文件register_rpc!生成的register_rpc()汇总入口apply_routes(conf)rpcrouter::register_rpc()注入装配到Appserver.layer(RpcRouterLayer(router))单例OnceLockOnce OnceLock/ DI Bean一图流调用链[main.rs] ctx.add(RpcregPlugin → 注册到 etcd) ctx.add(RpcPlugin) └─ start ├─ register → rpcrouter::register_rpc()Once │ └─ rpcservice::register_rpc() │ ├─ item_service::register_rpc() → voloserver::register_service(codec) │ ├─ hello_service::register_rpc() → voloserver::register_service(codec) │ └─ mail_service::register_rpc() → voloserver::register_service(codec) │ └→ VoloRoutes::register(codec) └─ RpcServer::start → serve ├─ RpcContainer::register_all_services()当前表为空 ├─ RpcServer::build_server → layer(RpcRouterLayer(VoloRoutes::global().router())) └─ run_with_shutdown └─ Router 分发 → impl ItemService / HelloService / MailService └─ MailService::send ctx.add(WebPlugin) 客户端侧RpcClients { get_item / say_hello / send_mail } → RpcClientC::client()OnceLock 缓存 resolve_target → volo_gen client → 对端 RpcServer

相关推荐

STM32智能药盒
STM32智能药盒

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 10:05:15

Claude Opus 5.5 一句话需求造出 703 条视频,新手能上手吗
Claude Opus 5.5 一句话需求造出 703 条视频,新手能上手吗

Claude Opus 5.5 一句话需求造出 703 条视频,新手能上手吗 【免费下载链接】awesome-opus5-5-videos A growing collection of viral videos made with Claude Opus 5.5 and the prompts behind them. Watch each original next to a live remake on Skillry. Updat… · 2026/11/3 10:05:15

【演进式架构】短期项目的演进式架构:不追求完整,只追求三道护栏
【演进式架构】短期项目的演进式架构:不追求完整,只追求三道护栏

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 10:04:15

IShell 3.0:全协议终端工具的高效运维实践
IShell 3.0:全协议终端工具的高效运维实践

1. IShell 3.0:运维工程师的瑞士军刀IShell 3.0的发布在运维圈引起了不小的震动。作为一款集成了SSH、RDP、VNC、Telnet等多种协议的终端工具,它解决了我们日常工作中最头疼的多工具切换问题。记得去年处理一个跨平台运维项目时,我不得不在5个… · 2026/11/3 11:45:24

SQL DDL详解:数据库结构设计与优化实践
SQL DDL详解:数据库结构设计与优化实践

1. SQL基础概念解析 SQL(Structured Query Language)是关系型数据库管理系统的标准语言,它就像数据库世界的"普通话"。想象一下,如果你要和来自不同国家的人交流,英语就是通用语言;而在数据库领域,无论你使用… · 2026/11/3 11:45:24

Linux常用命令大全:按功能域分类的学习地图与易错点清单
Linux常用命令大全:按功能域分类的学习地图与易错点清单

简介:面向Linux初学者与运维入门者的命令速查手册,聚焦日常系统管理与文件操作场景,帮助读者摆脱对图形界面的依赖、建立命令行操作的基本功。资源为单个PDF文档,压缩包约130KB,篇幅精炼、便于随查随用,适合… · 2026/11/3 11:45:24

JavaScript常用库函数解析与实战技巧
JavaScript常用库函数解析与实战技巧

1. JavaScript常用库函数概览 作为一名前端开发者,我每天都要和各种JavaScript库函数打交道。这些看似简单的工具函数,实际上构成了我们日常开发的基石。记得刚入行时,我总是习惯性地重复造轮子,直到有次看到同事用一行 Array.pr… · 2026/11/3 11:45:24

程序员证书考试:语言处理程序核心知识点解析
程序员证书考试:语言处理程序核心知识点解析

1. 程序员证书考试核心知识点解析作为一名从业多年的程序员,我深知软考程序员证书对于职业发展的重要性。今天我们就来深入剖析语言处理程序这个核心考点,这也是考试中经常出现的难点内容。程序员证书考试主要考察计算机基础知识和编程能力,其… · 2026/11/3 11:45:24

分布式电源选址定容问题的现实挑战
分布式电源选址定容问题的现实挑战

1. 分布式电源选址定容问题的现实挑战 在电力系统规划领域,分布式电源(Distributed Generation, DG)的选址和容量确定一直是个复杂的技术难题。传统电力网络设计以集中式发电为主,而随着可再生能源占比提升,如何在配电… · 2026/11/3 11:44:24

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46

STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码