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という感じです)