データベース
 Computer >> コンピューター >  >> プログラミング >> データベース

意外な組み合わせ:MongoDBとMySQLの共存戦略

データストアの選択肢とその組み合わせの豊富さは、もはや「ワン・サイズ・フィッツ・オール(一つで全てに対応)」なデータストアの世界ではないことを証明しています。

今日では、SQLデータストア(MySQL、PostgreSQL、Oracle、SQL Serverなど)とNoSQLデータストア(MongoDB、CouchDB、Neo4jなど)を組み合わせて使う明確な理由があります。エンタープライズにおいてOracleが依然としてシステム・オブ・レコード(信頼性の高い基幹データベース)として好まれる存在である一方で、それが唯一の選択肢ではなくなりました。

開発者たちは、SQLとNoSQLを組み合わせて問題を解決し始めています——時にはDBAやIT部門の意向に反してでさえ。

仕事に適したツールを選ぶ

現代のデータストアは大きく分けて5つのカテゴリに分類されます:カラムファミリ、ドキュメント、グラフ、キー・バリュー、そしてリレーショナルです。「ポリグロット永続化(Polyglot Persistence)」とは、文字通り「複数の言語を使ってデータを格納・永続化する」ことを意味します。より実用的な言葉で言えば、同じアプリケーション内でCypher、JSON、SQL、その他さまざまなクエリ言語を使ってデータにアクセスすることを指します。

開発者が持続性のニーズにピンポイントで対応するより良いツールを求める中で、これら異なるデータストアとそれらの言語を使い分けることがますます一般的になっています。

SadalageとFowlerは『NoSQL Distilled』の中で、ポリグロット永続化の必要性について次のように述べています:

異なるデータベースは、異なる問題を解決するために設計されています。 単一のデータベースエンジンをすべての要件に使おうとすると、たいていパフォーマンスの出ない解決策になります。トランザクションデータの格納、セッション情報のキャッシュ、顧客とその友人が購入した製品のグラフ探索は、本質的に異なる問題なのです。

データの関係性について考えてみましょう。 RDBMSは「関係性が存在すること」を強制するのに優れています。 しかし、関係性を「発見」したい場合や、同じオブジェクトに属するデータを別テーブルから探し出す必要がある場合、RDBMSの利用は難しくなります。

データストアの選択は、以下の2つの基準に帰着します:

  1. 格納されるデータの構造
  2. データとやり取りするために使われるクエリ

データのクエリ方法が変われば、データの構造化の仕方も変わります。上述の通り、リレーショナルデータストアは関連エンティティの強制には優れていますが、それらエンティティ間の他の関係性を発見する必要が出た瞬間に邪魔になります。

以下では、MongoDBを使ったCraigslistのデータアーカイブというユースケースを取り上げ、彼らがどのように実現したかを推測してみます。

登場人物:MongoDB、MySQL、そしてCraigslist

MongoDB

MongoDBは、MySQLに代わるお気に入りのNoSQLデータベースとなっています。その利点は数多く、スケーラビリティ、オートシャーディング、今日の人気プログラミング言語向けのネイティブバインディングの提供などが挙げられます。MongoDBとリレーショナルデータストアの核心的な違いは、データについてどのように考え、どう格納するかという点にあります。

外部キー制約を持つテーブルの集合で関係性を強制するのではなく、MongoDBではデータをドキュメントの集合として表現します。ドキュメントは、リレーショナルデータ構造における行やタプルに「類似しています(ただし同一ではありません)」。ドキュメントデータストアの分類と命名は、データがJSONドキュメントとして格納され、コレクションにグループ化されることから直接来ています。これらのドキュメントの深さは無制限で、クエリやインデックスによって完全に検査可能です。通常、リレーショナルデータベース向けに適切なデータを非正規化することで、MongoDB向けの良いデータ表現に到達できます。もちろん、実行したい特定のクエリがこのプロセスを導くべきです。

MongoDBのニュアンスについてより詳細な情報は、MongoDBの公式サイトで確認できます。

MySQL

誰もが知り、愛する古典的な存在、MySQLはコンピューティングの時間スケールで言えば「夜明け前」から存在し、最も広く使われているDBMSです。その提供する機能により、アプリケーションは約10年にわたってデータをモデリングし、多くのビジネス目的におけるシステム・オブ・レコードとして機能してきました。今日、「リレーショナルデータベース」と言えば、多くの人はMySQLを思い浮かべるでしょう。

