• OceanBase TableAPI实践案例(Rust)


    引子

    这是OceanBase TableAPI实践案例(Java)的姊妹篇,上一篇比较全面的比较全面的介绍了TableAPI的相关概念,以及基本的环境搭建,因此这篇不再赘述。本文将主要介绍TableAPI的Rust客户端obkv-table-client-rs ,因为这个开源项目相关说明较少,初学者可能未必能够直接上手操作,所以可以将本文内容作为该项目的增强版README。

    想更好的理解本文内容需要有Rust语言基础、OceanBase基础、了解TableAPI工作原理。

    注:为了不增加冗余篇幅,请提前阅读TableAPI官方文档***、******OceanBase TableAPI实践案例(Java)***两篇文章。

    环境准备

    假设按照OceanBase TableAPI实践案例(Java)中的方法,搭建好了OceanBase数据库环境、ob-configserver环境。

    Rust环境搭建

    • 安装
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    
    • 1
    • 版本
    rustcrustc 1.59.0-nightly (f1ce0e6a0 2022-01-05)
    rustuprustup 1.25.1 (bb60b1e89 2022-07-12)
    cargocargo 1.59.0-nightly (358e79fe5 2022-01-04)

    obkv-table-client-rs工程(可选)

    该步骤为可选,这一章节主要介绍如何编译obkv-table-client-rs工程。

    • 获取工程源码
    git clone https://github.com/oceanbase/obkv-table-client-rs.git
    
    • 1
    • 配置cargo国内镜像(可选),主要是为了加快下载速度,节省时间
    vim ~/.cargo/config
    # 写入以下内容
    [source.crates-io] 
    registry = "https://github.com/rust-lang/crates.io-index" 
    replace-with = 'tuna' 
    [source.ustc] 
    registry = "git://mirrors.ustc.edu.cn/crates.io-index"
    [source.tuna]
    registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 编译工程
    cd obkv-table-client-rs
    cargo build
    
    • 1
    • 2

    Rust客户端测试

    • 新建工程
    # 在obkv-table-client-rs同级目录下
    cargo new obkv_cli
    
    • 1
    • 2

    图片.png

    • 测试代码
    // Copyright 2022 CeresDB Project Authors. Licensed under Apache-2.0.
    
    extern crate obkv;
    
    use std::{sync::Arc, thread, time};
    
    use obkv::{serde_obkv::value::Value, Builder, ClientConfig, ObTableClient, RunningMode, Table};
    
    // TODO: use test conf to control which environments to test.
    const TEST_FULL_USER_NAME: &str = "frank@sys#obcluster";
    const TEST_URL: &str = "http://172.18.108.43:8080/services?Action=ObRootServiceInfo&ObCluster=obcluster&database=test";
    const TEST_PASSWORD: &str = "frank";
    const TEST_SYS_USER_NAME: &str = "root@sys";
    const TEST_SYS_PASSWORD: &str = "root";
    
    fn build_client(mode: RunningMode) -> ObTableClient {
        let mut config = ClientConfig::default();
        config.min_idle_conns_per_server = 1;
        config.max_conns_per_server = 1;
        config.rpc_connect_timeout = std::time::Duration::from_secs(1);
        config.metadata_mysql_conn_pool_max_size = 1;
        config.metadata_mysql_conn_pool_min_size = 1;
    
        let builder = Builder::new()
            .full_user_name(TEST_FULL_USER_NAME)
            .param_url(TEST_URL)
            .running_mode(mode)
            .password(TEST_PASSWORD)
            .sys_user_name(TEST_SYS_USER_NAME)
            .sys_password(TEST_SYS_PASSWORD);
    
        let client = builder.build();
    
        assert!(client.is_ok());
    
        let client = client.unwrap();
        client.init().expect("Fail to create obkv client.");
        client
    }
    
    const TABLE_NAME: &str = "series_key_to_id_0";
    // read and write the table:
    // create table series_key_to_id_0 (
    //  series_key VARBINARY(8096) NOT NULL,
    //  series_id BIGINT NOT NULL,
    //  PRIMARY KEY(series_key),
    //  KEY index_id(series_id)
    // );
    fn concurrent_insert(client: Arc<ObTableClient>) {
        let mut thds = Vec::with_capacity(20);
        for i in 0..50 {
            let client = client.clone();
            let thd = thread::spawn(move || {
                for j in i * 100..(i * 100 + 50) {
                    let series_key = format!("series_key_test_padding_padding_{}", j);
                    let series_id = j * j;
                    client
                        .insert(
                            TABLE_NAME,
                            vec![Value::from(series_key.clone())],
                            vec!["series_id".to_owned()],
                            vec![Value::from(series_id as i64)],
                        )
                        .expect(&format!("fail to insert row:{} {}", series_key, series_id));
                }
            });
            thds.push(thd);
        }
    
        for (i, thd) in thds.into_iter().enumerate() {
            thd.join().expect(&format!("thread#{} fail to join", i));
        }
    }
    
    fn main() {
        let client = build_client(RunningMode::Normal);
        client
            .truncate_table(TABLE_NAME)
            .expect("fail to truncate the table");
        let start = time::Instant::now();
        concurrent_insert(Arc::new(client));
        let elapsed = time::Instant::now() - start;
        println!("Benches::concurrent_insert cost time:{:?}", elapsed);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    根据你自己的情况修改以下几个参数/变量:

    const TEST_FULL_USER_NAME: &str = "frank@sys#obcluster";
    const TEST_URL: &str = "http://172.18.108.43:8080/services?Action=ObRootServiceInfo&ObCluster=obcluster&database=test";
    const TEST_PASSWORD: &str = "frank";
    const TEST_SYS_USER_NAME: &str = "root@sys";
    const TEST_SYS_PASSWORD: &str = "root";
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • Cargo.toml
    [package]
    name = "obkv_cli"
    version = "0.1.0"
    edition = "2022"
    
    # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
    
    [dependencies]
    obkv-table-client-rs = { path = "../obkv-table-client-rs" }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 编译
    cd obkv_cli
    cargo build
    
    • 1
    • 2
    • 运行
    cargo run
    
    • 1

    Q&A

    • 运行报错
    $ cargo run
        Finished dev [unoptimized + debuginfo] target(s) in 0.21s
         Running `target/debug/obkv_cli`
    thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: MySqlError { ERROR 1193 (HY000): Unknown system variable 'socket' }', /home/frank/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd/mysql-16.1.0/src/conn/mod.rs:1760:61
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    
    • 1
    • 2
    • 3
    • 4
    • 5

    问题跟踪:https://github.com/oceanbase/obkv-table-client-rs/issues/6

    总结

    相对与obkv-table-client-java 客户端,obkv-table-client-rs 运行时会有一些问题,可能是版本相关的问题,应该可以很快解决。

  • 相关阅读:
    EF Core: 使用AsNoTracking减少内存调用 / 实体跟踪的技巧
    Gitee的使用
    pythoin爬虫2之利用cookie进行登录
    程序员如何“升级打怪”?我用了这几个“歪瓜”!
    大前端CPU优化技术--NEON自动向量化
    java项目快速打包镜像到docker服务器
    Qt_C++读写NFC标签Ntag支持windows国产linux操作系统
    换工作有感
    针对结构映射的SVM算法:核心思路解读
    第6章——存储器层次结构
  • 原文地址:https://blog.csdn.net/xk_xx/article/details/127982654