RUST有毒,如何从零开始到接入微服务集群 第一章

前言

RUST:

  • 适合编程初学者学习、当前适合当团队的语言选型对象、优雅
  • 适合学习、适合准备、适合强迫症、适合
缺点
  • 1 上手困难,相对其他语言有较复杂的语法和理念,门槛比较高
  • 2 有很多独有表达式,可读性较差
  • 3 严格的语法限制,如作用域、生命周期等,学习成本高
  • 4 目前版本不统一,stable和nightly版本区别较大
  • 5 不好做语言迁移,生态还不完全
优点
  • 1 有毒,容易上瘾
  • 2 社区开发速度快,现在是个学习的好时候,目前,保持着每 6 周更新一次的节奏。Rust 发布的工具链包括了 stablebetanightly 三种不同版本。 nightly 是最激进的版本,包含了大量(可能不稳定)的新/高级特性。stable 版本目前可能还不支持一些高级特性。beta 介于两者之间。
  • 3 从语言层面就减少各种开销和数据竞争,更加安全
  • 4 性能

参考资料

官方中文网站
crates 库类搜索
简体中文文档
语法基础教程
RUST 特性分析 by austenliao
Rust中文社区
tokio文档
Rocket文档

必看语法

借用和引用
匹配
模式
生命周期
更多...

目录

  • 安装RUST
  • hello world
  • 使用第三方库
  • 测试socket stream
  • 搭建http服务
  • 数据库操作
  • 与golang的压测对比
  • 接入基于consul的grpc微服务集群

一 安装RUST

  • 下载
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  • 激活环境
source $HOME/.cargo/env
  • 检查是否安装成功
$ cargo --version
cargo 1.38.0 (23ef9a4ef 2019-08-20)

cargo 命令介绍

  • cargo build 可以构建项目
  • cargo run 可以运行项目
  • cargo test 可以测试项目
  • cargo doc 可以为项目构建文档
  • cargo publish 可以将库发布到 crates.io。

二 helloworld

$ cargo new myhello
  • 生成的文件结构
$ tree
.
├── Cargo.toml
└── src
    └── main.rs
//main.rs
fn main() {
    println!("Hello, world!");
}

//Cargo.toml
[package]
name = "myhello"
version = "0.1.0"
authors = ["root"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
  • 运行
$ cargo run
Compiling myhello v0.1.0 (/mnt/hgfs/winwork/rust/myhello)
error: linker `cc` not found
  |
  = note: No such file or directory (os error 2)

error: aborting due to previous error

error: Could not compile `myhello`.

To learn more, run the command again with --verbose.
  • 失败了,新装的虚拟机环境不够完全,注意最好换成aliyun的源再继续
$ sudo apt install build-essential
  • 再次运行,成功
$ cargo run
   Compiling myhello v0.1.0 (/mnt/hgfs/winwork/rust/myhello)
    Finished dev [unoptimized + debuginfo] target(s) in 0.54s
     Running `target/debug/myhello`
Hello, world!

三 简单使用第三方库

  • 参照官方示例,使用ferris-says库,用来画个say hi的小人
// main.rs
use ferris_says::say; // from the previous step
use std::io::{stdout, BufWriter};

fn main() {
    let stdout = stdout();
    let out = b"Hello fellow Rustaceans!";
    let width = 24;
    let mut writer = BufWriter::new(stdout.lock());
    say(out, width, &mut writer).unwrap();
}
# Cargo.toml中加入
[dependencies]
ferris-says = "0.1"
# 编译 后可在target目录中找到可执行文件
$ cargo build
# 或者直接运行
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 1.79s
     Running `target/debug/myhello`
----------------------------
| Hello fellow Rustaceans! |
----------------------------
              \
               \
                  _~^~^~_
              \) /  o o  \ (/
                '_   -   _'
                / '-----' \

四 测试socket stream

  • 当我们需要写功能的时候,可以从crates.io 可以搜索需要用到的库
image.png

注意:
Documentation 会指向官方文档网站
Repository 会指向github

  • tokio 异步编程框架是使用人数较多的框架,不仅是引用量和下载量都是最高的,而且是官方支持的项目。但是rust生态目前还不是很完善,因此很多项目都不稳定,从github中可以看到

NOTE: Tokio's master is currently undergoing heavy development. This branch and the alpha releases will see API breaking changes and there are currently significant performance regressions that still need to be fixed before the final release. Use the v0.1.x branch for stable releases.

  • 根据官方的start文档 修改Cargo.toml 和 main.rs
[dependencies]
tokio = "0.1"
extern crate tokio;

use tokio::io;
use tokio::net::TcpStream;
use tokio::prelude::*;

fn main() {
    // Parse the address of whatever server we're talking to
    let addr = "127.0.0.1:6142".parse().unwrap();
    let client = TcpStream::connect(&addr).and_then(|stream| {
        println!("created stream");
        // Process stream here.
        io::write_all(stream, "hello world\n").then(|result| {
            println!("wrote to stream; success={:?}", result.is_ok());
            Ok(())
        })
    }).map_err(|err| {
        // All tasks must have an `Error` type of `()`. This forces error
        // handling and helps avoid silencing failures.
        // In our example, we are only going to log the error to STDOUT.
        println!("connection error = {:?}", err);
    });

    println!("About to create the stream and write to it...");
    tokio::run(client);
    println!("Stream has been created and written to.");
}
  • 先用 nc 启动6142端口的监听进程, 然后运行cargo run 可以看到以下状态
$ nc -l -p 6142
hello world
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 3.90s
     Running `target/debug/myhello`
About to create the stream and write to it...
created stream
wrote to stream; success=true
Stream has been created and written to.

五 搭建一个http restful服务

  • 这里我们直接使用框架rocket,类似于node中的express, go里面的gin等。
  • 推荐先读rocket api文档
  • 注意 需要使用nightly版本
$ rustup default nightly
$ rustc --version
rustc 1.40.0-nightly (aa69777ea 2019-10-29)
新建项目
$ cargo new management
  • main.rs代码:
#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use] extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    "Hello, world!"
}