MySQLは、古典的なリレーショナルデータモデルの実装を提供します。型理論と集合論を用いて、1970年代にE.F. Coddによって開発されました。プログラムによる正規化、計画、内省が可能であることは、リレーショナルデータシステムを極めて人気のあるものにしています。実際、これらのデータストアは、データを一般的な方法でモデリングする問題を解決し続けるため、今も好まれています。

Craigslist

MongoDBとMySQLの両方を採用しているよく知られたオンラインビジネスの一つがCraigslistです。両データストアの並行採用についてはMongoDBのケーススタディで概説されていますが、ここでは要点をまとめます。

規制要件により、Craigslistは分類広告のデジタル記録を保持しなければなりません。1日あたり100万件以上の新規分類広告があるため、保持すべきデータ量は膨大です。アクティブな分類広告の情報はすべてMySQLデータストアで保持し、アーカイブ済みデータ(おそらく30日以上経過したもの)はMongoDBで格納しています。通常のビジネス変更の一環として、格納データのスキーマが変更されます。アーカイブデータにMongoDBを使うことで、Craigslistはデータを効果的にセグメント化し、スキーマ移行に伴う問題を軽減できました。

思考実験として、CraigslistのようなアプリケーションでMongoDBとMySQLを併用する一例の実装を推測してみましょう。これが実際のCraigslistの実装である可能性は極めて低いですが、馴染み深い高トランザクションなウェブサイトにおいて、複数のデータストアがどのように協調できるかを考える上で興味深い視点となります。

どうやって実現するか

開発者やエンジニアは、巨大なSQLデータベースでスキーマ更新を行う際、必ず問題に直面します。これは、スキーマ更新適用後に「修正」しなければならないデータ量を減らすことで回避できます。これらの移行やスキーマ更新の苦痛は、一般的にデータ量に比例して増大します。

この例では、Craigslistが出品者から新しい情報を取得する必要が生じたと想像してください。スキーマ更新が必要になるため、影響を受けるデータサイズを最小化して更新の苦痛を減らしたいはずです。

このアーカイブと移行のサイクルを数回繰り返すと、単一の場所に保存するにはスキーマレスなデータストアを必要とする、かなりの量の異種混在データが蓄積されます。MongoDBはこの要件に非常に適しています。

分類広告のスキーマ例は以下のようになります(craigslist-cloneから恥ずかしながら再実装):

CREATE TABLE `classifieds` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(75) COLLATE utf8_unicode_ci DEFAULT NULL,
  `description` text COLLATE utf8_unicode_ci,
  `location` varchar(75) COLLATE utf8_unicode_ci DEFAULT NULL,
  `adtype` varchar(1) COLLATE utf8_unicode_ci DEFAULT 'O',
  `email` varchar(75) COLLATE utf8_unicode_ci DEFAULT NULL,
  `phone` varchar(75) COLLATE utf8_unicode_ci DEFAULT NULL,
  `activation_code` varchar(40) COLLATE utf8_unicode_ci DEFAULT NULL,
  `status` tinyint(4) DEFAULT '0',
  `category_id` int(11) DEFAULT NULL,
  `subcategory_id` int(11) DEFAULT NULL,
  `city_id` int(11) DEFAULT NULL,
  `permalink` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `image_file_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `image_content_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `image_file_size` int(11) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

もちろん、実際のCraigslistは異なるスキーマを持っているでしょうし、少なくとも現在のスキーマは複数のイテレーションを経て発見されたものです。また、将来的にデータの構成方法を変え、スキーマを再変更する可能性もあります。created_atupdated_atフィールドを使って、MySQLに格納されたデータをいつアーカイブするかを決めたいとします。

Craigslistの分類広告ポリシーでは、広告がウェブサイト上で2週間利用可能で、その後も利用可能だが必ずしもアクティブ(MySQL内)である必要はない、と仮定しましょう。これを実現するために、SQLAlchemyとPyMongoの組み合わせを使います:

まず、MySQLインスタンスからデータを取り出す必要があります。SQLAlchemyを使ってこれを実現し、スキーマを内省させます(これにより、このコードがこの目的でより再利用しやすくなります)。

import sqlalchemy.schema

m = sqlalchemy.schema.MetaData("mysql://root:I'm required why?@192.0.2.3/craigslist")
m.reflect()

print m.tables.keys()

