Rust企业落地探索

前言

最近我在微博转发了亚马逊对Rust和Go语言的对比。亚马逊发文力捧 Rust ,Go 技术负责人:别“拉踩”我们https://weibo.com/2150275531/LlkxkvTrl

AWS的文章对Rust的推崇溢于言表。引起了业内的震动。再次把cloud native, green programming language 这些问题推到舆论风口。那我们就多关注一下Rust

Rust学习并不是很容易。如果大家学习过C++的语言特性,并且深入了解C++的标准库auto pointer和Boost扩展库里的smart pointer的话,我觉得大家会比较容易了解Rust的强类型和内存安全的一些考虑。这部分大家可以比较学习,横向比较确实是一种提高自己的方法。

但是真正用Rust做一些企业真实的应用。我觉得只是学习语言特性是不足够的。底层库或者程序框架的开发者对语言特性的要求比较高。而我们要跨越谈论语言特性,和其他语言之间做比较的时候。我们还是要通过语言的生态,企业开发的支持来做一些探索。这样,才能真正落地,应用到生产环境里。

我们探索的脚步不能停止。我将对一些比较重要的问题展开讨论。

入门资料

在学习Rust的时候,我们再语言入门的时候一定有很多的资料。我可以推荐大家看一些基本的资料。

Rust学习资源和路线_weixin_34174132的博客-CSDN博客Rust学习资源和路线来源 https://rust-lang-cn.org/article/23学习资源The Rust Programming Language堪称Rust的"The Book",是目前最权威的Rust系统教程,入门必读。Rust by Example实例化的讲解方法,通过一个个可实际运行的例子去介绍Rust的特性和用法,有的时候,代码是最好的老师。Frequen...https://blog.csdn.net/weixin_34174132/article/details/85975606?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164826295516780261980079%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164826295516780261980079&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-85975606.142%5Ev5%5Epc_search_result_cache,143%5Ev6%5Econtrol&utm_term=rust%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF&spm=1018.2226.3001.4187

Rust学习资料汇总_chirpyli的博客-CSDN博客_rust学习列举一些学习Rust的好资料,方便平常学习与查阅。大部分文档在官网Grow with Rust一节都有列出,另一部分是平常学习时涉及到的文档资料。The Rust Programming Language这本书当然是要第一本阅读的了,入门首选。Rust对单元测试的支持是非常友好的,可参考Writing Automated Tests这一章。Rust by Example通过代码示例...https://blog.csdn.net/s_lisheng/article/details/105778760?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164826295516780261980079%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164826295516780261980079&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-5-105778760.142%5Ev5%5Epc_search_result_cache,143%5Ev6%5Econtrol&utm_term=rust%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF&spm=1018.2226.3001.4187

多线程

在官方的教程文档中,我们可以看到multi-thread的用处和如何使用线程池。官方文档示例里给出了跟好的例子。

当然如果我们需要一个有生产强度的并行库。我们可以使用Rayon, tokio_threadpool等等。

Rayon

GitHub - rayon-rs/rayon: Rayon: A data parallelism library for RustRayon: A data parallelism library for Rust. Contribute to rayon-rs/rayon development by creating an account on GitHub.https://github.com/rayon-rs/rayon

tokio_threadpool

GitHub - gatoWololo/tokio-threadpool-0.1.18: Modified version of tokio-threadpool for Servo-rr-channel compatibility.Modified version of tokio-threadpool for Servo-rr-channel compatibility. - GitHub - gatoWololo/tokio-threadpool-0.1.18: Modified version of tokio-threadpool for Servo-rr-channel compatibility.https://github.com/gatoWololo/tokio-threadpool-0.1.18

异步处理框架

Rust里最大名鼎鼎的一部框架就是 Tokio。这个框架是很多框架的基础。框架本身的文档还是非常的详尽。而且在Github项目代码目录,有非常详细的实例程序。我们可以在 examples 这个位置找到。我是非常推崇直接通过例子来学习框架。

对于异步处理框架,我们还是需要仔细了解异步框架的原理。大家可以看一下 Async in Depth 来更深入的了解Async的实现原理。这对异步系统的理解和调优相关的任务会有比较好的帮助。

