2021-04-04

rqlite入門

rqlite というバックエンドにSQLite3を使った分散DBについて調べてみました

インストール

macの場合こんな感じでインストールできます

$ curl -L https://github.com/rqlite/rqlite/releases/download/v5.10.2/rqlite-v5.10.2-darwin-amd64.tar.gz -o rqlite-v5.10.2-darwin-amd64.tar.gz
$ tar xvfz rqlite-v5.10.2-darwin-amd64.tar.gz
$ cd rqlite-v5.10.2-darwin-amd64
$ cp rqlite /usr/local/bin/rqlite
$ cp rqlited /usr/local/bin/rqlited
$ cp rqbench /usr/local/bin/rqbench

使い方

各ノードのサービスの立ち上げはrqlitedでできます。
今回はシングルホストでクラスタリングを検証するため、↓をそれぞれ別シェルで実行します。

$ rqlited -node-id 1 ./node.1
$ rqlited -node-id 2 -http-addr localhost:4003 -raft-addr localhost:4004 -join http://localhost:4001 ./node.2
$ rqlited -node-id 3 -http-addr localhost:4005 -raft-addr localhost:4006 -join http://localhost:4001 ./node.3

↑の場合はリーダーノードは 1 のノードになります。

データ操作するにはHTTP APIを使うことになりますが、CLIのクライアント rqlite も用意されています。

$ rqlite

> CREATE TABLE hoge (id int primary key);
> INSERT INTO hoge VALUES (1),(2),(3);
> SELECT * from hoge;
+----+
| id |
+----+
| 1  |
+----+
| 2  |
+----+
| 3  |
+----+

リーダーノードはrqliteのコマンド .status かStatus APIで確認可能です

> .status
...
  leader:
    node_id: 1
    addr: 127.0.0.1:4002
$ curl -sS localhost:4001/status | jq .store.leader
{
  "addr": "127.0.0.1:4002",
  "node_id": "1"
}

リーダーノードのrqlitedのプロセスを落とすと別のノードがリーダーに昇格します。

リードレプリカ

リードレプリカ用のノードを使う場合はRead-onlyノードを使います。

$ rqlited -node-id 4 \
    -http-addr localhost:4005 \
    -raft-addr localhost:4006 \
    -join http://localhost:4001 \
    -raft-non-voter=true \
    ./node.4

rqliteは基本的にリーダーノードがレスポンスを返すようになっており、 フォロワーノードにリクエストした場合は301でリーダーノードにリダイレクトします。

$ curl -i -G 'localhost:4005/db/query?pretty&timings' --data-urlencode 'q=SELECT * FROM hoge'

HTTP/1.1 301 Moved Permanently
Content-Type: application/json; charset=utf-8
Location: http://localhost:4003/db/query?pretty&timings&q=SELECT%20%2A%20FROM%20hoge
X-Rqlite-Version: v5.10.2
Date: Sun, 04 Apr 2021 03:41:50 GMT
Content-Length: 0

Readレベルがnoneの場合はそのノードがレスポンスを返すので、リードレプリカとして利用したい場合はRead-onlyノードに対して level=none のクエリパラメータを指定する必要があります

$ curl -i -G 'localhost:4005/db/query?level=none&pretty&timings' \
    --data-urlencode 'q=SELECT * FROM hoge'

ただし、Readonlyノードとリーダーノードで接続が切れてしまった場合、リードレプリカが正しいデータを返していない可能性があります。

その場合は freshness={duration} のパラメータを指定することで、リーダーノードとの接続断がdurationの期間を超えるとstaleエラーを返すようになり、 誤ったデータを不意に読み出さないようにすることができます。

{
    "error": "stale read",
    "time": 0.000010519
}

その他

アーキテクチャ的にはRaft + SQLite3(In Memory?) っぽいです

まとめ

SQLite3をバックエンドに使った分散DBであるrqliteを調べてみました。 シングルバイナリでインストールやクラスタリングが簡単でしたし、HTTP APIを使ったデータの操作も使いやすいと思いました。 (SQLite3を冗長化する仕組みではなく、SQLite3をバックエンドに使った新しいDBという感じです)

このエントリーをはてなブックマークに追加