データベースへの接続に成功していれば、キー(カラム名)が標準的なPython形式で出力されます:[u'classifieds', u'cities', u'subcategories', u'categories']。まだこれらのテーブルから個々のデータ項目を取り出す必要があります。それらを確認できるだけでなく、SQLAlchemyはこれをずっと簡単にするエレガントなインターフェースも提供しています。

これで内省によりテーブル定義が得られました。オブジェクトマップを作成するか、テーブルをクエリして含まれるデータ項目を取得します。以下のクエリで分類広告をデータストアから抽出します(他のテーブルは読者の演習として残します)。

import sqlalchemy.sql

connection = m.bind.connect()

classifieds = m.tables['classifieds']

query = classifieds.select()

result = connection.execute(query)

for row in result:
    print dict(row.items())

このスニペットはMySQL接続を使ってすべての分類広告をクエリします。他のテーブルも処理してデータを非正規化し、MongoDBのドキュメントスタイルにより適合させることも容易です。ただし、このデモではclassifiedsテーブルのみに焦点を当てます。この時点で、classifiedsテーブルの個々の項目すべてが辞書に変換されました。これは、PyMongo経由でMongoDBに挿入するためにまさに必要な形式です。

次のサンプルは、PyMongoに接続して辞書を挿入する方法を示しています:

import pymongo

client = pymongo.MongoClient('mongodb://192.0.2.2')

db = client['craigslist']
collection = db['classifieds']
collection.insert({'_id': 1})

ここで一つ問題があります。SQLAlchemyとMongoDBでIDのキー指定が異なるのです。SQLAlchemyはidをキーとして使うのに対し、MongoDBは_idを使います。したがって、このキーを変換する必要があります(非常に簡単なプロセスです):classified['_id'] = classified.pop('id')

結論

SQLとNoSQLのデータストアは、しばしば「どちらか一方のみ」の選択肢として描かれますが、実際には複雑な問題を解決するために一緒に使うことができます。この例を通じて、MongoDBとMySQLの両方を利用するシステムには、ごく少量のコードしか必要ないことがわかりました。実際、これはデーモン化するのではなく、cronで駆動することさえ可能です。

複数のデータストアを利用する難しさは、必ずしも翻訳コードや移行コードの開発にあるわけではありません。むしろ、追加システムの管理が難易度を上げます。1つのデータストアを維持するだけでも専門知識(DBAやデータストア知識を持つ管理者)が必要ですが、データストアを増やすにつれてこの専門知識への需要も高まります。

ビジネスサイドは、複数のデータストアを運用する価値があるかどうかを判断しなければなりません。これらの課題を緩和するテクノロジーも存在します。

ChefやSaltのような自動化技術に加え、RackspaceによるマネージドMongoDBサービス「ObjectRocket」のようなサービスベンダーを活用することでも、この課題を緩和できます。複雑性が増すことは事実ですが、もし問題が複数のデータストアの使用によってメリットを得られるなら、思い込みでそれらの解決策の検討を止めてはいけません。

  1. ObjectRocketがMongoDBを常に正常かつ利用可能な状態に保つ仕組み

    ※本記事は2020年11月にObjectRocket.com/blogで公開された内容をもとに再編集したものです。 Rackspaceでは、ObjectRocketチームがお客様のMongoDB®データベースの運用管理を全面的にサポートします。災害復旧(DR)、レプリケーション、耐障害性、そして高可用性(HA)まで、MongoDBデータベースの安定稼働に必要な機能をワンストップで提供しています。 はじめに ObjectRocketでは現在、シャーディング構成とレプリカセット構成の2種類のMongoDBインスタンスを選択できます。しかし内部では、データの冗長性と耐障害性を確保するために、常に3

  2. DBAとデータアーキテクトの進化:データ革命時代に求められる新スキルセット

    企業の顧客、従業員、パートナーが使いやすいシステムを通じてデータにスムーズにアクセスできるとき、その陰には2人のプロフェッショナルの存在があります。それがデータベース管理者(DBA)とデータアーキテクトです。数千人、さらには数百万人規模のユーザーに対して、堅牢に構築されたデータベースを安定かつ安全に稼働させ続けることは重大な責任であり、あらゆる業界の企業が、利用者のニーズに応えるデータネットワークの設計と監視をこの2つの役割に依存しています。ビジネス界におけるデータ需要が急増するにつれ、最新のデータベース技術に対応するために必要なスキルも拡大し続けています。以下のインフォグラフィックでは、これ