序言:Rust語言簡介html
參與過C/C++大型項目的同窗可能都經歷過由於Null Pointer、Memory Leak等問題「被」 加班了不知道多少個晚上。別沮喪,你不是一我的,Mozilla Firefox的開發者們一樣經歷過這個問題。瀏覽器能夠說是咱們平常使用最爲頻繁的軟件了,目前主流的瀏覽器主要有Google Chrome、Internet Explorer、Mozilla Firefox。爲了提高用戶體驗,Mozilla就已經啓動了多線程渲染的計劃。然而,面對大型的C/C++工程,Mozilla的開發者們也堅持不住了。此時,Rust進入了開發者的眼中,與C語言ABI兼容、多編程範式支持、無GC及獨特的全部權系統,使得Mozilla與Rust語言一拍即合,並迅速啓動了 Mozilla 的下一代瀏覽器引擎項目:servo,到目前爲止(2018年8 月),servo已經成爲了除Rust編譯器自身外,社區中最大的Rust項目。servo目前已經部 分應用在Firefox 57以後的版本中。git
Rust語言的設計目標是安全、高效、併發以及實用性。Rust 從必定程度上解決了C++的以 下痛點:github
1容器/數組越界訪問;web
2動態內存分配的泄露與double free問題;編程
3難以對依賴進行管理。json
其中前兩點在C/C++項目中是最容易引起Bug以及安全問題的緣由,依靠人來對這些問題進行檢查每每不是最佳的解決方案。Rust經過其獨特的全部權系統,簡化所研究的對象,使得一些隱晦的問題在編譯期間便暴露出來。任何事情都是有兩面性的,因爲嚴格的編譯期檢查以及工程實現上的取捨,Rust在必定程度上犧牲了編譯速度以及靈活性,對「靈活性」的捨棄並不表明Rust語言的表現力降低,只是咱們在編寫Rust程序時,可能須要改變一下以往的思路。後端
在Rust圈子中,有一句調侃:「C++是調試的時候想撞牆,而Rust是編譯的時候想撞牆」。接下來咱們將經過一個簡單的例子來創建Rust中全部權系統的一個基本印象。api
核心概念:全部權系統數組
Rust 的全部權系統包括三個核心概念:全部權、借用以及生命週期。咱們首先來經過一個 簡單的例子來創建對全部權以及生命週期的直觀概念。瀏覽器
#[derive(Debug)]
struct Foo;
fn main() {
let foo = Foo; // Note: Foo not implement Copy trait
let bar = foo;
println!("{:?}", bar);
// println!("{:?}", foo);
}
首先建立了一個Foo類型的變量foo,而後咱們執行let bar = foo;,而後咱們嘗試輸出這兩個變量的值,若是咱們將第9行的註釋去掉,程序將沒法經過編譯,這是由於在 Rust中,對於沒有實現Copy trait的類型,若是咱們將一個綁定賦給另外一個綁定,默認使用的是move語義,也即對於任意給定的資源,當且僅當有一個變量綁定與之對應。
想要進一步學習Rust的小哥哥小姐姐,能夠參考Rust Learning(https://github.com/ctjhoa/rust-learning)
使用Rust進行HTTP Web後端應用開發
在Rust生態中進行HTTP Web後端應用開發目前主要依賴兩個基礎庫:http 以及hyper,其中 http 提供HTTP標準相關的基礎類型,如Request<T> 、Response<T>以及StatusCode和經常使用的Header等;hyper的定位是一個高效、準確的 HTTP底層庫,它封裝了HTTP的報文解析、報文編碼處理、鏈接控制等內容,對於用戶而言只須要實現一個相似於Fn(Request) -> Response的映射,就能夠完成HTTP Web服務端的開發。
基於http以及hyper,社區中還有不少用於Web應用開發的框架,經常使用的有:
➤rocket
➤iron
➤actix-web
➤tower-web
值得一提的是上週剛發佈的tower-web,由於這是官方net團隊2018年工做計劃的一部分, 這個庫在將來會爲Rust生態提供一個靈活、高效、易於使用的Web開發框架。那麼事不宜遲, 咱們經過實戰演練來一睹爲快。
在本月月底,tower-web將會集成到warp項目中,成爲warp框架的一部分,開發的重心將會轉移到warp上。
實戰演練
登陸華爲雲,並建立彈性雲服務器做爲咱們的後端應用服務器:
實戰中使用的系統版本爲Ubuntu 16.04,若是選擇不一樣的系統須要根據狀況調整命令。
安裝相關的工具鏈
apt update && apt install build-essential
# 安裝Rust工具鏈
curl https://sh.rustup.rs -sSf | sh
這一步結束後,咱們就能夠開始編寫咱們的應用服務了。
編寫後端Web應用
此次分享咱們來構建一個RESTful中文分詞API,首先咱們來建立一個Rust工程 cargo new --bin chinese_segmentation
接下來在Cargo.toml中添加相關
[dependencies]
tower-web = "0.2"
# Jieba Chinese Work Segmentation
jieba-rs = "0.2"
# logging utils
log = "0.4.0"
env_logger = "0.5.12"
# Serializing responses, deserializing requests
serde = "1.0.70"
而後是咱們的main.rs,與其餘語言同樣,在文件開始的部分引入外部依賴以及相關聲明:
extern crate jieba_rs;
#[macro_use]
extern crate tower_web;
#[macro_use]
extern crate log;
extern crate env_logger;
use std::iter::FromIterator;
use std::collections::HashSet;
use jieba_rs::Jieba;
use tower_web::ServiceBuilder;
接下來咱們定義咱們的服務資源ChineseTokenizer:
#[derive(Debug)]
struct ChineseTokenizer {
inner: Jieba,
}
impl ChineseTokenizer {
pub fn new() -> ChineseTokenizer {
ChineseTokenizer { inner: Jieba::new() }
}
// 對傳入的字符串進行分詞,並返回一個字符串向量
pub fn cut(&self, text: &String) -> Vec<String> {
let words = self.inner.cut(&text, true)
.into_iter()
.map(|word| word.to_owned())
.collect::<HashSet<String>>();
let mut words = Vec::from_iter(words.into_iter());
// 因爲使用HashSet進行去重會引入不肯定性,
// 所以對結果進行重排,使輸出的結果有序。
words.sort();
words
}
}
定義了咱們的服務資源後,咱們來定義輸入Web API的輸入輸出類型:
#[derive(Debug, Extract)]
struct TokenizeRequest {
text: String
}
#[derive(Debug, Response)]
#[web(status = "200")] // 當 handler 返回 Ok(xx) 時,返回 200 狀態碼
struct TokenizeResponse {
words: Vec<String>,
}
到目前爲止,咱們已經有了咱們的服務資源,輸入輸出類型,接下來就到咱們的重頭戲了, Web 部分的實現,別擔憂,由於真的很簡單。
impl_web! {
impl ChineseTokenizer {
#[post("/tokenize")]
#[content_type("application/json")]
fn tokenize(&self, body: TokenizeRequest) -> Reqult<TokenizeResponse, ()> {
Ok(TokenizeResponse {
words: self.cut(&body.text),
})
}
}
}
最後是咱們的main函數:
fn main() {
// 初始化Logger
env_logger::init();
let addr = "0.0.0.0:8081".parse().expect("invalid address");
info!("listening on http://{}", addr);
ServiceBuilder::new()
.resource(ChineseTokenizer::new()) // 註冊咱們的服務資源
.run(&addr) // 讓咱們的服務跑起來
.unwrap();
}
如今,咱們經過命令RUST_LOG=chinese_segmentation=info cargo run --release來檢驗 一下咱們的成果了。服務在本地跑起來以後,咱們能夠經過命令 curl -H "Content-Type: application/json" -X POST -d '{"text":"中間件小哥"}' <url> 來測試一下咱們的接口。
本地測試經過以後,就須要着手開始部署了,咱們檢查一下彈性雲服務器的安全組的入方向 是否放開8081端口。
API 部署
API 網關集成了監控、流控、負載均衡等一系列功能,爲開發者提供高性能、高可用的API 託管服務,在本次實踐中,咱們將咱們的API部署在API網關中。
一、登陸華爲雲API網關服務,選擇「新建API」
二、填寫API的基本信息。
在本次實驗中,選擇無認證。
三、定義API請求。
請求路徑填爲 /segment,方法爲 POST。
四、定義後端服務。
請求方式設置爲POST,在VPC通道這一項中,咱們須要新建VPC通道。端口設置爲8081, 並將其與彈性雲服務器關聯。
建立完VPC通道後,回到API建立頁面,填入相關信息:
網關建立完成後,咱們須要回到咱們的彈性雲服務器,將咱們的後端服務器先跑起來:
RUST_LOG=chinese_segmentation=info nohup ./target/release/chinese_segmentation 2>&1 ~/api.log &
做爲示例,這裏使用nohup命令來跑咱們的服務。但在生產環境中,建議使用 systemd等工具來跑服務。服務在雲服務器運行起來以後,將API發佈至RELEASE環境中。
而後咱們就能夠和咱們的API愉快地玩耍啦。