NoSQLベンチマーク紹介：MongoDB, Cassandra, そしてCouchbase

# はじめに

## 概要

本記事では、以下のNoSQLデータベースに対して実施されたベンチマークの内容を紹介します。

- MongoDB v3.6
- DataStax Enterprise v6 (Cassandra)
- Couchbase Server v5.5

ここで紹介するベンチマークは、2018年にAltros社によって実施されたもので、下記から入手可能です。

[NoSQL Performance Benchmark 2018: Couchbase Server v5.5, DataStax Enterprise v6 (Cassandra), and MongoDB v3.](https://www.altoros.com/research-papers/nosql-performance-benchmark-2018-couchbase-server-v5-5-datastax-enterprise-v6-cassandra-and-mongodb-v3-6/)

## 目的

この記事は、以下の目的のために執筆・発表されます。

- Altoros社によるベンチマーク内容の紹介
- Altoros社によるベンチマーク方法が不適切と考える部分についての指摘
- 将来のベンチマーク実施のためのベースライン設定の試みとして

# Altoros社ベンチマーク概要

## 評価基準・ツール

[Yahoo! Cloud Serving Benchmark (YCSB)](https://en.wikipedia.org/wiki/YCSB)

## ワークロード・カテゴリー
### YSCB標準
- ワークロード A: 更新処理
- ワークロード E: レンジスキャン

### クエリー
- クエリ１：ページネーション（OFFSETとLIMITによるフィルター）
- クエリ２：ジョイン（テーブル結合）

クエリ 1 とクエリ 2 は、それぞれ、下記のドメインとシナリオを表現。

- 財務：フィルター処理されたトランザクションを一覧表示するためのサーバー側のページネーション
- eコマース: 顧客が利用するさまざまな製品やサービスに関する一連のレポート


## 環境


同じリージョン内のサイズの異なる以下の３通りのクラスターで検証。

- 4 ノード
- 10 ノード
- 20 ノード

### データベース用インスタンス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/6b355a9f-588b-4041-2e82-3e38d6a73551.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/8f7b0d75-e318-65e5-9707-d123b216bb37.png)
### クライアント用インスタンス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/5fd30078-ef01-40f3-2b79-a52fff123da5.png)

## 共通条件
- データサイズは、メモリーサイズと適合している状態
- Durability（耐久性）オプション未使用
- 各データセットに対して1 つのレプリカ（複製）

注) Durability（耐久性）オプションとは、WRITE処理の際のデータの耐久性のレベルをデフォルトよりも高く設定すること。例えば、複製の作成やディスクへの同期の際に、キューによる処理が行える場合でも、キューを利用せずに、複製やディスクへの永続化処理完了を待って処理完了とみなす。

## データベース固有の構成

### Couchbase

クラスタ サイズに関係なく、各ノードはデータ サービス、インデックス サービス、およびクエリ サービスで構成。
バケットには、使用可能な RAM (36,178 MB) の 60% を割り当て。
インデックス サービスには、使用可能な RAM の約 40 % (約 24 GB) を割り当て。作成された各インデックスは、すべてのインデックスサービスに複製。

### MongoDB

MongoDBは、Routerプロセス、Configサーバー、およびデータシャードからなる階層型クラスタトポロジを採用しています。各クラスタ サイズ (4、10、および 20 ノード) に対して、以下の構成が使用されています。

- Configサーバーは、3つのメンバーからなるレプリカセットとして構成 (クラスタのノード数としてはカウントしない、別のコンピュータ）。
- 各シャードは、3つのメンバーからなるレプリカ セット (プライマリ、1 つのセカンダリ、1 つのArbeiter)として構成。
- 各クライアントに3つの`mongos`（Routerプロセス）をデプロイ

### Cassandra
下記の設定を適用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/8e38d951-4872-d94e-08b5-34a8fc91a492.png)

# Altros社ベンチマーク：ワークロード別詳細

## ワークロード A: 更新処理

### 詳細

- 読み取り： 50% 
- 更新： 50% 

- 4 ノード クラスタ: 5千万レコード (1レコード1KB) 
- 10 ノード クラスタ: 1 億レコード
- 20 ノード クラスタ: 2 億レコード

### クエリ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/1d8ee3b3-f366-6100-b183-0cecbfa099d4.png)


### 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/a5880b34-4d3a-e35a-7682-aa48c1c9e1b0.png)


## ワークロード E: レンジスキャン

### 詳細

- 読み取り： 95% 
- 更新： 5% 

- 4 ノード クラスタ: 5千万レコード (1レコード1KB) 
- 10 ノード クラスタ: 1 億レコード
- 20 ノード クラスタ: 2 億5千万レコード

### 本検証における問題

冒頭の本稿の目的に記した、「Altoros社によるベンチマーク方法が不適切と考える部分についての指摘」は、この検証に対して行われます。以下、原文から引用します。

>Because the scan operation is performed over the primary key in Couchbase, the following primary index has been created:

```sql
CREATE PRIMARY INDEX `ycsb_primary` ON `ycsb`
USING GSI WITH {"nodes": [...]}
```

ここには、Couchbaseのプライマリーインデックスに対する誤解が見えます。
原文で、「the primary key in Couchbase (Couchbaseのプライマリーキー)」と呼ばれているのは、実際には、キーバリューストアとしてドキュメントが格納される際のキー（ドキュメントID）であり、インデックスの概念とは異なるものです。
また、Couchbaseのプライマリーインデックスは、そのバケット（上記の`yscb`）に対する、あらゆるクエリを可能にする（インデックスサービスがそのバケットに対する全件スキャンを可能にする）ためのものであって、そのキー（ドキュメントID）を使った検索を最適化するものではありません（上記のDDLでは、バケット名`ycsb`のみが指定されていることに注意）。
後出のクエリの実行を最適化するためには、以下のように、`meta().id`を「プライマリーキー」の役割で利用するためのインデックスを、(Couchbaseの概念における)*セカンダリーインデックス*として作成する必要があります。

```sql
CREATE INDEX `yscb_primary` on `yscb`(META().id) using GSI;
```

CouchbaseのN1QLクエリは、SQLをJSONへのクエリとして拡張したものです。キーバリューストアのキーとしてのドキュメントIDは、JSONデータを構成する要素ではなく、メタデータの位置づけとなるため、上記のような`META().~`という指定が用いられます。



### クエリ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/a9ad2fae-08de-e458-28cb-fd06b43e00e5.png)

### 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/e5d835d9-ffdf-beda-a6b4-d64e779e8cb0.png)

## クエリ１：ページネーション（OFFSETとLIMITによるフィルター）

### 詳細

- 読み取り：　100%

- 4 ノード クラスタ: 5百万顧客レコード (1レコード4KB) 
- 10 ノード クラスタ: 2千5百万顧客レコード
- 20 ノード クラスタ: 5千万顧客レコード

### クエリ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/2ed72880-8e9c-a70b-a6d6-371dc1b12950.png)

### 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/2e130518-e47b-e9bc-9baa-f25a0c370347.png)


## クエリ２：ジョイン（テーブル結合）

### 詳細

- 読み取り：　100%

- 4 ノード クラスタ: 5百万顧客レコード、５百万受注レコード  (1レコード4.5KB)
- 10 ノード クラスタ: 2千5百万顧客レコード、2千5百万受注レコード
- 20 ノード クラスタ: 5千万顧客レコード、5千万受注レコード
- 
### クエリ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/b300d4e9-96e5-fe60-0907-abcbea651086.png)


### 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/34dfd74a-1dae-66d7-fb4d-aec7647500da.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/593a9ff7-8be8-4592-0cde-07c90848edcc.png)

# 最後に

冒頭に本稿の目的として「将来のベンチマーク実施のためのベースライン設定の試みとして」と書きました。

ベンチマーク規格としては、他にTransaction Processing Performance Councilという組織によるTPCベンチマークがあります。TPCベンチマークには、TPC-C、TPC-H、TPC-R、TPC-Wといった種類があり、OLTP/業務系システムを想定したワークロード(更新中心)を計るTPC-Cと、OLAP/集計性能(OLAP/情報系システムを想定したワークロード(集計中心)を測るTPC-Hが代表的といえそうです。TPC-HとTPC-Rは意思決定支援/DWH処理向け、TPC-WはWebベースでトランザクション処理する電子商取引システム向けと位置付けられています。

[YCSB](https://en.wikipedia.org/wiki/YCSB)や、TPCは、比較のためにデータベースの処理内容の標準化を提供している、と言えるかと思います。性能評価実行のための環境については、公開されているツールもありますが、全く手を加えずに利用可能とはいえないようです。そもそも、それぞれのツールの扱っているデータベースは限定されていますし、最新バージョンへの対応が行われているわけでもありません。そのような状況で、特殊な（一般性のない）ツールに合わせて、修正やスクリプトを追加するための労力を裂くことには、疑問を感じます。

自分自身の関心としては、クライアント側の処理を共通化することで、異なる条件・環境での性能を比較可能とすることを考えています。その意味で、シンプルなデータ入出力を提供するRESTサーバーとしてWEBアプリケーションを構築し、以下のようなWEBサーバ性能計測ツールを用いることが考えられます。

- Apache Bench
- Apache JMeter
- httperf
- weighttp

例えば、Restサーバーの実装としては、[Spring Data](https://spring.pleiades.io/projects/spring-data)を使うことによって、データベースアクセスの手法についても、それぞれのデータベースの標準的な手法を使っていることを示すことができるかもしれません。またSpring Dataは、[Spring Data R2DBC](https://spring.pleiades.io/projects/spring-data-r2dbc)のように、リアクティブプログラミングモデルにも対応しているため、リアクティブ（非ブロッキング）API同士の比較が可能という意味でも、公平性があるように思われます。

具体的な性能検証の実施にむけて、また別の記事で、考察（そして実際の実行）を進められればと考えています。

# 参考情報

[TPCベンチマーク基礎講座](https://xtech.nikkei.com/it/free/NT/WinColumn/20030408/1/)

[Apache Benchでサクッと性能テスト](https://qiita.com/flexfirm/items/ac5a2f53cfa933a37192)