Tonic

Tokio 本身提供了一个 gRPC 的实现 Tonic。用Tonic开发其实也是比较容易的。我认为gRPC本身的效率还是非常高的。

我们可以参照这篇文章实现一个基本的三层应用后端。How to use gRPC with Rust Tonic and Postgres database with examples - DEV CommunityIn this post, we will learn how to use Rust Tonic gRPC crate and implement CRUD with Postgresql... Tagged with rust, tonic, postgres, grpc.https://dev.to/steadylearner/how-to-use-grpc-with-rust-tonic-and-postgres-database-with-examples-3dl7

或者使用tonic + sqlx来实现数据库连接也可以。 

hhttps://github.com/rezmuh/todo-tonic-sqlx-refinery-barrelhttps://github.com/rezmuh/todo-tonic-sqlx-refinery-barrelhttps://github.com/rezmuh/todo-tonic-sqlx-refinery-barrel当然Tonic本身的examples也可以给大家大的帮助。

Tracing

Tracing提供了一个比较统一日志体系。他的重要性和java里的log4j一样。所以这也是基本的企业应用的基础件。日志的重要性大家都知道吧?

数据库访问

数据库的重要性肯定是不言而喻的。Rust的数据库支持有哪些呢?下面这个文章给了我们一个比较全面的介绍。

11 database drivers and ORMs for Rust that are ready for production - LogRocket Bloghttps://blog.logrocket.com/11-database-drivers-and-orms-for-rust-that-are-ready-for-production/

Diesel

GitHub - diesel-rs/diesel: A safe, extensible ORM and Query Builder for RustA safe, extensible ORM and Query Builder for Rust. Contribute to diesel-rs/diesel development by creating an account on GitHub.https://github.com/diesel-rs/diesel

SQLX

SQLX是本身是一个基于Tokio的异步框架。所以应该基本上可以其他的异步框架进行使用。

GitHub - launchbadge/sqlx: The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, SQLite, and MSSQL. The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, SQLite, and MSSQL. - GitHub - launchbadge/sqlx: The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, SQLite, and MSSQL.https://github.com/launchbadge/sqlx

SQLX的好处就是比较纯粹,我们还是需要写SQL来完成工作。但是所有的语法检查,sql准备都在编译期做好了。在执行的时候效率非常高。

RBatis

GitHub - rbatis/rbatis: Rust High Performance compile-time ORM(RBSON based)Rust High Performance compile-time ORM(RBSON based) - GitHub - rbatis/rbatis: Rust High Performance compile-time ORM(RBSON based)https://github.com/rbatis/rbatis/这个基本上就是一个MyBatis的 Rust版本。具体例子可以看官方的 examples。这样的话从 java 转型过来的程序员就非常适应这种数据库访问方式。

比较有意思的是RBatis的底层就是使用了sqlx,所以相对来说给sqlx添加了一个ORM层。RBatis所有的sql语法检查准备也都是在编译期完成。保持性能方面的优势。

微服务框架

现在大多数的后端应用还是在使用无状态的微服务框架,现在这些框架已经基本上比较成熟。所以在本人的gitee里面fork了并且维护了一个国外的实现。

kanban: 由于对spring框架和java技术栈约来约笨重。我们在承担不必要的成本。所以该项目开始讨论其他的方案。特别是针对Rest API实现的方案。https://gitee.com/raymondshen/kanban

这里面以快捷开发的看板应用为例,演示了如何使用不同的框架。和Rust有关的是如下两种。

同步框架: Diesel + Rocket

  • Directory: diesel-rocket
  • Nickname: DR
  • Connection pool: r2d2
  • SQL executor: Diesel
  • HTTP routing: Rocket
  • Compiled with: Rust v1.53 (Nightly)

异步框架: sqlx + actix-web

  • Directory: sqlx-actix-web
  • Nickname: SA
  • Connection pool: sqlx
  • SQL executor: sqlx
  • HTTP Routing: actix-web
  • Compiled with: Rust v1.53 (Nightly)

当然我非常推荐大家仔细阅读一下原作者的说明。

