< 返回版块

kwsc98 发表于 2024-04-16 00:02

Tags:Rust,RPC,Dubbo,Volo,SpringCloud

fusen-rs 一个最像RPC框架的Rust-RPC框架

fusen-rust是一个高性能,轻量级的微服务框架,通过使用Rust宏来解决目前主流rpc框架使用复杂,性能低等问题,不需要通过脚本和脚手架生成RPC调用代码,通过宏来进行编译期"反射"来实现高性能的调用,满足RPC调用的简易性,同时支持Dubbo3,SpringCloud微服务生态可以与Java项目进行服务注册发现与互相调用.

题外话:目前Rust主流的Rpc框架是真的没法用,换句话说Grpc基本就没法用,通过IDL再使用脚本生成代码,这句话看着就不怎么靠谱...微服务这块还得是学Java,本项目支持RPC服务同时还支持实现WebService服务,甚至你可以用Client当一个Figen用,还望大家多多点Star支持呀!

https://github.com/kwsc98/fusen-rs

快速开始

Common InterFace

#[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(path="/DemoService",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

#[derive(Clone, Debug)]
struct DemoServiceImpl {
    _db: String,
}

#[fusen_server(package = "org.apache.dubbo.springboot.demo")]
#[asset(path="/DemoService")]
impl DemoService for DemoServiceImpl {

    async fn sayHello(&self, req: String) -> FusenResult<String> {
        info!("res : {:?}", req);
        return Ok("Hello ".to_owned() + &req);
    }
    #[asset(path="/sayHelloV2-http",method = POST)]
    async fn sayHelloV2(&self, req: ReqDto) -> FusenResult<ResDto> {
        info!("res : {:?}", req);
        return 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())
    }
}

#[tokio::main(worker_threads = 512)]
async fn main() {
    fusen_common::logs::init_log();
    let server = DemoServiceImpl {
        _db: "我是一个DB数据库".to_string(),
    };
    //支持多协议,多注册中心的接口暴露
    FusenServer::build()
        //初始化Fusen注册中心,同时支持Dubbo3协议与Fusen协议
        .add_register_builder(
            NacosConfig::builder()
                .server_addr("127.0.0.1:8848".to_owned())
                .app_name(Some("fusen-service".to_owned()))
                .server_type(fusen_rs::register::Type::Fusen)
                .build()
                .boxed(),
        )
        //初始化SpringCloud注册中心
        .add_register_builder(
            NacosConfig::builder()
                .server_addr("127.0.0.1:8848".to_owned())
                .app_name(Some("service-provider".to_owned()))
                .server_type(fusen_rs::register::Type::SpringCloud)
                .build()
                .boxed(),
        )
        //同时兼容RPC协议与HTTP协议
        .add_protocol(Protocol::HTTP("8081".to_owned()))
        .add_protocol(Protocol::HTTP2("8082".to_owned()))
        .add_fusen_server(Box::new(server))
        .run()
        .await;
}

Client

lazy_static! {
    static ref CLI_FUSEN: FusenClient = FusenClient::build(
        NacosConfig::builder()
            .server_addr("127.0.0.1:8848".to_owned())
            .app_name(Some("fusen-client".to_owned()))
            .server_type(fusen_rs::register::Type::Fusen)
            .build()
            .boxed()
    );
    static ref CLI_DUBBO: FusenClient = FusenClient::build(
        NacosConfig::builder()
            .server_addr("127.0.0.1:8848".to_owned())
            .app_name(Some("dubbo-client".to_owned()))
            .server_type(fusen_rs::register::Type::Dubbo)
            .build()
            .boxed()
    );
    static ref CLI_SPRINGCLOUD: FusenClient = FusenClient::build(
        NacosConfig::builder()
            .server_addr("127.0.0.1:8848".to_owned())
            .app_name(Some("springcloud-client".to_owned()))
            .server_type(fusen_rs::register::Type::SpringCloud)
            .build()
            .boxed()
    );
}

#[tokio::main(worker_threads = 512)]
async fn main() {
    fusen_common::logs::init_log();
    //进行Fusen协议调用HTTP2 + JSON
    let client = DemoServiceClient::new(&CLI_FUSEN);
    let res = client
        .sayHelloV2(ReqDto {
            str: "world".to_string(),
        })
        .await;
    info!("rev fusen msg : {:?}", res);

    //进行Dubbo3协议调用HTTP2 + GRPC
    let client = DemoServiceClient::new(&CLI_DUBBO);
    let res = client.sayHello("world".to_string()).await;
    info!("rev dubbo3 msg : {:?}", res);

    //进行SpringCloud协议调用HTTP1 + JSON
    let client = DemoServiceClient::new(&CLI_SPRINGCLOUD);
    let res = client.divideV2(1, 2).await;
    info!("rev springcloud msg : {:?}", res);
}

Dubbo3