fn main() {
    rocket::ignite().mount("/", routes![index]).launch();
}
  • 运行
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 2m 28s                                                          │root@cowkeysu1:/mnt/hgfs/winwork/rust/Rocket# cd ..
     Running `target/debug/management`                                                                                  │root@cowkeysu1:/mnt/hgfs/winwork/rust# cd ..
 Configured for development.                                                                                          │root@cowkeysu1:/mnt/hgfs/winwork# mv^C
    => address: localhost                                                                                               │root@cowkeysu1:/mnt/hgfs/winwork# ls
    => port: 8000                                                                                                       │faf  go  go1.12.12.linux-amd64.tar.gz  ocr  rust  ziliao
    => log: normal                                                                                                      │root@cowkeysu1:/mnt/hgfs/winwork# cd rust/
    => workers: 2                                                                                                       │root@cowkeysu1:/mnt/hgfs/winwork/rust# s
    => secret key: generated                                                                                            │cd s: command not found
    => limits: forms = 32KiB                                                                                            │root@cowkeysu1:/mnt/hgfs/winwork/rust# ls
    => keep-alive: 5s                                                                                                   │hello  myrust  Rocket  rustover
    => tls: disabled                                                                                                    │root@cowkeysu1:/mnt/hgfs/winwork/rust# cd rustover/
  Mounting /:                                                                                                         │root@cowkeysu1:/mnt/hgfs/winwork/rust/rustover# ls
    => GET / (index)                                                                                                    │management  myhello
 Rocket has launched from http://localhost:8000
  • 调用测试
$ curl http://127.0.0.1:8000
hello,world!
  • 加入GET、POST的方法
    下面的代码只有不到50行,不过很容易出错,主要难点还是在rust语法以及Rocket框架的处理上
  • main.rs 代码:
#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use] 
extern crate rocket;
#[macro_use] 
extern crate rocket_contrib;
#[macro_use] 
extern crate serde;

use serde::{Serialize, Deserialize};
use rocket::response::status;
use rocket::response::{self,Responder,Response};
use std::io::Cursor;
use rocket::http::{Status, ContentType};
use rocket::request::Request;
use rocket_contrib::json::Json;
use serde_json::json;


#[derive(Serialize)]
struct User {
    id : usize,
    name : String,
    age : i32,
    updated : i64,
}

impl<'r> Responder<'r> for User {
    fn respond_to(self, _: &Request) -> response::Result<'r> {
        Response::build()
            .sized_body(Cursor::new(json!(self).to_string()))
            .header(ContentType::new("application", "json"))
            .ok()
    }
}

#[post("/user/")]
fn addUser(id: usize) -> status::Accepted {
    status::Accepted(Some(format!("id: '{}'", id)))
}

//fn getUser(id: usize) -> Json {
#[get("/user/")]
fn getUser(id: usize) -> User {
    User{
        id:id,
        name:"cowkeys".to_string(),
        age:27,
        updated:0
    }
}

fn main() {
    rocket::ignite().mount("/", routes![addUser,getUser]).launch();
}
  • 运行
$ Cargo run
 Configured for development.
    => address: 0.0.0.0
    => port: 8000
    => log: normal
    => workers: 2
    => secret key: generated
    => limits: forms = 32KiB
    => keep-alive: 5s
    => tls: disabled
  Mounting /:
    => POST /user/ (addUser)
    => GET /user/ (getUser)
 Rocket has launched from http://0.0.0.0:8000
  • 测试调用
// GET
curl http://localhost:8000/user/1
id: '1'
// POST
curl -X POST http://localhost:8000/user/1
{"age":19,"id":1,"name":"cowkeys","updated":0}
  • 控制台会出现:
GET /user/1:
    => Matched: GET /user/ (getUser)
    => Outcome: Success
    => Response succeeded.
GET /user/1:
    => Matched: GET /user/ (getUser)
    => Outcome: Success
    => Response succeeded.
  • 到此,http服务完成。
总结

本文介绍了RUST的基础入门,如何开始使用rust。下篇会从接入数据库开始,一直到使用grpc接入consul服务发现。

你可能感兴趣的:(RUST有毒,如何从零开始到接入微服务集群 第一章)