rust-blog/restful-api-in-sync-and-async-rust.md at master · pretzelhammer/rust-blog · GitHubEducational blog posts for Rust beginners. Contribute to pretzelhammer/rust-blog development by creating an account on GitHub.https://github.com/pretzelhammer/rust-blog/blob/master/posts/restful-api-in-sync-and-async-rust.md

他深入的分析了这些框架之间的异同。得到了一个并不让人惊讶的结论,异步框架吞吐量占有而同步系统延迟占优。

这里我在sqlx-actix-web的基础上添加了i18n的支持。如果您面临的是国际化的后端应用。不妨可以看一下。

如果大家希望快速有生产力的话,我建议大家做出一定的选择,直接跳过复杂的Rust语言特性。直接使用框架写后端应用。这样学习的话会表有成果,也能鼓励人不断在实践中进步。这比一下子掉到语言特性的坑里要好多了。

另一个比较全面的例子是在这里,而且这个例子对数据程序的架构给了一定的示范作用。非常值得学习。

GitHub - jamesjmeyer210/actix_sqlx_mysql_user_crud: A user crud written in Rust, designed to connect to a MySQL database with full integration test coverage.A user crud written in Rust, designed to connect to a MySQL database with full integration test coverage. - GitHub - jamesjmeyer210/actix_sqlx_mysql_user_crud: A user crud written in Rust, designed to connect to a MySQL database with full integration test coverage.https://github.com/jamesjmeyer210/actix_sqlx_mysql_user_crud

比较重要的一点,是这个例子对数据库链接进行了多线程的封装。这样避免了之前案例中的问题。请关注下面 AppState 的初始化方法。这里也用了 Arc::new 来创建数据库连接的引用计数。

use actix_web::{web, App, HttpServer};
use sqlx_user_crud::config::Config;
use sqlx_user_crud::dao::Database;
use sqlx_user_crud::{controller, AppState};
use std::sync::{Arc, Mutex};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    println!("=== SQLX User CRUD ===");

    // Read in the configuration file.
    // In small projects this can be a local configuration, but in more sophisticated systems, it is
    // best practice to keep the configuration file on a remote server where it can be retrieved
    // with an http request.
    let config_file: &'static str = "config.json";
    let config = Config::from_file(config_file);
    println!("Using configuration file from {0}", config_file);

    // Connect to the database
    let db_context = Database::new(&config.get_database_url()).await;
    println!("Connected to database: {0}", config.get_database_url());

    // Instantiate the app_state. This application state will be cloned for each Actix thread but
    // the Arc of the DbContext will be reused in each Actix thread.
    let app_state = web::Data::new(AppState {
        connections: Mutex::new(0),
        context: Arc::new(db_context),
    });

    // Start the web application.
    // We'll need to transfer ownership of the AppState to the HttpServer via the `move`.
    // Then we can instantiate our controllers.
    let app = HttpServer::new(move || {
        App::new()
            .app_data(app_state.clone())
            .configure(controller::init_index_controller)
            .configure(controller::init_user_controller)
            .configure(controller::init_group_controller)
    })
    .bind(config.get_app_url())?;
    println!("Listening on: {0}", config.get_app_url());

    app.run().await
}

如果大家感兴趣,也可以看一下这个例子里有关 Module, Dao, Controler 的分层考虑。会比较有启发。 在下面研发自动化的时候我们还会在 sql_reverse 这一节进行更详细的说明。

RBatis + Actix-web

rbatis和Actix-web配合的例子如下:

#![allow(unused_must_use)]
#[macro_use]
extern crate rbatis;

use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use std::sync::Arc;

use rbatis::crud::CRUD;
use rbatis::rbatis::Rbatis;

#[crud_table]
#[derive(Clone, Debug)]
pub struct BizActivity {
    pub id: Option,
    pub name: Option,
    pub pc_link: Option,
    pub h5_link: Option,
    pub pc_banner_img: Option,
    pub h5_banner_img: Option,
    pub sort: Option,
    pub status: Option,
    pub remark: Option,
    pub create_time: Option,
    pub version: Option,
    pub delete_flag: Option,
}

