CLOVER🍀

That was when it all began.

OSSのサーバーレスPostgreSQL(Amazon Aurora OSS代替)、NeonをUbuntu Linux 22.04 LTSでビルドしてみる

これは、なにをしたくて書いたもの?

Neonという、フルマネージドでサーバーレスなPostgreSQLというプロダクトがあります。

Neon — Serverless, Fault-Tolerant, Branchable Postgres

これはマネージドサービスとしても使えるのですが、ローカルで動かすことができるようなので1度試してみようかなということで。

やってみた結果としては、ローカルで動かすことはもうやらないと思いますが(笑)。

Neon

Neonは、フルマネージドでサーバーレスなPostgreSQL互換のプロダクトです。

Neon — Serverless, Fault-Tolerant, Branchable Postgres

ドキュメントはこちら。

Neon documentation - Neon Docs

Rustで実装されていて、ストレージとコンピューティングを分離したアーキテクチャーであり、サーバーレスでもあるとされています。

Neon is a fully managed serverless Postgres with a generous free tier. Neon separates storage and compute and offers modern developer features such as serverless, branching, bottomless storage, and more. Neon is open source and written in Rust.

What is Neon? - Neon Docs

PostgreSQLとの互換性はこちらにあるとおりで、PostgreSQL 14、15、16に対して互換性があり、Neonプロジェクトを作成する時に
どのPostgreSQLのバージョンを使うかを選択するようです。

Postgres compatibility - Neon Docs

利用は基本的にマネージドサービスとしての利用で、無料枠を含めて4つのプランがあります。

Pricing — Neon

無料枠で試してみるのもよいですね。

一方で、Neon自体はOSSで自分でビルドして動かすこともできます。

GitHubリポジトリーはこちらです。

GitHub - neondatabase/neon: Neon: Serverless Postgres. We separated storage and compute to offer autoscaling, branching, and bottomless storage.

README.mdの最初を見ると、AWS Aurora PostgreSQLのサーバーレスなOSS代替であると書かれていますね。イメージとしては
これで捉えるのがよさそうです。

Neon is a serverless open-source alternative to AWS Aurora Postgres. It separates storage and compute and substitutes the PostgreSQL storage layer by redistributing data across a cluster of nodes.

現在のバージョンはrelease-4917で、ローカルで動かすためには自分でビルドする必要があります。

その手順は、こちらに記載があります。

Neon / Running local installation

また、開発者向けドキュメントはこちらですね。

https://github.com/neondatabase/neon/tree/release-4917/docs

今回は、このNeonをローカルでビルドして動かすところまでをREADME.mdに沿ってやってみます。

結果を言うと、動くには動いたのですがビルドにものすごく時間がかかるので、今後はちょっと扱えないかなと思います…。
クラスターを組むところとかまで、到達しそうにないですね…。

環境

今回の環境はこちら。Ubuntu Linux 22.04 LTSです。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.4 LTS
Release:        22.04
Codename:       jammy


$ uname -srvmpio
Linux 5.15.0-97-generic #107-Ubuntu SMP Wed Feb 7 13:26:48 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

Neonをビルドしてインストールする

では、こちらの手順に沿ってNeonをビルド、インストールしていきます。

Neon / Running local installation

依存ライブラリーのインストール。

$ sudo apt install build-essential libtool libreadline-dev zlib1g-dev flex bison libseccomp-dev \
    libssl-dev clang pkg-config libpq-dev cmake postgresql-client protobuf-compiler \
    libcurl4-openssl-dev openssl python3-poetry lsof libicu-dev

postgresql-clientが含まれていますが、これはNeonに接続するpsqlコマンドで使います。

Rustのインストール。

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ source "$HOME/.cargo/env"

インストールされたRustのバージョン。

$ rustc --version
rustc 1.76.0 (07dca489a 2024-02-04)


$ cargo --version
cargo 1.76.0 (c84b36747 2024-01-18)

Neonリポジトリーをcloneします。

$ git clone --recursive https://github.com/neondatabase/neon.git

Neonだけでなく、サブモジュールとして登録されているPostgreSQL 14、15、16もcloneしてくるのでかなり時間がかかります。