本项目同时兼容dubbo3协议,可以很方便的与Java版本的Dubbo3项目通过接口暴露的方式进行服务注册发现和互调。

Rust的Server和Client完全不用改造就如上示例即可。

Java版本的Dubbo3项目,代码层面不需要改造,只需要添加一些依赖和配置(因Dubbo3使用接口暴露的方式默认不支持json序列化协议,而是采用fastjson2的二进制序列化格式,所以这里我们需手动添加fastjson1的支持)

这里我们使用duboo3的官方示例dubbo-samples-spring-boot项目进行演示 https://github.com/apache/dubbo-samples

首先我们需要把Server和Client的服务的pom.xml都添加fastjson和nacos的maven依赖

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-serialization-fastjson</artifactId>
    <version>2.7.23</version>
</dependency>
<!-- registry dependency -->
<dependency>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-client</artifactId>
    <version>2.2.0</version>
</dependency>

Java-Server

@DubboService
public class DemoServiceImpl implements DemoService {

    @Override
    public String sayHello(String name) {
        return "Hello " + name;
    }
}

Server-application.yml

dubbo:
  application:
    name: dubbo-springboot-demo-provider
  protocol:
    name: tri
    port: 50052
    //添加fastjson的支持
    prefer-serialization: fastjson
  registry:
    address: nacos://${nacos.address:127.0.0.1}:8848

Java-Client

@Component
public class Task implements CommandLineRunner {
    @DubboReference
    private DemoService demoService;

    @Override
    public void run(String... args) throws Exception {
        String result = demoService.sayHello("world");
        System.out.println("Receive result ======> " + result);

        new Thread(()-> {
            while (true) {
                try {
                    Thread.sleep(1000);
                    System.out.println(new Date() + " Receive result ======> " + demoService.sayHello("world"));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                }
            }
        }).start();
    }
}

Client-application.yml

dubbo:
  application:
    name: dubbo-springboot-demo-consumer
  registry:
    address: nacos://${nacos.address:127.0.0.1}:8848

SpringCloud

同时本项目还拓展了HTTP接口可以当做一个WebServer框架,并且还支持了SpringCloud服务注册与发现,用户可以灵活的选择和切换需要暴露的协议,并且支持同时暴露。

这里我们使用spring-cloud-alibaba项目进行演示 https://github.com/alibaba/spring-cloud-alibaba

Rust的Server和Client端的代码无需改造就如上示例即可。 Java的Server和Client端的代码也无需改造。直接启动即可。

Server

Provider启动类 package com.alibaba.cloud.examples.ProviderApplication

//EchoController
@RestController
public class EchoController {
...
	@GetMapping("/divide")
	public String divide(@RequestParam Integer a, @RequestParam Integer b) {
		if (b == 0) {
			return String.valueOf(0);
		}
		else {
			return String.valueOf(a / b);
		}
	}
...
}

Client

Consumer启动类 package com.alibaba.cloud.examples.ConsumerApplication

//TestController
@RestController
public class TestController {
...
	@GetMapping("/divide-feign")
	public String divide(@RequestParam Integer a, @RequestParam Integer b) {
		return echoClient.divide(a, b);
	}
...
}

测试curl ( curl => SpringCloud => fusen-rust ) http://127.0.0.1:18083/divide-feign?a=1&b=2

2024-04-10T06:52:32.737307Z  INFO ThreadId(07) server: 33: res : a=1,b=2

测试curl ( curl => fusen-rust )

http://127.0.0.1:8081/divide?a=2&b=3

2024-04-10T06:54:26.436416Z  INFO ThreadId(512) server: 33: res : a=2,b=3

测试curl ( curl => fusen-rust )

curl --location --request POST 'http://127.0.0.1:8081/sayHelloV2-http'
--header 'Content-Type: application/json'
--header 'Connection: keep-alive'
--data-raw '{ "str" : "World" }'

2024-04-10T07:02:50.138057Z  INFO ThreadId(03) server: 26: res : ReqDto { str: "World" }

评论区

写评论
作者 kwsc98 2024-04-18 23:33

这两个项目都不是一个东西...我这个项目是一个微服务框架,包括了服务的注册与发现,Client端与Server端的RPC调用, actix-web只是一个WebService...而WebService只是这个项目的一个功能点而已

--
👇
github.com/shanliu/lsys: 要用在生产还是用 actix-web 吧。不做无谓的瞎折腾。

github.com/shanliu/lsys 2024-04-18 23:08

要用在生产还是用 actix-web 吧。不做无谓的瞎折腾。

作者 kwsc98 2024-04-16 10:17

你说放弃了Dubbo吧,我这个其实支持的是Dubbo3

--
👇
gorust21: 为啥支持dubbo?人家都放弃了,你还支持

gorust21 2024-04-16 08:42

为啥支持dubbo?人家都放弃了,你还支持

1 共 4 条评论, 1 页