前回は、サービスの成長と分岐点であるWebサービスとネットワークについてまとめた。ここでは、大規模サービスに対応するための実践技術4選について解説する。
1 ジョブキューシステム
Webサービスとリクエスト
Webサービスでは、リクエストは基本的に同期的に実行される。そのため、成長を続けるWebサービスでは、データが徐々に蓄積され、データの追加処理、更新処理が重くなってくる。その場合に、ジョブキューシステムを使用することで後回しにできる処理を非同期に実行することができ、ユーザ体験を改善することができる。
ジョブキューシステム入門
ジョブキューシステムとは、ジョブキューに実行させたい処理(ジョブ)を登録し、ワーカーがキューからジョブを取り出して実際に処理するものである。ジョブキューによって、一時的に大量の処理が登録されたときの負荷の変動を吸収することができる。基本的な処理の流れは以下の3つである。
- クライアント(Webアプリケーション):ジョブを投入する。ジョブを投入した後は、処理を続行することができる
- ジョブキュー:ジョブを蓄える
- ワーカー:ジョブキューを参照し、未実行のジョブを取り出してジョブを実行する
はてなでのジョブキューシステム
はてなではジョブキューシステムとして、Perlで実装されたTheSchwartzとGearmanを使用している。
- TheSchwartz:ジョブキューにMySQLのようなRDBMSを使用するジョブキューシステム。高い信頼性と安定性を確保している
- Gearman:ジョブキューに独自デーモンを使用しジョブの情報をオンメモリで格納することで、性能を確保している。クライアントからジョブを投入する際に以下の3つのパターンを取ることができる。同期的に順番に処理、同期的に並列に処理、非同期的にバックグランドで処理
- WorkerManagerによるワーカーの管理:はてな自前開発機能。TheScwartzとGearmanをラッピングし、できるだけ少ない変更で両方に対応させるなど
ログからの分析
WorkerManagerでは、ワーカーがジョブを処理した際のタイムスタンプを記録する。また、TheSchewartzの場合はジョブの処理時間(process)と、ジョブが投入されてから実際に処理が行われるまでの遅延時間(delay)を記録する。
2 ストレージの選択
増大するデータをどう保存するか
ストレージとは、アプリケーションのデータを永続的に、もしくは一時的に保存するための機能という意味で使っている。データの種類にも本質的に失うことができないオリジナルデータから再生成可能な加工データ、失われてもパフォーマンス上の問題以外は発生しないキャッシュなどがある。データの特性以外にも、データのサイズや更新頻度、成長速度というものも重要となる。
ストレージ選択の前提となる条件
ストレージ選択の前提条件として、アプリケーションからのアクセスパターンを知ることが重要である。アクセスパターンとして、以下の6つの指標が選択の重要な判断ポイントとなる。
- 平均サイズ
- 最大サイズ
- 新規追加頻度
- 更新頻度
- 削除頻度
- 参照頻度
ストレージの種類
現在使用可能なストレージの種類は以下の4つに分けられる。
- RDBMS:MsSQL、PostgreSQLなど
- 分散key-valueストア:memcached、TokyoTyrantなど
- 分散ファイルシステム:MogileFS、GlusterFS、Lustre
- その他のストレージ:NFS系分散ファイルシステム、DRBD、HDFS
RDBMS
RDBMS(Relational Database Management System)とは、表形式でデータを保存し、多くはSQL言語によりデータ操作を行うシステムである。様々なデータを保存することや、強力な問い合わせをすることができ、最も汎用性の高いストレージである。主なオープンソース実装にはMySQLやPostgreSQLなどがあるが、ここではMySQLについて説明する。
MySQLの構造はSQLを解釈し実行する機能ブロックと、実際にデータを保管する機能ブロック(ストレージエンジン)が分離していることが特徴的である。主なストレージエンジンにはMyISAMとInnoDBがあり、現在開発中のものにMariaがある。MyISAMは現在の最新版であるMySQL 5.1の標準ストレージエンジンとなっている。
MyISAMは1テーブルが実際のファイルシステム上で3つのファイル(定義・インデックス・データ)として表現される。一方、DBプロセスが異常終了すると、テーブルが破損する可能性が高かったり、更新が多い用途には性能的に不利であるなどのデメリットもある。
InnoDBは、MyISAMとは対照的なストレージで、以下のようなメリット・デメリットがある。メリットはストレージエンジン全体で事前に定義した少数のファイルにデータを保存する、トランザクションに対応する、異常終了したときのリカバリ機能があるなどである。デメリットは起動・停止がデータ量によっては数分単位でかかるなどがある。
MariaはMyISAMの後継として開発されているストレージエンジンで、現在ベータ版が公開されている。トランザクション機能と異常終了時のリカバリ機能を加えたもので、MyISAMの弱点が大きく補われている。
MyISAMとInnoDBの比較では、アクセスパターンが追記しかしない場合とSELECT COUNT(*)を使用する場合にはMyISAMが、更新頻度が高い場合とトランザクションが必要な場合にはInnoDBが適している。
分散key-valueストア
key-valueストアは、keyとvalueのペアを保存するためのシンプルなストレージであり、分散key-valueストアはこのkey-valueストアをネットワーク対応させることで、多数のサーバにスケールさせる機能を持ったものである。RDBMSに比べて機能的には劣るが、パフォーマンスが1桁〜2桁上となるのが特徴である。
key-valueストアで最も有名な実装はmemcachedである。memcachedはファイルシステムを使用せずオンメモリで動作するため、極めて高速に動作し、世界中で広く使われている。ただし再起動するとデータがすべて消えてしまう。この適正がうまく働くデータはキャッシュデータである。TokyoTyrantは、ディスク上にDBファイルを持つkey-valueストアの実装で、再起動した後もデータが保存されていることが特徴となっている。
分散ファイルシステム
分散ファイルシステムはファイルシステムの特性上、ある程度以上のサイズのデータを保存するのに適している。例えば、MogileFSは比較的小さい大量のファイルを扱うことを目的として、Perlで実装された分散ファイルシステムである。アーキテクチャはメタデータを収容するRDBMS、ストレージサーバ、その間をつなぐ配信サーバから構成される。画像アップロードを受け付けるようなWebアプリケーションに向いている。
その他のストレージ
その他のストレージとして以下の4つを紹介する。
- NFS系分散ファイルシステム:NFSはあるサーバのファイルシステムを他のサーバからマウントして、そのサーバのローカルのファイルシステムと同様に操作できるようにする技術。NFSの改良版としてGlusterFSやLustreなどの実装がある
- WebDAVサーバ:HTTPをベースとしたプロトコルで、アプリケーションレイヤで実装されることが多く、より安定したシステムを構築することができる
- DRBD(Distributed Replicated Block Device):ネットワークレイヤでのRAIDといえる技術。ブロックデバイスレベルで分散・冗長化させることのできる技術で、2台のストレージサーバのブロックデバイスで同期を実現する
- HDFS(Hadoop Distributed File System):Hadoop用(後述)に設計された分散ファイルシステム。ファイルを64MBごとに分割して格納し、数百MB〜数十GBの巨大なデータを格納することを目的としている
ストレージの選択戦略
ストレージの選択戦略は以下の3つの条件が挙げられる。
- データが巨大になるか:NoならMySQL MyISAM
- 検索するときのキーは1つ:Noかつ書き込みが多ければMySQL InnoDB、少なければMySQL MyISAM
- メディア:YesならMogileFS、Noかつ消えてもいいならmemcache、だめならTokyoTyrant
3 キャッシュシステム
Webアプリケーションの負荷とプロキシ/キャッシュシステム
Webアプリケーションの負荷が徐々に増大し、システム容量が不足してきたときはHTTPレベルのキャッシュを行うHTTPアクセラレータを使用することで、低コストで効果の高い対策ができることもある。HTTPアクセスを高速化するHTTPアクセラレータは、大きくフォワードプロキシとリバースプロキシの2種類がある。フォワードプロキシはクライアントが外部のサーバにアクセスする際に挟むプロキシで、リバースプロキシは逆に外部のクライアントが内部のサーバにアクセスする際に挟まれるプロキシである。
リバースプロキシキャッシュサーバの実装として最も有名なものはSquidである。Squidは1990年代にフォワードプロキシとして開発されたもので、HTTP、HTTPS、FTP用の多機能プロキシである。極めて強力なキャッシュ機能を備えていることを最大の特徴としている。一方、VarnishはFreeBSDの開発者であるPoul Henning-Kamp氏によって開発されている高性能HTTPアクセラレータである。Squidより高速に動作することが特徴である。
Squid
前提として、リバースプロキシとAPサーバの2台による構成を考えてみる。この構成でキャッシュサーバを導入する場合、リバースプロキシとAPサーバの間に配置する。これにより、リバースプロキシからAPサーバへ転送されていたリクエストの一部をキャッシュサーバで処理することができるようになり、システム全体の性能を向上させることができる。
キャッシュサーバを組み込むメリットは、安定的にリクエストが発生している平常時の効果と、一部のコンテンツに異常にリクエストが発生するアクセス集中時の効果の2つがある。その他の工夫および注意点は以下の通り。
- 複数台で分散する:Squidサーバを2台並べることで冗長性を持たせることができる。連携にはICP(Inter-Cache Protocol)を使用することが基本
- 二段構成のキャッシュサーバ:CARP(Cache Array Routing Protocol)でスケールさせる
- COSS(Cyclic Object storage system)サイズの決定方法:1秒あたりに保存されるオブジェクト数×オブジェクトの平均サイズ×オブジェクトの平均有効時間(秒)
- 投入時の注意:事前に普段流れているリクエストを流してウォームアップを済ませておく
Varnish
Varnishはリバースプロキシとしてのキャッシュサーバに特化した実装であり、Squidより高い性能を確保することができる。高速化を極限まで追求した設計がなされており、特に以下の3点が注意点である。
- オブジェクトは(デフォルトでは)mmap(ファイルやデバイスをメモリにマッピングするシステムコール)によるディスク上のファイルに保存される。またプロセスの再起動でキャッシュはすべて失われる
- 基本的な設定(Listenするポート番号など)はコマンドラインオプションで与え、プロキシとしてのルールは設定ファイル(VCL)に記述する
- 単体ではログをファイルに書き出す機能を備えておらず、共有メモリ上に書き出す
4 計算クラスタ
大量ログデータの並列処理
大規模なWebサービスを運営していると、ログデータも大量に溜まっていく。読み出しや解析といった処理を高速で行うために、並列処理が可能な計算クラスタが必要となる。
MapReduceの計算モデル
MapReduceとは、Googleが2004年に発表した計算モデルで、巨大なデータを高速に並列して処理することを目的としている。その計算システムは、多数の計算ノードから構成されたクラスタと大量のデータを分散して格納するための分散ファイルシステムから構成される。
MapReduceの計算モデルは、キーと値のペアのリストを入力データとし、最終的に値のリストを出力する。計算は基本的にMapステップとReduceステップの2つから構成される。Mapステップ、Reduceステップは以下のように表せる。また、大量の入力データの読み出しが性能のボトルネックとなることが多い。
- Mapステップ:(k1, v1)→list(k2, v2)
- Reduceステップ:(k2, list(v2))→(k2, list(v3))
Hadoop
Hadoopはapacheプロジェクトの1つで、MapReduceのオープンソース実装の1つである。Javaで実装されており、Yahoo! Inc、Facebookをはじめとした大量データを持つ企業で広く使われている。
最後に
最近のWebサービス構築に求められる実践技術には、ジョブキューシステム、ストレージの選択、キャッシュシステム、計算クラスタの4つが挙げられる。それぞれThSchwartzやGearman、RDBMSかkey-valueストアか、SquidやVarnish、そしてHadoopといったものである。
16回にわたり、「大規模サービス技術入門」(技術評論社)についてまとめた。大規模サービスがどのように開発・運用されているかについて、講義と演習を通して学べる良書である。興味がある人は手に取ってみてほしい。
![]() |
[Web開発者のための]大規模サービス技術入門 ―データ構造、メモリ、OS、DB、サーバ/インフラ (WEB DB PRESS plusシリーズ) |