網(wǎng)站開(kāi)發(fā) 軟文品牌營(yíng)銷(xiāo)和市場(chǎng)營(yíng)銷(xiāo)的區(qū)別
WebAssembly (Wasm) 正在成為一個(gè)廣受歡迎的編譯目標(biāo),幫助開(kāi)發(fā)者構(gòu)建可遷移平臺(tái)的應(yīng)用。最近 Greptime 和 WasmEdge 協(xié)作,支持了在 WasmEdge 平臺(tái)上的 Wasm 應(yīng)用通過(guò) MySQL 協(xié)議讀寫(xiě) GreptimeDB 中的時(shí)序數(shù)據(jù)。
什么是 WebAssembly
WebAssembly 是一種新的指令格式,同時(shí)具備了跨平臺(tái)和接近原生機(jī)器代碼的執(zhí)行速度。** 通過(guò)將 C/C++ 或 Rust 代碼編譯成 WebAssembly ,可以在瀏覽器中提升程序的性能。而在瀏覽器外的其他運(yùn)行環(huán)境,尤其是 CDN 或 IoT 的邊緣端,我們也可以利用 WebAssembly 實(shí)現(xiàn)沙盒、動(dòng)態(tài)加載的插件機(jī)制等高級(jí)的功能。
什么是 WasmEdge
WasmEdge 是 CNCF 的沙箱項(xiàng)目,提供上文提到的沙盒能力,允許開(kāi)發(fā)者在 WebAssembly 標(biāo)準(zhǔn)的基礎(chǔ)上,進(jìn)一步擴(kuò)展其能訪問(wèn)的資源和接口。例如,WasmEdge 為 Wasm 提供了額外的 TLS、網(wǎng)絡(luò)能力和 AI 能力,大大豐富了使用場(chǎng)景。
WasmEdge GitHub 地址:
https://github.com/WasmEdge/WasmEdge
安裝 GreptimeDB 和 WasmEdge
如果你已經(jīng)安裝了 GreptimeDB ,可以跳過(guò)這個(gè)步驟。
下載 GreptimeDB 并運(yùn)行:
curl -L https://github.com/GreptimeTeam/greptimedb/raw/develop/scripts/install.sh | sh
./greptime standalone start
安裝 WasmEdge:
curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s
編寫(xiě) GreptimeDB 的 WASM 應(yīng)用
在 WasmEdge 中,我們可以使用 MySQL 協(xié)議,讓 Rust 語(yǔ)言編寫(xiě)的應(yīng)用程序連接到 GreptimeDB。
首先通過(guò) `cargo new`?創(chuàng)建一個(gè)新的 Rust 項(xiàng)目,我們的編譯目標(biāo)將是 `wasm32-wasi`,可以在項(xiàng)目根目錄下創(chuàng)建 `.cargo/config.toml` 文件,指定默認(rèn)編譯目標(biāo),之后就無(wú)需在每次 `cargo build` 命令后專(zhuān)門(mén)指定 `--target` 了。
# .cargo/config.toml
[build]
target = "wasm32-wasi"
編輯 `Cargo.toml` 增加依賴(lài)。`mysql_async` 的應(yīng)用需要 `tokio` 運(yùn)行時(shí),WasmEdge 維護(hù)了這兩個(gè)庫(kù)的修改版本,使他們能夠編譯成 WebAssembly 代碼,并且運(yùn)行到 WasmEdge 環(huán)境中。
[package]
name = "greptimedb"
version = "0.1.0"
edition = "2021"[dependencies]
mysql_async_wasi = "0.31"
time = "0.3"
tokio_wasi = { version = "1", features = [ "io-util", "fs", "net", "time", "rt", "macros"] }
進(jìn)一步編輯 `src/main.rs` 文件,加入數(shù)據(jù)庫(kù)訪問(wèn)的邏輯。這段代碼將演示:
1. 通過(guò)環(huán)境變量讀取數(shù)據(jù)庫(kù)地址,并創(chuàng)建連接池;
2. 執(zhí)行 SQL 語(yǔ)句創(chuàng)建數(shù)據(jù)表;
3. 插入數(shù)據(jù);
4. 查詢(xún)數(shù)據(jù)。
定義數(shù)據(jù)結(jié)構(gòu):
#[derive(Debug)]
struct CpuMetric {hostname: String,environment: String,usage_user: f64,usage_system: f64,usage_idle: f64,ts: i64,
}impl CpuMetric {fn new(hostname: String,environment: String,usage_user: f64,usage_system: f64,usage_idle: f64,ts: i64,) -> Self {Self {hostname,environment,usage_user,usage_system,usage_idle,ts,}}
}
初始化數(shù)據(jù)庫(kù)連接池:
use mysql_async::{prelude::*, Opts, OptsBuilder, Pool, PoolConstraints, PoolOpts, Result,
};
use time::PrimitiveDateTime;fn get_url() -> String {if let Ok(url) = std::env::var("DATABASE_URL") {let opts = Opts::from_url(&url).expect("DATABASE_URL invalid");if opts.db_name().expect("a database name is required").is_empty(){panic!("database name is empty");}url} else {"mysql://root:pass@127.0.0.1:3306/mysql".into()}
}#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<()> {// Alternative: The "easy" way with a default connection pool// let pool = Pool::new(Opts::from_url(&*get_url()).unwrap());// let mut conn = pool.get_conn().await.unwrap();// Below we create a customized connection poollet opts = Opts::from_url(&*get_url()).unwrap();let builder = OptsBuilder::from_opts(opts);// The connection pool will have a min of 1 and max of 2 connections.let constraints = PoolConstraints::new(1, 2).unwrap();let pool_opts = PoolOpts::default().with_constraints(constraints);let pool = Pool::new(builder.pool_opts(pool_opts));let mut conn = pool.get_conn().await.unwrap();Ok(())
}
創(chuàng)建數(shù)據(jù)表:
? ? // Create table if not existsr"CREATE TABLE IF NOT EXISTS wasmedge_example_cpu_metrics (hostname STRING,environment STRING,usage_user DOUBLE,usage_system DOUBLE,usage_idle DOUBLE,ts TIMESTAMP,TIME INDEX(ts),PRIMARY KEY(hostname, environment)
);".ignore(&mut conn).await?;
插入數(shù)據(jù):
? ? let metrics = vec![CpuMetric::new("host0".into(),"test".into(),32f64,3f64,4f64,1680307200050,),CpuMetric::new("host1".into(),"test".into(),29f64,32f64,50f64,1680307200050,),CpuMetric::new("host0".into(),"test".into(),32f64,3f64,4f64,1680307260050,),CpuMetric::new("host1".into(),"test".into(),29f64,32f64,50f64,1680307260050,),CpuMetric::new("host0".into(),"test".into(),32f64,3f64,4f64,1680307320050,),CpuMetric::new("host1".into(),"test".into(),29f64,32f64,50f64,1680307320050,),];r"INSERT INTO wasmedge_example_cpu_metrics (hostname, environment, usage_user, usage_system, usage_idle, ts)VALUES (:hostname, :environment, :usage_user, :usage_system, :usage_idle, :ts)".with(metrics.iter().map(|metric| {params! {"hostname" => &metric.hostname,"environment" => &metric.environment,"usage_user" => metric.usage_user,"usage_system" => metric.usage_system,"usage_idle" => metric.usage_idle,"ts" => metric.ts,}})).batch(&mut conn).await?;
查詢(xún)數(shù)據(jù):
? ? let loaded_metrics = "SELECT * FROM wasmedge_example_cpu_metrics".with(()).map(&mut conn,|(hostname, environment, usage_user, usage_system, usage_idle, raw_ts): (String,String,f64,f64,f64,PrimitiveDateTime,)| {let ts = raw_ts.assume_utc().unix_timestamp() * 1000;CpuMetric::new(hostname,environment,usage_user,usage_system,usage_idle,ts,)},).await?;println!("{:?}", loaded_metrics);
WasmEdge 團(tuán)隊(duì)提供的 `tokio` 和 `mysql_async` 庫(kù)與原始版本編程接口完全一致,因此可以無(wú)縫地將普通 Rust 應(yīng)用切換到 WebAssembly 平臺(tái)上。
編譯這個(gè)項(xiàng)目,我們可以獲得 greptimedb.wasm 文件:
cargo build
ls -lh target/wasm32-wasi/debug/greptimedb.wasm
通過(guò) WasmEdge 運(yùn)行我們的程序:
wasmedge --env "DATABASE_URL=mysql://localhost:4002/public" target/wasm32-wasi/debug/greptimedb.wasm
上面這段示例程序已經(jīng)納入了 WasmEdge 的數(shù)據(jù)庫(kù)使用示例,你可以在 GitHub 倉(cāng)庫(kù)找到完整的代碼:
https://github.com/WasmEdge/wasmedge-db-examples/tree/main/greptimedb。
總結(jié)
WasmEdge 為 WebAssembly 應(yīng)用提供了更多的擴(kuò)展能力。如果你也將應(yīng)用部署在 WebAssembly 環(huán)境里,未來(lái)我們還可以使用 OpenTelemetry SDK 采集指標(biāo)數(shù)據(jù)直接存儲(chǔ)到 GreptimeDB ?,F(xiàn)在就下載 GreptimeDB 或開(kāi)通 GreptimeCloud 實(shí)例運(yùn)行上面的例子吧。