impl Default for BizActivity {
    fn default() -> Self {
        BizActivity {
            id: None,
            name: None,
            pc_link: None,
            h5_link: None,
            pc_banner_img: None,
            h5_banner_img: None,
            sort: None,
            status: None,
            remark: None,
            create_time: None,
            version: None,
            delete_flag: None,
        }
    }
}

async fn index(rb: web::Data>) -> impl Responder {
    let v = rb.fetch_list::().await.unwrap_or_default();
    HttpResponse::Ok()
        .insert_header(("Content-Type", "text/json;charset=UTF-8"))
        .json(v)
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    //log
    fast_log::init(fast_log::config::Config::new().console());
    //init rbatis . also you can use  pub static RB:Lazy = Lazy::new(||Rbatis::new()); replace this
    log::info!("linking database...");
    let rb = example::init_sqlite_path("").await;
    let rb = Arc::new(rb);
    log::info!("linking database successful!");

    log::info!("start on http://127.0.0.1:8080");
    //router
    HttpServer::new(move || {
        App::new()
            //add into actix-web data
            .app_data(web::Data::new(rb.to_owned()))
            .route("/", web::get().to(index))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

这里BizActivity本身也可以通过sql_reverse 自动生成。请查看下面的相应章节。

Actor模式

Actor模式可以构建比较复杂的CQRS模式的应用。并且完成无锁机制的同步。最典型的框架是Erlang,Akka等虚拟机系统。在Rust语言上实现Actor模式,对我们来讲还是非常有意思的。

我推荐大家深度关注Actix。早在2020年,Rust语言也涌现出很多不同的Actor模式的实现。但是尘归尘,土归土,现在还在积极维护的看起来只有Actix了。如果有其他的服务实现,我觉得大家也可以留言推荐给我。我对此的看法是Actor模式非常适合大型企业后端应用,特别是有状态的应用。而Actix现在也助推actix-web框架,主要还是考虑现在微服务框架入门比较容易。而大型企业应用后端还是JVM的天下。Actix-actor在一定程度上是单机系统,只是考remote特性手工组建集群相对还是对架构师要求太高。但是,这不影响我对Actor模式的热情。还是会介绍一下。

有效利用使用多核CPU

在 Arbix 的实现离,Arbiter是一个调度单元。为了能够演示多个Arbiter的使用,下面的代码段还是非常有用的。

extern crate actix;
use actix::prelude::*;

struct Fibonacci(pub u32);


struct SomeActor;

impl Actor for SomeActor {
    type Context = Context;
}

impl Message for Fibonacci{
    type Result = Result;
}

impl Handler for SomeActor {
    type Result = Result;

    fn handle(&mut self, msg: Fibonacci, context: &mut Self::Context) -> Self::Result {
        println!("working on fib({})", msg.0);
    let mut sum=0;
    if msg.0 == 0 {
        Err(())
    } else if msg.0 == 1 {
        Ok(1)
    } else {

        for j in 1..1000000 {
            let mut i = 0;
            sum = 0;
            let mut last = 0;
            let mut curr = 1;
            while i < msg.0 - 1 {
                sum = last + curr;
                last = curr;
                curr = sum;
                i += 1;
            }
        }
        Ok(sum)
    }
}
}

fn main() {
let sys = System::new();

let a1 = Arbiter::new();
let a2 = Arbiter::new();
let a3 = Arbiter::new();

let execution1 = async {
    println!("exec 1 created");
    let sa = SomeActor {}.start();
    for n in 2..80 {
        sa.do_send(Fibonacci(n));
    }
};

let execution2 = async {
    println!("exec 2 created");
    let sa = SomeActor {}.start();
    for n in 2..80 {
        sa.do_send(Fibonacci(n));
    }
};

let execution3 = async {
    println!("exec 3 created");
    let sa = SomeActor {}.start();
    for n in 2..80 {
        sa.do_send(Fibonacci(n));
    }
};


a1.spawn(execution1);
a2.spawn(execution2);
a3.spawn(execution3);

sys.run();
}

websocket-chat-server

examples/websockets/chat-broker at master · actix/examples · GitHubCommunity showcase and examples of Actix ecosystem usage. - examples/websockets/chat-broker at master · actix/exampleshttps://github.com/actix/examples/tree/master/websockets/chat-broker这个例子之所以重要,主要是他是Actix框架位数不多的接近实战的官方示例。而这个例子很好的演示了 WebSocket Session, Actor, Arbiter, SystemService, Supervied之间的配合。堪称难能可贵。这也体现了Artix框架设计的精妙。

下面是我们节选一下main.rs里的代码。

use actix_files::{Files, NamedFile};
use actix_web::{middleware::Logger, web, App, Error, HttpRequest, HttpServer, Responder};
use actix_web_actors::ws;

mod message;
mod server;
mod session;

use session::WsChatSession;

async fn index() -> impl Responder {
    NamedFile::open_async("./static/index.html").await.unwrap()
}

async fn chat_ws(req: HttpRequest, stream: web::Payload) -> Result {
    ws::start(WsChatSession::default(), &req, stream)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));

    log::info!("starting HTTP server at http://localhost:8080");

    HttpServer::new(move || {
        App::new()
            .service(web::resource("/").to(index))
            .service(web::resource("/ws").to(chat_ws))
            .service(Files::new("/static", "./static"))
            .wrap(Logger::default())
    })
    .workers(2)
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

大家可以注意代码中 workers(2) 这个调用。由于Session本身就是Actor,所以,多少个 worker 也就启动了多少个 Arbiter。

通过lldb我们可以看到这两个Arbiter的存在。

chat-broker % lldb ../../target/debug/server 
(lldb) target create "../../target/debug/server"
Current executable set to '/Users/raymond/src/rust/examples/target/debug/server' (arm64).
(lldb) run
Process 5532 launched: '/Users/raymond/src/rust/examples/target/debug/server' (arm64)
[2022-03-27T06:36:51Z INFO  server] starting HTTP server at http://localhost:8080
[2022-03-27T06:36:51Z INFO  actix_server::builder] Starting 2 workers
[2022-03-27T06:36:51Z INFO  actix_server::server] Actix runtime found; starting in Actix runtime
Process 5532 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x00000001af84ac40 libsystem_kernel.dylib`kevent + 8
libsystem_kernel.dylib`kevent:
->  0x1af84ac40 <+8>:  b.lo   0x1af84ac60               ; <+40>
    0x1af84ac44 <+12>: pacibsp 
    0x1af84ac48 <+16>: stp    x29, x30, [sp, #-0x10]!
    0x1af84ac4c <+20>: mov    x29, sp
Target 0: (server) stopped.
(lldb) thread list
Process 5532 stopped
* thread #1: tid = 0xfd860a, 0x00000001af84ac40 libsystem_kernel.dylib`kevent + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  thread #2: tid = 0xfd864f, 0x00000001af84ac40 libsystem_kernel.dylib`kevent + 8, name = 'actix-rt|system:0|arbiter:0'
  thread #3: tid = 0xfd8650, 0x00000001af84ac40 libsystem_kernel.dylib`kevent + 8, name = 'actix-rt|system:0|arbiter:1'
  thread #4: tid = 0xfd8651, 0x00000001af84ac40 libsystem_kernel.dylib`kevent + 8, name = 'actix-server acceptor'
(lldb) 

就此,我们看到了一些Actix的一些内部机制。但是最好的学习方法还是源代码。这里不再详述。

使用websocket-chat-server,进行扩充,控制好线程模型,我们很容易得到一个效率还不错的行情分发系统。这以后我们会尝试,并且和go语言的实现进行对比。 

actix-web-prometheus

GitHub - atomix-team/actix-web-prometheus: Prometheus middleware for actix webPrometheus middleware for actix web. Contribute to atomix-team/actix-web-prometheus development by creating an account on GitHub.https://github.com/atomix-team/actix-web-prometheus这个项目是用了最为流行的 tikv/rust-prometheus进行了针对Actix的适配。很值得尝试。使用方法确实也不困难。本身项目代码也不多,有问题自己动手改吧。哈哈

use std::collections::HashMap;
use actix_web::{web, App, HttpResponse, HttpServer};
use actix_web_prometheus::{PrometheusMetrics, PrometheusMetricsBuilder};
fn health() -> HttpResponse {
    HttpResponse::Ok().finish()
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let mut labels = HashMap::new();
    labels.insert("label1".to_string(), "value1".to_string());
    let prometheus = PrometheusMetricsBuilder::new("api")
        .endpoint("/metrics")
        .const_labels(labels)
        .build()
        .unwrap();
        HttpServer::new(move || {
            App::new()
                .wrap(prometheus.clone())
                .service(web::resource("/health").to(health))
        })
        .bind("127.0.0.1:8080")?
        .run()
        .await?;
    Ok(())
}

 研发自动化

sql_reverse

对于Sqlx,其实没有给出比较完善的ORM能力,所以我们使用sql_reverse来帮助我们。大家可以找到这个项目。他非常新。

GitHub - ptechen/sql_reversehttps://github.com/ptechen/sql_reverse我们为sqlx的model代码生成写了专门的template:

use serde::{Deserialize, Serialize};
use sqlx::mysql::MySqlRow;
use sqlx::{FromRow, Row};

{% if table.comment -%}
	/// {{ table.comment }}
{% endif -%}
{% for index in table.index_key -%}
    /// 索引:{{index}}
{% endfor -%}


#[derive(Serialize, Deserialize, PartialEq, Clone)]
pub struct {{ table.struct_name }} {
{%- for v in table.fields %}
	{% if v.comment -%}
	    /// {{ v.comment }} {% if v.database_field_type %} field_type: {{ v.database_field_type }}{% endif %}{% if v.default %} default: {{ v.default }}{% endif %} {% if v.default == '' %} default: ''{% endif %}
	{% endif -%}
	{% if v.is_null == 1 -%}
    	pub {{ v.field_name }}: Option<{{ v.field_type }}>,
    {%- else -%}
        {% if v.field_type == 'NaiveDateTime' -%}
            pub {{ v.field_name }}: Option<{{ v.field_type }}>,
        {%- else -%}
            pub {{ v.field_name }}: {{ v.field_type }},
        {%- endif -%}
    {%- endif -%}
{%- endfor %}
}

impl<'c> FromRow<'c, MySqlRow<'c>> for {{ table.struct_name }} {
    fn from_row(row: &MySqlRow) -> Result {
        Ok({{ table.struct_name }} {
{%- for v in table.fields %}
            {{ v.field_name }}: row.get( {{ loop.index0 }} ),
{%- endfor %}        
        })
    }
}

大家可以一试。

Tera

这是一个比较有效的模版引擎。可以帮助我们做代码生成。也是sql_reverse的后端引擎。

GitHub - Keats/tera: A template engine for Rust based on Jinja2/DjangoA template engine for Rust based on Jinja2/Django. Contribute to Keats/tera development by creating an account on GitHub.https://github.com/Keats/tera

audit

rust项目的代码安全审计可以通过 cargo audit 进行审计。这里是公开的rust库的安全建议列库。这个建议库还是得到了很好的维护。

GitHub - rustsec/advisory-db: Security advisory database for Rust crates published through crates.ioSecurity advisory database for Rust crates published through crates.io - GitHub - rustsec/advisory-db: Security advisory database for Rust crates published through crates.iohttps://github.com/RustSec/advisory-db

如何安装和使用 cargo audit,可以参考这个文档:

rustsec/cargo-audit at main · rustsec/rustsec · GitHub

下面是我们针对actix-net进行审计的结果。发现了一个已经不被维护的库。

~/rust/actix-net
cargo audit
    Fetching advisory database from `https://github.com/RustSec/advisory-db.git`
      Loaded 421 security advisories (from /Users/user1/.cargo/advisory-db)
    Updating crates.io index
    Scanning Cargo.lock for vulnerabilities (214 crate dependencies)
Crate:     serde_cbor
Version:   0.11.2
Warning:   unmaintained
Title:     serde_cbor is unmaintained
Date:      2021-08-15
ID:        RUSTSEC-2021-0127
URL:       https://rustsec.org/advisories/RUSTSEC-2021-0127
Dependency tree:
serde_cbor 0.11.2
└── criterion 0.3.5
    └── actix-codec 0.5.1
        ├── actix-tls 3.0.4
        └── actix-server 2.1.1
            └── actix-tls 3.0.4

warning: 1 allowed warning found

前端相关开发

Rust不仅能够在后端开发中得到大量应用。还可以在前端开发中使用。当前我们的架构基本上是这么来做的。

Rust企业落地探索_第1张图片

 如果我们需要通过安装程序发布APP, 那外层,我们可以使用Tauri作为对操作系统适配的层。同时Tauri也提供各个不同操作系统安装包的制作。当然这个层具有一定跨平台的能力。Tauri也有相应的框架实现一些本地方法有WebBrowser调用。当前Tauri支持桌面版本的开发,也逐步会支持移动端开发。如果Tauri支持移动端,那它的使用场景就更加丰富了。

Tauri是一个基于Rust开发的项目。由于Rust本身的特性,Tauri的执行效率非常高,并且安装包非常小。

Build smaller, faster, and more secure desktop applications with a web frontend | Tauri AppsTauri is a framework for building tiny, blazing fast binaries for all major desktop platforms. Developers can integrate any front-end framework that compiles to HTML, JS and CSS for building their user interface.https://tauri.app/

而在WebBrowser里面,主要还是使用JS进行UI的开发。开发基本上就是按照Web开发的模式。实际上就是Tauri使用WebPack来在本地执行一个Http服务器,而浏览器加载本地站点服务。而对Tauri实现的扩充本地方法,JS会做好包装。

WebAssembly实际上是可以在WebPack中进行打包发布的。WebAssembly不仅支持Rust,还支持很多主流语言。这里我们偏重Rust。当然Web Assembly 并不只是用在当前的场景。还可以用在大多数的Web开发场景里。对我们来讲,使用Web Assembly的主要优势就是在一些机密的算法特别是加密的方法中,编译成二进制代码发布,可以保护我们的算法不被反向工程而被破译和窃取。

这里有很多资料帮助我们使用Rust来进行 WebAssembly开发:

WebAssembly - Rust Programming Language A language empowering everyone to build reliable and efficient software.https://www.rust-lang.org/what/wasm

集群,Raft,Gossip和其他

选择使用Raft的同学,在很大程度上都会考虑性能要求比较高的关键应用。而关键应用除了对性能要求比较高以外,还会考虑稳定性。通过集群的配置提高可用性是一个非常关键的技术。所以,我们会对集群进行进一步的讨论探索。

Actix集群

这是一个实验项目,我们暂时还没有深入研究。但是如果真的能达到Akka集群的水平,我们还是非常期待的。为了这个理想,大家也去给人点个星星,鼓励一下呗。

GitHub - pengwin/actix-raft-clusterContribute to pengwin/actix-raft-cluster development by creating an account on GitHub.https://github.com/pengwin/actix-raft-cluster

另外一个实验项目是 actix_telepathy。作者 Phillip Wenig 是Hasso Plattner Institute的软件系统专业的博士生。有问题可以向他咨询。祝愿这个项目越来越好。这样我们就有基于Rust的Actor集群可用了。

actix_telepathy - RustActix-Telepathy is an extension to Actix that enables remote messaging and clustering support.https://docs.rs/actix-telepathy/latest/actix_telepathy/这里有一个例子可以知道项目如何运作。 

https://github.com/wenig/telepathy-examples

Raft

这篇文章我们叙述了如何使用Raft来实现高可用的高性能撮合引擎。有兴趣的架构设计师,软件设计师同学我们可以一起探讨。原子多播是撮合引擎的正解,当前国际上比较有名的金融交易所都是延续这个设计方法。我们有幸通过开源项目低成本实现源自多播的撮合引擎,也说明开源项目的不断发展。

Raft in Rust (原子多播+撮合引擎)_Raymond-Shen的博客-CSDN博客

 

参考资料:

https://speakerdeck.com/lukemathwalker/writing-enterprise-software-a-rust-experiment

rust-blog/restful-api-in-sync-and-async-rust.md at master · pretzelhammer/rust-blog · GitHub

你可能感兴趣的:(rust,rust)