ビッグデータ向けプラットフォームに入門する - NoSQL

こちらのページは[ビッグデータ向けプラットフォームに入門する](https://qiita.com/mito_110/items/0a275ecbddb9fd678ed1)の子記事です。

prev: [ビッグデータ向けプラットフォームに入門する - Hadoop](https://qiita.com/mito_110/items/b83a2e38cef505b306d6)

---

分散処理により、大規模データに対し効率的に集計処理を行えることに触れてきました。
NoSQLを利用することでこの効率的な分散処理をオペレーション用途に活用することができます(一部例外あり)。

いきなり例外ありとか書いてしまいましたが、実際NoSQL="Not only SQL"であり、**一口にNoSQLデータベースと言っても、多種多様なプラットフォームが存在します**。

しかしこれらのプラットフォームは「**分散処理を前提としておりスケールさせることが容易であり、スキーマレスデータを格納できる**」という共通の特徴が挙げられます。
なおスキーマを定義する必要があるApache Cassandra、スケールが困難なグラフDBなどいくつかの例外は挙げられます。
特にグラフDBは他のNoSQLプラットフォームとは著しく特性が異なるため、この後の説明は「グラフDB以外のNoSQL DB」に対するものとなっています。

### オペレーション用途のDBで分散処理を実現するには
そもそもなぜRDBでは処理性能をスケールさせることが困難なのでしょうか。
それは端的に言えば「データの整合性」を重視しているためです。

"relational database"の名の通り、RDBではデータ間の関係性が厳密に定義されており、データを分散配置した場合関係を持つデータが複数のノードにまたがることになります。
このようなデータに対しトランザクション処理を実行した場合、複数のノードを参照し、かつ処理中は他の処理はロックして整合性を保つ必要があります。このため処理を効率的に同時並行で進めることは困難です。
Map/Reduceについての節で触れたとおり、**分散処理では各処理が互いに独立し、並列性が高いことが高い処理性能を持つ上で重要な点となります。**
しかしこのように各処理が互いに影響を与える状態ではオーバーヘッドが増大し、十分な処理性能があげられないことになります。

これに対し、NoSQLでは主に以下の2点によって効率的な分散処理を実現しています。

- **分散させやすいデータ構造をとる**
- **強い厳密性をある程度犠牲にする**

まず、RDBが分散処理の性能を下げているのは、データ間に厳密な関係性が定義されているためです。
そこでより関係が薄く各データがより独立している形式でデータを保持します(具体的な形式は後述)。
さらに、RDBのような完全な整合性を捨て「結果的に合ってる」程度の整合性
(ACID特性と対比してBASE特性という言葉で形容されたりします)を担保することで、
効率的な分散処理を実現しています。

### NoSQLの種類
NoSQLデータベースの種類はデータの格納方法に応じて分類することができます。
現在主に利用されているNoSQLデータベースには4つのタイプがあり、データ構造が単純な順に、

- **キーバリューストア(KVS)**
- **カラムストア**
- **ドキュメントストア**
- **グラフ**

が挙げられます。

![データ処理プラットフォーム入門_素材.003.png](https://qiita-image-store.s3.amazonaws.com/0/303946/a1a37034-d02f-8a82-4d47-216b64bfa79a.png)

#### キーバリューストア
KVSはいわゆる連想配列(map, dictionaryとも)の形式でデータを格納します。
1つのキーに対して1つの値が入るという非常に単純な形式で、キーをもとにデータを取得する処理を非常に高速に行うことができます。

主要なプラットフォーム: DynamoDB、Voldemotoなど。

#### カラムストア
ワイドカラムストアとも呼ばれます。
一般的なRDBのような表形式に近い構造を持ちますが、
このキーに対してはカラムAとBとCの値をもたせる、あのキーに対してはカラムBとCとDとEの値を持たせる、といった具合に保持する値の種類を自由に選択でき、かつカラムの形式も自由に定義できます。

主要なプラットフォーム: Apache Cassandra, Apache HBaseなど。

#### ドキュメントストア
ドキュメントストアでは階層構造のデータを保持できます。
xmlやJSON形式のデータを想像していただけると、データ構造のイメージがつくかと思います。
実際ドキュメントデータベースではJSON構造のデータをそのまま格納することができ、
外部のRestful APIから取得したデータの保持などで威力を発揮します。

主要なプラットフォーム: Apache CouchDB, MongoDBなど。

#### グラフ
ノードとエッジから構成されるグラフ構造でデータを保持します。
上の3つで挙げた「分散させやすい」データ構造と異なるためスケールさせることは困難ですが、
リレーショナルデータモデルでは複雑すぎる関係性を明快に定義でき、
データ間を関係性をもとにたどっていくような検索(経路の検索など)で高い性能を発揮します。

主要なプラットフォーム: Amazon Neptune, Neo4Jなど。

### NoSQLの特徴
#### レイテンシの小ささ
NoSQLはDWHやHadoopとは異なり、オペレーション用途で用いられるプラットフォームです。
データ処理の速さを表す言葉として「スループット」と「レイテンシ」の2つが使われますが、
DWHやHadoopのような集計用途で用いられるプラットフォームは「スループット」の大きさが、
NoSQLのようなオペレーション用のプラットフォームは「レイテンシ」の小ささが重視されています。

**「スループット」は単位時間あたりに処理できるデータの量を示し、
「レイテンシ」は1回の処理が終わるまでの遅延時間を表しています。**
結局何が違うんだという感じですが、HadoopとNoSQLの違いを例に見てみましょう。

Hadoopで何らかの処理を行う場合、各TaskTrackerにタスクを分配し、JVM上でプログラムを立ち上げて、しかもHDFS上ではデータにシーケンシャルにアクセスすることとなります。
すなわち、Hadoop上で処理を行う場合は一定の準備時間が必要であり、
なおかつ実際にアクセスしたいデータ以外にもアクセスする可能性があるということになります。

大量のデータを対象とした集計処理を行うような場合はこのような準備時間は相対的に小さくなりますが、
たった一つのレコードを撮ってくる場合でも同様の準備時間が必要となります。

すなわち、**大量のデータに対する集計を行う場合の単位時間あたりに処理できるデータ量は大きいものの、
1回の処理あたりの遅延は数十秒から数分にもなります**。
これが「スループット」が大きく、かつ「レイテンシ」も大きいということです。

一方KVSやドキュメントDBのようなNoSQLではデータが単純な形式で格納されており、
特定の1件のデータをとってくることを効率的に実行できます。
このため**NoSQLでは数ミリ秒程度の非常に小さな「レイテンシ」となります**。

一方集計処理を行う場合は、列指向のような集計に適した形式でデータが格納されておらず、
特定のカラムにのみアクセスして集計を行うといったことはできません。
このため大量のデータに対する集計処理を行うような場合は時間がかかり、
「スループット」は相対的に小さくなることとなります。

オペレーション用途のDBでは、「レイテンシ」が小さいことが重視されます。
1件のデータにアクセスするために十秒単位での時間がかかっていたらサービスとしては成り立ちません。
これがNoSQLがオペレーション用途のプラットフォームであるといえる所以です。

#### スキーマレス
NoSQLでは処理を分散させやすいように、データ間の依存が少ない構造でデータを格納していますが、
関連性を厳密に定義しない、というのにはいい面もあります。

RDBにデータを入れようとした場合、まずテーブルのスキーマを定義する必要があります。
複雑な関連性を持つデータを格納するテーブルを作る場合スキーマを定義するのは簡単ではありませんし、
あとからスキーマの定義を変更することも非常に大変です。

しかしKVSやドキュメントDBではこのようなスキーマを定義する必要がありません。
データをとりあえず入れるということが可能ですし、**あとからデータ構造を変えたい場合も柔軟に変更が可能です**。
このようなDBをスキーマレスDBといったりします。

例えば外部のAPIを叩いて持ってきたデータを格納するような場合、この利点は顕著にあらわれます。
ドキュメントDBではレスポンスとして返ってくるJSONをそのまま入れることが可能ですし、
頻繁に仕様の変わるAPIにもすぐに対応することができ、開発をスムーズに進めることが可能です。

このようにNoSQLではデータの整合性についてはRDBに一歩劣るものの、
開発速度や柔軟な仕様変更が求められる場合にも力を発揮します。