fusen-rs
一个最像RPC框架的Rust-RPC框架
fusen-rust是一个高性能,轻量级的微服务框架,通过使用Rust宏来解决目前主流rpc框架使用复杂,性能低等问题,不需要通过脚本和脚手架生成RPC调用代码,通过宏来进行编译期"反射"来实现高性能的调用,满足RPC调用的简易性,同时支持Dubbo3,SpringCloud微服务生态可以与Java项目进行服务注册发现与互相调用,并且支持用户自定义组件等功能.
功能列表
- 【已完成】 RPC调用抽象层(Rust宏)
- 【已完成】 多协议支持(HTTP1, HTTP2)
- 【已完成】 服务注册与发现(Nacos, Zookeeper)
- 【已完成】 微服务生态兼容(Dubbo3, SpringCloud)
- 【已完成】 自定义组件(自定义负载均衡器,Aspect环绕通知组件)
- 【待建设】 配置中心(热配置, 本地文件配置, Nacos)
- 【待建设】 HTTP3协议支持
快速开始
Common InterFace
rust
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct ReqDto {
pub str: String,
}
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct ResDto {
pub str: String,
}
#[fusen_trait(package = "org.apache.dubbo.springboot.demo")]
#[asset(spring_cloud = "service-provider")]
pub trait DemoService {
async fn sayHello(&self, name: String) -> String;
#[asset(path = "/sayHelloV2-http", method = POST)]
async fn sayHelloV2(&self, name: ReqDto) -> ResDto;
#[asset(path = "/divide", method = GET)]
async fn divideV2(&self, a: i32, b: i32) -> String;
}
Server
rust
#[derive(Debug)]
struct DemoServiceImpl {
_db: String,
}
#[fusen_server(package = "org.apache.dubbo.springboot.demo")]
impl DemoService for DemoServiceImpl {
async fn sayHello(&self, req: String) -> FusenResult<String> {
info!("res : {:?}", req);
Ok("Hello ".to_owned() + &req)
}
#[asset(path="/sayHelloV2-http",method = POST)]
async fn sayHelloV2(&self, req: ReqDto) -> FusenResult<ResDto> {
info!("res : {:?}", req);
Ok(ResDto {
str: "Hello ".to_owned() + &req.str + " V2",
})
}
#[asset(path="/divide",method = GET)]
async fn divideV2(&self, a: i32, b: i32) -> FusenResult<String> {
info!("res : a={:?},b={:?}", a, b);
Ok((a + b).to_string())
}
}
Client
rust
#[tokio::main(worker_threads = 512)]
async fn main() {
fusen_common::logs::init_log();
let context = FusenApplicationContext::builder()
.add_register_builder(
NacosConfig::builder()
.server_addr("127.0.0.1:8848".to_owned())
.app_name(Some("fusen-service".to_owned()))
.server_type(Type::Fusen)
.build()
.boxed(),
)
.add_register_builder(
NacosConfig::builder()
.server_addr("127.0.0.1:8848".to_owned())
.app_name(Some("service-provider".to_owned()))
.server_type(Type::SpringCloud)
.build()
.boxed(),
)
.add_register_builder(
NacosConfig::builder()
.server_addr("127.0.0.1:8848".to_owned())
.app_name(Some("dubbo-client".to_owned()))
.server_type(Type::Dubbo)
.build()
.boxed(),
)
.add_handler(CustomLoadBalance.load())
.add_handler(ClientLogAspect.load())
//todo! Need to be optimized for configuration
.add_handler_info(HandlerInfo::new(
"org.apache.dubbo.springboot.demo.DemoService".to_owned(),
vec!["CustomLoadBalance".to_owned(),"ClientLogAspect".to_owned()],
))
.build();
//进行Fusen协议调用HTTP2 + JSON
let client = DemoServiceClient::new(context.client(Type::Fusen).unwrap());
let res = client
.sayHelloV2(ReqDto {
str: "world".to_string(),
})
.await;
info!("rev fusen msg : {:?}", res);
//进行Dubbo3协议调用HTTP2 + GRPC
let client = DemoServiceClient::new(context.client(Type::Dubbo).unwrap());
let res = client.sayHello("world".to_string()).await;
info!("rev dubbo3 msg : {:?}", res);
//进行SpringCloud协议调用HTTP1 + JSON
let client = DemoServiceClient::new(context.client(Type::SpringCloud).unwrap());
let res = client.divideV2(1, 2).await;
info!("rev springcloud msg : {:?}", res);
}
自定义组件
微服务自定义组件包括, 负载均衡器, 服务熔断/限流组件, 前置后置请求处理器, 服务链路追踪等组件. 由于组件的定制化程度较高, 所以本项目参考AOP的概念提供了两种自定义组件,来提供灵活的请求处理。
LoadBalance
负载均衡组件, LoadBalance提供一个select接口来实现用户自定义服务均衡配置。
rust
#[handler(id = "CustomLoadBalance")]
impl LoadBalance for CustomLoadBalance {
async fn select(
&self,
invokers: Vec<Arc<InvokerAssets>>,
) -> Result<Arc<InvokerAssets>, fusen_rs::Error> {
invokers
.choose(&mut rand::thread_rng())
.ok_or(fusen_rs::Error::from("not find server : CustomLoadBalance"))
.cloned()
}
}
Aspect
动态代理的概念相信大家都不陌生,这是Java对类进行增强的一种技术,而Spring框架利用此特性封装出了更高级的模型, 那就是AOP面先切面编程模型. 本组件就是参考了此模型,实现了环绕式通知模型, 用户可以基于此组件实现各种组件需求,比如说服务熔断/限流,请求的前置后置处理,链路追踪,请求响应时间监控等需求.
rust
#[handler(id = "ClientLogAspect" )]
impl Aspect for ClientLogAspect {
async fn aroud(
&self,
filter: &'static dyn fusen_rs::filter::FusenFilter,
context: fusen_common::FusenContext,
) -> Result<fusen_common::FusenContext, fusen_rs::Error> {
let start_time = get_now_date_time_as_millis();
info!("client send request : {:?}", context);
//执行RPC调用
let context = filter.call(context).await;
info!(
"client receive response RT : {:?}ms : {:?}",
get_now_date_time_as_millis() - start_time,
context
);
context
}
}