「リソース」の棲処
- ここまでを振り返ると、
- Webサーバの一類型として、HTTPリクエストを入力に、プログラムに基づいた処理を行い、
動的なコンテンツを生成したりするのがアプリケーションサーバ
- APIの設計には、ベースとするプロトコルの違いや、RESTfulなどのパターンなど、複数の流儀がある
- 「状態」や、「リソース」といった概念が登場する
- 「リソース」と無邪気に言い放ってきたが、リソースってなんだろうか
- 古典的な静的ファイルを送信するWebサーバに立ち戻ると、リソース≒ファイルだった
- しかしアプリケーションサーバでは、必ずしもファイルとリソースは1対1対応しない
- Unix系でもWindowsでも、 ファイルシステム; file system は、
- ツリー状のデータ構造
- 一意にファイルを特定する パス; path
- 作成時刻、更新時刻、バイトサイズなどのメタデータ
- 中身のデータの保持
- といった特徴は共通で、それ自体汎用的で欠かせない体系なのだが、
Webアプリケーションを実装するにあたってはそれだけでは足りないことが多い
- リソースとして保存したい事項は様々あるので、データの中身を 構造化 したい
- 一つ一つのデータ点が、特定の値の組み合わせを持つよう規定できる
- たとえば、サービスのユーザ情報だったら
id, email, family_name, given_name
など
- 構造にそぐわないデータ入力は拒否するなど、検証・強制できる
- 生のファイルシステムにおいては、ファイルは任意のデータ
- 構造化されたデータの中身をもとに、 問い合わせ, クエリ; query あるいは 検索; search したい
- 任意のファイル群相手では、求める内容を含むものを一意に見つけ出すことは難しい
- バイナリファイルであれば、内部構造を解釈する方法を知らなければならない
- テキストファイルでも、 encoding によっては読み出し方が異なる
- ファイルは 暗号化 されていてそのままでは読めないかもしれない
- クエリや検索が 時間的・空間的に高効率(time and spatial efficiency) で行えるようなシステムであって欲しい
- 「目的とする文字列を含む行をテキストファイルから見つけ出す」といった原始的な操作なら様々な方法がある(例えば grep)
- が、単なるgrepなどは 線形時間; linear time で動く
- つまりファイル数(行数)が増えるごとに、検索完了までにかかる時間は線形で伸びる
- ついでにqueryはできたら統一的な文法で簡単に書きたいし、なんなら複雑な条件を組み合わせたりもしたい
データベース
- まさに データベース; database (DB) の必要とされる世界
- このような要求はWebの誕生以前からあり、豊富な知見、研究、技術の蓄積がある
- 豊富であるということは当然取っ掛かりがつかみにくい世界でもある
- 多くのアプリケーションサーバは、何処かにあるリソースを組み合わせて機能を実現するが、DBはその主たる棲処の一つ
- DB管理システム(database management system; DBMS)も様々存在するが、おおよその共通項としては、
- ファイルシステム上で動作し、最終的にデータ実体はファイルとして保存する
- ただし、保存(永続化)する際のファイル形式と、読み出されるときの形式とは必ずしも対応しない。
そこはDBMSの実装が知っていればいい部分で、利用者側からは隠蔽されている
- Database engine/Storage engineの担当箇所。そのDBMSの性能と密接な関係を持つ
- アプリケーションが取り扱うリソースをどのように表現し、それをどのように(物理的・論理的に)DBに格納するかは長らく研究されてきた
- 関係(リレーショナル)データモデル; Relational data model と、
それに対応した 関係(リレーショナル)データベース; Relational database management system, RDBMS が非常に広範に使用されている
- RDBMSは、「ある程度」標準化された SQL という専用言語(Domain Specific Language; DSL)を利用してデータの操作やクエリを行う
- 「ある程度」というのがキモで、標準化団体による規格は策定されているが、
対応状況がまちまちだったり、製品ごとの独自拡張がたくさんあったりする
- 特定の空間ないし集合(テーブル; table)に属するデータ(レコード; record)は、
特定の値の組み合わせを持つよう強制力のある規定ができる(スキーマ; Schema)
- 製品によっては、「一連の操作がすべて成功するか、(何らかの問題があった場合には)まるごと一切なかったことにできる」
というall-or-nothingな操作を行うことができるものがある
- これを トランザクション; transaction 処理という
- Transaction処理の満たすべき特性を ACID(Atomicity, Consistency, Isolation, Durability) 特性という
- たとえば 電子商取引; E-Commerce でよくある例だと、
「ユーザの保有ポイントを消費し、商品を利用可能にする」といった処理は不可分としたい
- 「ポイントだけ減って、商品が利用できない」といった 部分的失敗; partial failure はユーザ体験を著しく損なう
- 有名なRDBMS: MySQL, PostgresSQL, Oracle Database など
- 一方で、RDBMSだけでは近年のWebアプリケーションの要求に対して最適な性能・信頼性を担保できないケースが近年頻出した
- そこで現れてきたのが NoSQL; Not only SQL と呼ばれるデータベースの類型
- RDBMSの既存製品が持っていた特徴の一部を諦める・弱めることを受け容れつつ、
- 別の部分の性能・信頼性を向上させるアプローチを取る
- Key-Value Store; KVS
- 「キーに対する値」、という単純なペアを基礎としてデータを保持するもの
- データの複雑な構造化や、それに対するSQLを用いた複雑なクエリなどは(ある程度)諦める代わりに高速で、
分散; distributed 処理の適用がし易い
- データを永続化せず、メモリ内だけで実現するものもある
- 有名なKVS: Amazon Dynamo, RiakKV, Redis(in-memory) など
- ドキュメント指向DB; Document-oriented database
- JSONなどの「ドキュメント」形式で、構造化されているが、固定のスキーマに縛られないデータを投入できる
- 一つのドキュメント内でデータの階層化なども行える
- SQLほど標準化はされていないが、それぞれの製品ごとにクエリのための文法を持つことが多い
- 完全なACIDトランザクションをサポートしないものが多いが、より弱い仮定の機能や保証を持つことはある
- 結果整合性; eventual consistency
- 楽観ロック; optimistic lock/optimistic concurrency control
- 有名なドキュメント指向DB: Amazon DynamoDB, MongoDB, CouchDB, MarkLogic など
- 全文検索エンジン; Full-text search engine もドキュメント指向DBの一種とみなすこともある
- 列指向DB; Columnar database
- グラフDB; Graph database
インデックス
- ところで、RDBMSにしろNoSQLにしろ、目的とするデータの読み出しに線形時間(O(N))かかったのでは意味がない
- たとえば、ユーザIDを元にしてそのユーザの情報を取得したいときに、
ユーザが合計100万人いるなら最悪ケースで100万件総なめしないと対象ユーザが見つからない、などというシステムは使えない
- ほとんどのDBは、データの取り出しを線形時間未満で行うために インデックス; index という補助的なデータ空間を持つ
- 「データが持つ項目(属性)の一つ(index key)」から、
「そのデータが永続化されている物理的な空間位置」を高速に解決できる、まさに「索引」
- 平衡木; Balanced tree の一種(B-tree や B+ tree など)や
ハッシュテーブル; Hash table を使って実装される
- O(log(N)) で目的データを取得・更新・削除できるものが多い
- ある項目に同じ値を持つデータはその集合内に1つしか存在できない(一意性; uniqueness)といった制約も、
その項目をkeyとするindexを事前に構築して利用することで達成する
- DBを「正しく」「効率的に」使うにはインデックスの存在を意識しておくのが肝心
- アプリケーションで取り扱うデータ構造を設計する際も、DBを効率良く使うことを念頭に置きながら考える