DynamoDB、Cassandra互換のOSS NoSQL「Scylla」を使ってみる

CassandraやDynamoDBに互換性のあるオープンソースのNoSQL「Scylla」を使ってみました。 現代のコンピュータアーキテクチャに沿ったハイパフォーマンスなDBのようです。
2021.08.12

Scyllaとは

Scyllaはオープンソースのワイドカラム型のデータストアです。 Apache CassandraやAmazon DynamoDBとの互換性があります。 Cassandraと同様にクラスタ構成が可能ですが、ノードの性能が高いため、より少ないノード数で同様のパフォーマンスが出せるようです。

公式ホームページでは以下のように謳っています。

World's Fastest NoSQL Database
Power your applications with ultra-low latency & extremely high throughput

速い!強い!そんなDBらしいです。

今回はあくまでもDynamoDBの代わりとして使いますが、メインはCassandraの方みたいです。 互換性があるのでエンドポイントを書き換えるだけでほとんどコード変更なしでDBを変更することができるみたいです。 (データのマイグレーション等の必要はあるでしょうが)

つかってみる

今回はDockerを使用してDynamoDBの代わりに使ってみます。

Scyllaを起動する

$ docker run -it -p 8000:8000 --name scylla \
    scylladb/scylla \
    --alternator-port 8000 \
    --alternator-write-isolation only_rmw_uses_lwt

デフォルトだとINFOのログが大量に発生してびっくりしました。 DynamoDBの互換機能はalternatorと呼ばれており、--alternator-portなどはそれ用の設定です。 これとは別にCassandra用の機能も同時に動いています。

以下のような感じでログを見てエラーが発生していなければ概ね大丈夫だと思います。

エラーログを確認する

$ docker logs scylla 2>&1 | grep ERROR

この時自分はエラーがでてハマりました。詳細は一番最後に書いておきます。

せっかくなのでCassandraのクライアントを使って動作確認をしてみます。

cqlshを使ってみる

$ docker exec -it scylla cqlsh
Connected to  at 172.17.0.2:9042.
[cqlsh 5.0.1 | Cassandra 3.0.8 | CQL spec 3.3.1 | Native protocol v4]
Use HELP for help.

無事に接続できたみたいです。

最後にドキュメントを参考にDynamoDBとして使用してみます。 やっているのは次のことです。

  1. テーブルの作成
  2. データの書き込み
  3. データの読み込み

as_dynamodb.py

import boto3
dynamodb = boto3.resource(
    'dynamodb',
    endpoint_url='http://localhost:8000',
    region_name='None',
    aws_access_key_id='None',
    aws_secret_access_key='None'
)

dynamodb.create_table(
    AttributeDefinitions=[
        {
            'AttributeName': 'key',
            'AttributeType': 'S'
        },
    ],
    BillingMode='PAY_PER_REQUEST',
    TableName='usertable',
    KeySchema=[
        {
            'AttributeName': 'key',
            'KeyType': 'HASH'
        },
    ])

dynamodb.batch_write_item(RequestItems={
    'usertable': [
        {
            'PutRequest': {
                'Item': {
                    'key': 'test', 'x': {'hello': 'world'}
                }
            },
        }
    ]
})


print(dynamodb.batch_get_item(RequestItems={
    'usertable': {'Keys': [{'key': 'test'}]}
}))

endpoint_urllocalhost:8000にしています。 これはDockerで動いてるScyllaの8000番がバインドされているポートです。

実行してみます。

実行する

$ python3 sample.py 
{
    'Responses': {
        'usertable': [
            {'key': 'test', 'x': {'hello': 'world'}}
        ]
    },
    'UnprocessedKeys': {},
    'ResponseMetadata': {
        'HTTPStatusCode': 200,
        'HTTPHeaders': {
            'content-length': '105',
            'content-type': 'application/json',
            'date': 'Wed, 11 Aug 2021 09:03:48 GMT',
            'server': 'Seastar httpd'
        },
        'RetryAttempts': 0
    }
}

無事に動いているようです。

ハマったところ

Scyllaサーバーを動かした時に以下のようなエラーが発生しました。

エラー

seastar - Could not setup Async I/O: Resource temporarily unavailable. The most common cause is not enough request capacity in /proc/sys/fs/aio-max-nr. Try increasing that number or reducing the amount of logical CPUs available for your application

CPUのコア数とカーネルパラメータによってはうまく起動しない場合があるみたいです。 使用するコア数を減らすか、カーネルパラメータを変えると自分は動きました。 変更するカーネルパラメータはfs.aio-max-nrです。 自分の環境(Ubuntu20.04 8コア)では65536でしたが、1048576に変えたところ動きました。 Dockerで動かしていてもこのパラメータはホスト側で変更しないといけないらしく、ホスト側で設定しました。

カーネルパラメータを変える

$ sudo sysctl -w fs.aio-max-nr=1048576

必要値の計算式はここにかいてあります。

感想

おもったよりも簡単に動きました。 自分はCassandraを使ったことないので今回はDynamoDBの代わりとして使用しましたが、勉強してCassandaraとしても使ってみたいです。 現代のコンピュータのアーキテクチャに合わせて設計されているみたいなのでパフォーマンスも期待できます。 また勉強して記事にできたらとおもいます。