使用 OpenDAL 连接 PostgreSQL

使用 OpenDAL 连接 PostgreSQL

文一

2025-04-08 发布146 浏览 · 0 点赞 · 0 收藏

太山不让土壤,故能成其大;河海不择细流,故能就其深;王者不却众庶,故能明其德。
——《史记》

OpenDAL 的项目目标在于,屏蔽具体存储软件的细节,为各种数据应用程序提供统一的“文件资源访问接口”(“One Layer, All Storage”),而在本文中,我们将会阐述如何使用 OpenDAL 项目连接到 PostgreSQL。

img

(本文将会使用 OpenDAL 的 Rust 接口连接 PostgreSQL)

环境准备

我们假定你的系统工作于 类 Linux 之下,同时已经安装了如下的软件:

git

# 假定系统为 Ubuntu
sudo apt -y install git

PostgreSQL

初始化环境配置

# 假定系统为 Ubuntu
sudo apt -y install gcc make gdb pkg-config libreadline-dev libicu-dev libldap2-dev uuid-dev tcl-dev libperl-dev python3-dev bison flex openssl libssl-dev libpam-dev libxml2-dev libxslt-dev libossp-uuid-dev libselinux-dev gettext
# 下载 PostgreSQL 源代码仓库
git clone git://git.postgresql.org/git/postgresql.git
# 编译 PostgreSQL,安装 PostgreSQL 至用户主目录下
cd postgresql
./configure --prefix=$HOME/postgres --exec-prefix=$HOME/postgres
make install
# 导入环境变量
echo 'export PATH=$PATH:$HOME/postgres:$HOME/postgres/bin' >> $HOME/.bashrc
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/postgres/lib'  >> $HOME/.bashrc
# 初始化数据库
initdb $HOME/postgres/data

数据表准备

OpenDAL 将 PostgreSQL 抽象为文件系统的原理如图所示:

img

因此,对于 PostgreSQL 而言,我们必须准备一张与图中格式相互匹配的数据表,以供 OpenDAL 应用程序使用:

# 运行 PostgreSQL 服务端
postgres -D $HOME/postgres/data
# 使用 psql 连接 PostgreSQL
psql -d postgres
create table example (
    /* 用于存储 OpenDAL 文件名 */
    filename text, 
    /* 用于存储 OpenDAL 文件数据 */
    filedata bytea, 
    /* OpenDAL 要求 filename 具有 UNIQUE 约束 */
    unique(filename)
);

Rust

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

项目准备

# 创建一个名为 `opendal-postgresql-service` 的新项目
cargo new opendal-postgresql-service
# 进入项目文件夹
cd opendal-postgresql-service
# 引入 OpenDAL 所需内容
cargo add opendal anyhow tokio
# 启动 OpenDAL PostgreSQL 服务特性
cargo add opendal --features services-postgresql
# tokio 为 程序带来异步支持
cargo add tokio --features full

知识准备

正如 Linux 使用 fd(文件描述符)统一描述各类设备一样,OpenDAL 将 Operator 作为统一的描述各类数据存储设备的对象。

一般而言,我们需要通过 OpenDAL 提供出来的各类 Service(服务用于描述各类可以存储数据资源的软件,如在这里,我们就需要使用 OpenDAL PostgreSQL Service 用以访问 PostgreSQL)构建 Builder(构建器被视作是一组 Service 的集合),再由此构建出 Operator(这就像),再使用 Operator 去访问各类数据资源(如果你阅读过 Linux 文件系统的有关原理,相信你可以有一个更为深刻的理解)。

更多论述可以参考OpenDAL 中的有关部分

具体实践

打开 opendal-postgresql-service 项目下 src 目录中的 main.rs,依靠 OpenDAL 中有关 PostgreSQL Service 的部分,修订为如下:

use anyhow::Result;
use opendal::services::Postgresql;
use opendal::Operator;

#[tokio::main]
async fn main() -> Result<()> {
    let builder = Postgresql::default()
        .root("/")
        /* 连接到本地 PostgreSQL 的 postgres 数据库上面 */
        .connection_string("postgresql://127.0.0.1:5432/postgres")
        /* 使用我们前面创建的 example 表  */
        .table("example")
        /* 存储文件名的数据列 */
        .key_field("filename")
        /* 存储文件数据的数据列 */
        .value_field("filedata");

    let op = Operator::new(builder)?.finish();

    Ok(())
}

特别注意:OpenDAL 采取了 Lazy Initialization(延迟初始化)策略

根据 Lazy Reader 有关的论述,OpenDAL sends an actual IO request to the storage when Accessor::read() is invoked(在数据访问器的数据读取工作真正开始以后,OpenDAL 才开始向有关的存储软件发送真正的 I/O 请求),换而言之,如果只是通过不同的服务层(Service)构建操作符(Operator),OpenDAL 将不会向存储软件展开任何访问的工作。

这种做法可以节约很多非必要场景下的资源。


之后,让我们阅读 ReaderWrite 的有关部分,将代码又修订为如下:

use anyhow::Result;
use opendal::services::Postgresql;
use opendal::Operator;

#[tokio::main]
async fn main() -> Result<()> {
    let builder = Postgresql::default()
        .root("/")
        /* 假定你的用户名为 user_name */
        .connection_string("postgresql://wenyi@127.0.0.1:5432/postgres")
        /* 使用我们前面创建的 example 表  */
        .table("example")
        /* 存储文件名的数据列 */
        .key_field("filename")
        /* 存储文件数据的数据列 */
        .value_field("filedata");

    let op = Operator::new(builder)?.finish();

    /* 将 `Hello PostgreSQL` 写入到一个名为 `postgres.txt` 的文件夹中 */
    op.write("postgres.txt", "Hello PostgreSQL").await?;

    /* 构建 Reader */
    let content = op
        .reader_with("postgres.txt")
        .await?
        ;
    
    /* 经由 Reader 获取到一个 Buffer */
    let bs = content.read(0..16).await?;
    
    /* 提取 Buffer 中的内容,即为文件内容 */
    println!("{:?}", bs.to_bytes());

    Ok(())
}

最后,执行如下的命令:

# 假定处于 opendal-postgresql 目录下
cargo build --release
# 执行构建后的程序
# 请保持 PostgreSQL 正常运行
./target/release/opendal-postgresql

写在最后

感谢我的本科生导师,系主任袁国铭老师,感谢中国 PG 分会魏波、王其达老师,感谢开放原子开源基金会张凯老师,感谢 @Manjusaka,@XuanWo,@尚卓燃 的指导与帮助。

期待将来成为一流的开源科学家!

请前往 登录/注册 即可发表您的看法…