Submodule 'vendor/postgres-v14' (https://github.com/neondatabase/postgres.git) registered for path 'vendor/postgres-v14'
Submodule 'vendor/postgres-v15' (https://github.com/neondatabase/postgres.git) registered for path 'vendor/postgres-v15'
Submodule 'vendor/postgres-v16' (https://github.com/neondatabase/postgres.git) registered for path 'vendor/postgres-v16'

cloneしたディレクトリ内に移動して、現時点のリリースバージョン(release-4917)にチェックアウト。

$ cd neon
$ git checkout release-4917

ビルド。

$ make -j`nproc` -s

すると、PostgreSQL 14、15、16も含めてビルドを始めようとします。

Configuring Postgres v14 build
Configuring Postgres v15 build
Configuring Postgres v16 build
Installing PostgreSQL v14 headers
Installing PostgreSQL v15 headers
Installing PostgreSQL v16 headers
Compiling PostgreSQL v14
Compiling PostgreSQL v15
Compiling libpq v14
Compiling pg_prewarm v14
Compiling pg_buffercache v14
Compiling pageinspect v14
Compiling amcheck v14
Compiling PostgreSQL v16
Compiling libpq v15
Compiling pg_prewarm v15
Compiling pg_buffercache v15
Compiling pageinspect v15
Compiling amcheck v15
Compiling neon v14
Compiling neon_walredo v14
Compiling neon_rmgr v14
Compiling neon_test_utils v14
Compiling neon_utils v14
Compiling neon v15
Compiling neon_walredo v15
Compiling neon_rmgr v15
Compiling neon_test_utils v15
Compiling neon_utils v15
Compiling libpq v16
Compiling pg_prewarm v16
Compiling pg_buffercache v16
Compiling pageinspect v16
Compiling amcheck v16
Compiling neon v16
Compiling neon_walredo v16
Compiling neon_rmgr v16
Compiling neon_test_utils v16
Compiling neon_utils v16
Compiling walproposer-lib
Compiling Neon
info: syncing channel updates for '1.76.0-x86_64-unknown-linux-gnu'
info: latest update on 2024-02-08, rust version 1.76.0 (07dca489a 2024-02-04)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'llvm-tools'
info: downloading component 'rust-docs'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: installing component 'clippy'
info: installing component 'llvm-tools'
info: installing component 'rust-docs'
info: installing component 'rust-std'
info: installing component 'rustc'
info: installing component 'rustfmt'

が、途中で失敗しました。

error: failed to run custom build command for `storage_broker v0.1.0 (/path/to/neon/storage_broker)`

Caused by:
  process didn't exit successfully: `/path/to/neon/target/debug/build/storage_broker-a85363180b39c0b7/build-script-build` (exit status: 101)
  --- stdout
  cargo:rerun-if-changed=proto/broker.proto
  cargo:rerun-if-changed=proto

  --- stderr
  thread 'main' panicked at storage_broker/build.rs:9:29:
  failed to compile protos Custom { kind: Other, error: "protoc failed: broker.proto: This file contains proto3 optional fields, but --experimental_allow_proto3_optional was not set.\n" }
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
make: *** [Makefile:69: neon] エラー 101

このissueを見ると、protocは3.15以上を使う必要がありそうです。

failed to run custom build command for `storage_broker v0.1.0 (/root/neon/storage_broker)` · Issue #4911 · neondatabase/neon · GitHub

aptでインストールしたprotocのバージョンを確認してみます。

$ protoc --version
libprotoc 3.12.4

たしかに古いです…。

というわけで、protocの最新バージョンをインストールしましょう。
適当なディレクトリに移動して、protoc 25.3(現時点での最新バージョン)をダウンロードして/usr/localにインストール。

$ curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v25.3/protoc-25.3-linux-x86_64.zip
$ unzip protoc-25.3-linux-x86_64.zip
$ sudo cp bin/protoc /usr/local/bin/
$ sudo cp -R include/google /usr/local/include/google

Release Protocol Buffers v25.3 · protocolbuffers/protobuf · GitHub

確認。

$ protoc --version
libprotoc 25.3

再度ビルド。

$ make -j`nproc` -s

今度はうまくいきました。

Installing PostgreSQL v14 headers
Installing PostgreSQL v15 headers
Installing PostgreSQL v16 headers
Compiling PostgreSQL v14
Compiling PostgreSQL v15
Compiling libpq v14
Compiling pg_prewarm v14
Compiling pg_buffercache v14
Compiling pageinspect v14
Compiling amcheck v14
Compiling PostgreSQL v16
Compiling libpq v15
Compiling pg_prewarm v15
Compiling pg_buffercache v15
Compiling pageinspect v15
Compiling amcheck v15
Compiling neon v14
Compiling neon_walredo v14
Compiling neon_rmgr v14
Compiling neon_test_utils v14
Compiling neon_utils v14
Compiling neon v15
Compiling neon_walredo v15
Compiling neon_rmgr v15
Compiling neon_test_utils v15
Compiling neon_utils v15
Compiling libpq v16
Compiling pg_prewarm v16
Compiling pg_buffercache v16
Compiling pageinspect v16
Compiling amcheck v16
Compiling neon v16
Compiling neon_walredo v16
Compiling neon_rmgr v16
Compiling neon_test_utils v16
Compiling neon_utils v16
Compiling walproposer-lib
Compiling Neon

ここまでで、とても時間がかかります…。

あとは、ドキュメントに沿ってNeonの初期化からプロセスの起動までを行っていきます。

Neonの初期化。

$ cargo neon init

実行ログ。

   Compiling rustc-hash v1.1.0
   Compiling tempfile v3.5.0
   Compiling bindgen v0.65.1
   Compiling prost-build v0.11.9
   Compiling tonic-build v0.9.2
   Compiling storage_broker v0.1.0 (/path/to/neon/storage_broker)
   Compiling postgres_ffi v0.1.0 (/path/to/neon/libs/postgres_ffi)
   Compiling pageserver_api v0.1.0 (/path/to/neon/libs/pageserver_api)
   Compiling pageserver_client v0.1.0 (/path/to/neon/pageserver/client)
   Compiling control_plane v0.1.0 (/path/to/neon/control_plane)
    Finished dev [unoptimized + debuginfo] target(s) in 5m 03s
     Running `target/debug/neon_local init`
Initializing pageserver node 1 at '127.0.0.1:64000' in ".neon/pageserver_1"

pageserver、safekeeper、内部通信のためのbrokerの起動。

$ cargo neon start

実行ログ。

    Finished dev [unoptimized + debuginfo] target(s) in 19.43s
     Running `target/debug/neon_local start`
Starting neon broker at 127.0.0.1:50051.
storage_broker started and passed status check, pid: 71502
The files belonging to this database system will be owned by user "xxxxx".
This user must also own the server process.

The database cluster will be initialized with locale "ja_JP.UTF-8".
The default database encoding has accordingly been set to "UTF8".
initdb: could not find suitable text search configuration for locale "ja_JP.UTF-8"
The default text search configuration will be set to "simple".

Data page checksums are disabled.

creating directory .neon/attachment_service_db ... ok
creating subdirectories ... ok
selecting dynamic shared memory implementation ... posix
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting default time zone ... Asia/Tokyo
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok

initdb: warning: enabling "trust" authentication for local connections
initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    /path/to/neon/pg_install/v16/bin/pg_ctl -D .neon/attachment_service_db -l logfile start

Starting attachment service database...
localhost:1235 - no response
.localhost:1235 - no response
localhost:1235 - rejecting connections
localhost:1235 - accepting connections

attachment_service_db started and passed status check, pid: 71520
...
attachment_service started and passed status check, pid: 71539
Starting pageserver node 1 at '127.0.0.1:64000' in ".neon/pageserver_1"..
pageserver started and passed status check, pid: 71550
Starting safekeeper at '127.0.0.1:5454' in '.neon/safekeepers/sk1'.
safekeeper-1 started and passed status check, pid: 71560

初期テナントの作成とneon_localのデフォルトの呼び出し先を設定。

$ cargo neon tenant create --set-default

実行ログ。

    Finished dev [unoptimized + debuginfo] target(s) in 1.85s
     Running `target/debug/neon_local tenant create --set-default`
tenant 274099fcecc835dfb9191dc8f717b759 successfully created on the pageserver
Created an initial timeline '57b0fb7782137034ccbce605eeb99412' for tenant: 274099fcecc835dfb9191dc8f717b759
Setting tenant 274099fcecc835dfb9191dc8f717b759 as a default one

PostgreSQLコンピュートノードの作成。

$ cargo neon endpoint create main

実行ログ。

    Finished dev [unoptimized + debuginfo] target(s) in 1.92s
     Running `target/debug/neon_local endpoint create main`

PostgreSQLコンピュートノードの起動。

$ cargo neon endpoint start main

実行ログ。

    Finished dev [unoptimized + debuginfo] target(s) in 1.73s
     Running `target/debug/neon_local endpoint start main`
Starting existing endpoint main...
Starting postgres node at 'postgresql://cloud_admin@127.0.0.1:55432/postgres'

実行中のPostgreSQLインスタンスの確認。

$ cargo neon endpoint list
    Finished dev [unoptimized + debuginfo] target(s) in 1.83s
     Running `target/debug/neon_local endpoint list`
 ENDPOINT  ADDRESS          TIMELINE                          BRANCH NAME  LSN        STATUS
 main      127.0.0.1:55432  57b0fb7782137034ccbce605eeb99412  main         0/149F8D8  running

無事、インストールと起動が完了しました。

psqlNeonに接続する

それでは、Neonに接続してみましょう。こちらもドキュメントに沿ってそのまま行います。

Neon / Running local installation

aptでインストールしたPostgreSQL Client(psql)がちょっと古いですが、今回はこのままいくことにしましょう。

$ psql --version
psql (PostgreSQL) 14.10 (Ubuntu 14.10-0ubuntu0.22.04.1)

Neonへ接続。

$ psql -p 55432 -h 127.0.0.1 -U cloud_admin postgres
psql (14.10 (Ubuntu 14.10-0ubuntu0.22.04.1), server 15.6)
WARNING: psql major version 14, server major version 15.
         Some psql features might not work.
Type "help" for help.

postgres=#

cargo neon startの時のログにも出ていましたが、ローカル接続だとtrust扱いになっているのでパスワードを聞かれません。

initdb: warning: enabling "trust" authentication for local connections
initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb.

テーブルの作成からデータ登録、確認まで。

postgres=# CREATE TABLE t(key int primary key, value text);
CREATE TABLE
postgres=# insert into t values(1,1);
INSERT 0 1
postgres=# select * from t;
 key | value
-----+-------
   1 | 1
(1 row)

1度、psqlを終了します。

postgres=# \q

次はブランチです。Neonは、データに対するブランチを作成できるようです。

Branching - Neon Docs

「migration_check」という名前のブランチを作成。

$ cargo neon timeline branch --branch-name migration_check
    Finished dev [unoptimized + debuginfo] target(s) in 1.87s
     Running `target/debug/neon_local timeline branch --branch-name migration_check`
Created timeline '99182b9ad53c4b534c1d6f9b948e3ba3' at Lsn 0/14D5450 for tenant: 274099fcecc835dfb9191dc8f717b759. Ancestor timeline: 'main'

ブランチを確認。

$ cargo neon timeline list
    Finished dev [unoptimized + debuginfo] target(s) in 1.84s
     Running `target/debug/neon_local timeline list`
main [57b0fb7782137034ccbce605eeb99412]
┗━ @0/14D5450: migration_check [99182b9ad53c4b534c1d6f9b948e3ba3]

mainから分岐した、migration_checkというブランチができていることがわかります。

ブランチに対するPostgreSQLコンピュートノードの作成。

$ cargo neon endpoint create migration_check --branch-name migration_check
    Finished dev [unoptimized + debuginfo] target(s) in 1.86s
     Running `target/debug/neon_local endpoint create migration_check --branch-name migration_check`

ブランチに対するPostgreSQLコンピュートノードの起動。

$ cargo neon endpoint start migration_check
    Finished dev [unoptimized + debuginfo] target(s) in 1.76s
     Running `target/debug/neon_local endpoint start migration_check`
Starting existing endpoint migration_check...
Starting postgres node at 'postgresql://cloud_admin@127.0.0.1:55434/postgres'

先ほどとは違うポートで起動しているようですね。

動作しているPostgreSQLインスタンスの一覧を見てみます。

$ cargo neon endpoint list
    Finished dev [unoptimized + debuginfo] target(s) in 1.93s
     Running `target/debug/neon_local endpoint list`
 ENDPOINT         ADDRESS          TIMELINE                          BRANCH NAME      LSN        STATUS
 main             127.0.0.1:55432  57b0fb7782137034ccbce605eeb99412  main             0/14D5450  running
 migration_check  127.0.0.1:55434  99182b9ad53c4b534c1d6f9b948e3ba3  migration_check  0/14D54C0  running

よく見ると、この中にブランチ名も含まれていますね。

migration_checkブランチの方のコンピュートノードへ接続。

$ psql -p 55434 -h 127.0.0.1 -U cloud_admin postgres
psql (14.10 (Ubuntu 14.10-0ubuntu0.22.04.1), server 15.6)
WARNING: psql major version 14, server major version 15.
         Some psql features might not work.
Type "help" for help.

postgres=#

データを確認すると、mainブランチで登録したデータが入っています。

postgres=# select * from t;
 key | value
-----+-------
   1 | 1
(1 row)

データを追加。

postgres=# insert into t values(2,2);
INSERT 0 1

現在は2件のデータがあります。

postgres=# select * from t;
 key | value
-----+-------
   1 | 1
   2 | 2
(2 rows)

psqlを終了。

postgres=# \q

mainブランチのコンピュートノードへ接続。

$ psql -p 55432 -h 127.0.0.1 -U cloud_admin postgres
psql (14.10 (Ubuntu 14.10-0ubuntu0.22.04.1), server 15.6)
WARNING: psql major version 14, server major version 15.
         Some psql features might not work.
Type "help" for help.

postgres=#

こちらでは、migration_checkブランチで追加したデータが見えないことが確認できます。

postgres=# select * from t;
 key | value
-----+-------
   1 | 1
(1 row)

オマケ:neon_local

Neonの初期化の際に、neon_localのデフォルトの呼び出し先を設定というステップがありましたが、neon_local自体には触れていません
でした。

neon_localは、Neonをビルドするとtarget/debugディレクトリ内に作成されます。

$ target/debug/neon_local --version
Neon CLI git:96a4e8de660be469fb00efd7d268120890ca06fd-modified

そもそも、今までcargo neon [コマンド]といった形でコマンドを実行していましたが、実行ログをよく見ると実体としてはneon_localを
呼び出していることが示されていました。

$ cargo neon endpoint list
    Finished dev [unoptimized + debuginfo] target(s) in 1.88s
     Running `target/debug/neon_local endpoint list`
 ENDPOINT         ADDRESS          TIMELINE                          BRANCH NAME      LSN        STATUS
 main             127.0.0.1:55432  57b0fb7782137034ccbce605eeb99412  main             0/14D5450  running
 migration_check  127.0.0.1:55434  99182b9ad53c4b534c1d6f9b948e3ba3  migration_check  0/14D5828  running

「Running」の部分ですね。

ということは、cargo neonneon_localに置き換えても実行できるはずです。

$ target/debug/neon_local endpoint list
 ENDPOINT         ADDRESS          TIMELINE                          BRANCH NAME      LSN        STATUS
 main             127.0.0.1:55432  57b0fb7782137034ccbce605eeb99412  main             0/14D5450  running
 migration_check  127.0.0.1:55434  99182b9ad53c4b534c1d6f9b948e3ba3  migration_check  0/14D5828  running

やっぱりそうでした。

ではこれがNeon標準のCLIツールかというとそれはちょっと違うようで、Neon CLIは別に存在します。

Neon CLI - Neon Docs

おわりに

OSSのサーバーレスPostgreSQLNeonを自分でビルドして動かしてみました。

おもしろいな、と思うのですが、ビルドに時間がかかりすぎるのとリソース的にもちょっとヘビー気味なので、自分の手持ちの環境で
遊ぶのは難しそうかな…と思います。

もともと興味はあって、1度動かしてみたいなと思っていたくらいなので、ここまでにしておきましょう。