Couchbaseにおけるデータ管理：メモリファーストアーキテクチャーが、ハイパフォーマンスを実現している裏側、それをどのように使うべきか

# はじめに

下記の記事では、Couchbaseの、他のインメモリDBと比べた時の独自の特徴を、メモリ「ファースト」アーキテクチャーとして、説明しました。
[インメモリDBという選択肢（Oracle Coherence、Redis、そしてCouchbase) ①データ永続化との関係](https://qiita.com/yoshiyuki_kono/items/cf156988239462287d63)

「インメモリDB」に対して、「メモリにデータを保存して高いパフォーマンスを実現するのは確かに結構なこと（論理的には十分理解の範囲）」だが、（実務的には）データベースを選定する立場として、「データの全てをメモリに保存することは、データ量およびコストの上で、現実的ではない」あるいは「そのような特殊な技術を使うための学習コストを払う程の価値（ニーズ）はない」と考えることは珍しくないのではないかと思います。

Couchbaseのメモリファーストアーキテクチャーは、そのような（メモリ利用による性能追求の要件がない）ケースであっても、JSONデータの扱いやすさや、クラスター間のデータの双方向の複製の容易さ、モバイルアプリケーションのための機能の充実といったメリットに加え、パフォーマンスについても、特別高い学習コストを払わずとも、他のNoSQL(JSON)データベースと変わらない（より低い）学習コストのみで、コスト制約・要件に応じて、高い性能を享受することが可能です。

この記事では、その背景と、ユーザにとっての選択肢を具体的に見ていきます。

# バケット

Couchbase Serverでは、データはバケットに保存されます。
バケットにはCouchbaseバケットと、Ephemeralバケットの２種類があります（Couchbaseタイプがデフォルト）。
Couchbaseバケットは、ディスクに対して非同期でデータの永続化を行います。
Couchbase Serverは、可能な限りすべてのデータ（アクティブ、およびレプリカ含め）をメモリに保持しようとします。

# Couchbaseにおけるデータ管理

## ドキュメント構造

まず、Couchbaseのデータの格納単位である、ドキュメントの構造を説明します。

### ドキュメントキー（またはドキュメントID）
- 可変長
 - 最大250バイト
- 値は、バケット内において一意

### ドキュメントメタデータ
- 固定長
 - Couchbaseバケットに保存されているドキュメントの場合：56バイト
 - Ephemeralバケットに保存されているドキュメントの場合：72バイト

###ドキュメント値
- 可変長
 - 最大20MB
 - 通常はJSONであることを想定しているが、バイナリデータの保存が可能


![Picture1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/a6c65d35-da65-1395-808d-6e5960928dc7.png)


## メモリからのデータ排出(Ejection)

メモリ内のデータがバケットの（ハイ・ウォーターマークと呼ばれる）メモリクォータの85％に達した場合、サーバーは、最近使用されていないものの一部をメモリから排出（削除）し始めます。データ排出プロセスは、メモリ内データがバケットメモリクォータの75％（ロー・ウォーターマークと呼ばれます）を下回るまで続きます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/1e8536ac-35f8-647d-1f49-40ae92153ce0.png)

画像は、[Couchbase公式ドキュメント Ejection](https://docs.couchbase.com/server/current/learn/buckets-memory-and-storage/memory.html)より引用。

## 排出方法(Ejection Method)

### 設定

排出方法として、Value-OnlyとFullの何かを選択可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/97cf18e6-51c1-d023-3836-dac0fc15ef14.png)

### 変更の影響

排出方法の決定は、バケット作成時に行うのみではなく、作成後の変更も可能です。
ただし、この変更は、（後から変更可能なバケット設定の中でも珍しく）、バケットのリスタート（設定変更時に暗黙に行われる）を必要とすることに注意が必要です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/6291246a-7fa6-50b8-fe5c-4277abd4846f.png)

## 排出方法概要
### Value-only
排出の際、値のみが排出され、キーとメタデータはメモリに残ります。
より多くのメモリが必要ですが、最高のパフォーマンスを提供します。

### Full
排出の際、すべて（キー、メタデータ、値を含む）が排出されます。
メモリ要件を軽減します。

## 排出方法の選択
要件に応じて排出方法を選択することになるのは当然ですが、以下の二つのデータ保存要件の性格の違いによって、対応が考えられます。

### データ量は一定であることを想定（増加した過去データを別の場所へ退避する）

この場合には、事前の計画に基づいたリソース設計により、*Value-only*を選択することができ、最高のパフォーマンスを実現することができます。

### データ量は経年的に増加することを想定

この場合、一般的なデータベースの場合、ディスクの容量に注目していれば十分だったとすると、データ数に応じて増えるメタデータがメモリ容量に与えるインパクトについても計画する必要があります。
*Full*を選択することで、データ数（メタデータ量）増加によるインパクト、つまり一般的なデータベースの場合考慮する必要がなかった検討要素を回避することができます。

# 監視と警告

事前の計画が基本である一方、運用中の監視も重要な要素です。

以下は、WEB管理コンソール上の監視項目のイメージです（同じ内容をコマンドラインや、外部監視システムとの連携で利用することができます）。データ全体のサイズ（上）に加え、メタデータのサイズ（下）を監視することができkます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/f3f41898-4076-5369-8535-70dc53a73edc.png)


## 警告
バケットのメモリクォータに対して占めるメタデータサイズの割合の超過に対する警告を利用することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/59796525-d3e2-57e4-7bd8-28a8544178a3.png)

# 最後に

本記事では、Couchbaseにおけるデータ管理について、ユーザを前提とした単なる機能説明としてでなく、データベースを選定する際に有益な情報、という観点から整理を試みました。
純粋に技術に対する関心に応えられていれば、それ自体嬉しいことであるのは当然として、本記事がデータベース選定の際の参考になるような情報を提供できているなら幸いです。

# 参考情報

[A Tale of Two Ejection Methods: Value-only vs. Full](https://blog.couchbase.com/a-tale-of-two-ejection-methods-value-only-vs-full/#:~:text=By%20default%2C%20a%20Couchbase%20bucket,in%20memory%20at%20all%20times.)
排出方法にフォーカスしたブログ記事

[The Best Database For Storing Images Might Not Be a Database At All](https://blog.couchbase.com/the-best-database-for-storing-images-might-not-be-a-database-at-all/)
データベース(Couchbase)利用の目的として、（一般によく取り上げられるものの中でも）必ずしも適切でないユースケースもあることを指摘しながら、Couchbaseのデータ管理、排出方法メカニズムとの関係を論じています。