Perl Hackers Hub

第9回 高速なWeb APIの実装とテスト―Mobage APIを支えるノウハウ(1)

この記事を読むのに必要な時間:およそ 5 分

本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回のハッカーはDeNAの嶋田裕二さんで,テーマは「高速なWeb APIの実装とテスト」です。

Web APIの基礎知識

はじめまして,DeNAMobageオープンプラットフォームのWeb API(以降Mobage API)を実装しているxaicronです。Mobageオープンプラットフォームは,Mobageの機能をWeb APIを通して外部の開発者に公開することにより,ソーシャルゲームをユーザに提供するサービスです。

簡単に説明するとWeb APIとは,HTTPを利用してネットワーク越しに処理を行い,結果を返すしくみです。最近ではJSONJavaScript Object Notationというフォーマットを利用してデータのやりとりをすることが多くなっており,Mobage APIも基本的にはJSONを受け取って処理を行います。

本稿では,Mobage APIを支えるノウハウを解説していきます。まず,Mobage APIのサーバがどのようにして高速にレスポンスを返しているのか,その実装を紹介します。次に,大量にあるデータベース(以降DB)やキャッシュサーバへ効率的にアクセスする方法を説明します。最後に,Web APIサーバの自動テストの書き方についての一例を紹介します。

本稿で登場するすべてのコードは,MySQL 5.1以上,memcached 1.2.5以上,Perl 5.8以上,Linux環境を対象にしています。

高速なWeb APIサーバの実装

Mobage APIは,そのほとんどすべてがPerlで実装されています。ゲームで利用されるWeb APIだけあって処理速度には常に注意して開発しており,だいたい100~300ms(ミリ秒)以内でレスポンスを返すことを目標にしています。ここでは,高速にレスポンスを返すために,実際にどのようなことに気をつけて実装しているのかを紹介します。

既存のフレームワークを使用しない

通常のWebアプリケーションを作成する場合は,Catalystなどの多機能なWebアプリケーションフレームワークWeb Application Framework以降WAF)を使うことが多いでしょう。Catalystを使用すれば,MVCModel-View-Controllerに則ったWebアプリケーションを簡単に書くことができます。

しかしWeb APIは,複数のテンプレートファイルを使ったり,セッションにさまざまな情報を格納したりといった一般的なWebアプリケーションのようなことをあまり行いません。MIMEメディアタイプも,通常のHTMLベースのWebアプリケーションで用いるapplication/x-www-form-urlencoded(HTMLフォーム形式)やtext/html(HTML文書)ではなく,ほとんどの場合にapplication/json(JSON文書)を用いるため,複雑な処理はあまり必要ありません。認証に関しても,古くはBasic認証やDigest認証,WSSEWS-Security Extension認証,最近はOAuth 1.0/2.0注1などでいずれもステートレスなので,セッションを使用することはまれでしょう。

また,既存のWAFではコントローラやビューの処理などが汎用的に作られているため,Web APIでは無駄なオーバーヘッドになってしまうことがあります。現在ではPSGIという仕様やPlackという実装注2があるので,面倒なHTTP周りの部分を考える必要がなく,簡単に独自のWAFを書けるようになりました。既存のWAF上でパフォーマンスチューニングをがんばるよりも自分たちで実装したほうがやりやすい場合があるため,Mobage APIではPlackをベースに,独自の軽量なフレームワークを書いて使用しています。

注1)
OAuthについて詳しくは,WEB+DB PRESS Vol.63『特集3「作って学ぶOAuth認証」⁠p.85)⁠をご覧ください。
注2)
PSGI,Plackについて詳しくは,WEB+DB PRESS Vol.55の本連載第1回「PSGI/Plack─⁠─フレームワークとサーバをつなぐエンジン」をご覧く ださい。gihyo.jpでも公開しています。

O/Rマッパを使用しない

O/RマッパObject/Relational Mapper以降ORM)とは誤解を恐れずに言えば,プログラム上にDBのスキーマ情報やさまざまなメタデータを記述し,DBを意識せずに扱えるようにしたものです。

ORMを使用すれば,SQLをプログラム上に記述しなくてもDBアクセスができるようになります。一見良いことのように思えますが,一般的に次の欠点があると言われています。

  • ORMの書き方を覚えなければならないため,学習コストが高い
  • 発行されるSQLが画一的で,必ずしも効率的とは言えない
  • SELECTの結果などをすべてオブジェクト化するなど,オーバーヘッドが非常に大きい

①②に関してはやり方しだいで解決できますが,Web APIを実装するうえで筆者が最も無視できないと考えているのがです。

そのためMobage APIではORMを使わず,Perlで古くから使われているDBアクセスの汎用モジュールDBIを利用しています。

DBIは高速

現在Perlで最も人気のORMであるDBIx::Class(バージョン0.08127)と,DBI(バージョン1.616)でベンチマークを取ったところ,DBIが5倍も高速であるという結果が出ました注3)⁠これはDBIx::Classがさまざまなオブジェクトを動的に生成しテーブルの情報にマッピングしているためで,複数のレコードを取得するケースではより顕著に性能の劣化が発生します。

DBIはほとんどの部分がXS注4で書かれているため,かなり高速です。また,実は便利なメソッドが数多くあり,ORMがなくても十分に使えるため,Mobage APIではほとんどラップせずにそのまま使用しています。

注3)
紙幅の都合でベンチマークに使用したコードは割愛します。本誌サポートサイトからダウンロードできます。
注4)
PerlからCを呼ぶしくみです。下手な書き方をしなければ高速です。
DBIでのSQLの生成

DBI自体にはORMにあるようなSQLを生成する機能はないため,SQL::Abstract注5などと併用して使っています。SQL::Abstractはかなりチューニングされており,現実的な速度でSQLをプログラマブルに生成できます。

SQL::Abstractで生成が難しいものや,そもそも常に同じSQLしか発行しないようなケースでは,プログラム上に直接SQLを書くなどして効率化しています。

以降では,DBIを直接使って可読性の高いコードを書くために知っておくべきこととして,次の6つのメソッドの使い方を詳しく解説します。

  • selectrow_array()
  • selectrow_arrayref()
  • selectrow_hashref()
  • selectall_arrayref()
  • selectall_hashref()
  • selectcol_arrayref()
注5)
最近ではSQL::Makerというものもあります。
selectrow_array

DBIの使い方をWeb上で検索すると,たいてい次のようにprepare()をしてexecute()でSQLを発行する形で書かれています。

use DBI;
my $dbh = DBI->connect(...);
my $sth = $dbh->prepare(
    'SELECT nickname FROM user_data WHERE user_id = ?'
);
my $rv = $sth->execute(1234);
my ($nickname) = $sth->fetchrow_array;

しかし,いちいちprepare()してexecute()をするのはコードの見通しが悪くなります。この場合は,selectrow_array()を使うとすっきりと書けます。次のコードは,上記のコードとまったく同じ挙動になります。

use DBI;
my $dbh = DBI->connect(...);
my ($nickname) = $dbh->selectrow_array(
    'SELECT nickname FROM user_data WHERE user_id = ?',
    undef,
    1234',
);

selectrow_array()はprepare()→execute()→fetchrow_array()をまとめたもので,実行速度の差はほとんどありませんので安心して使えます。ただし,同じ$sthを何度も実行するようなケースでは,prepare()を一度だけし,execute()とfetchrow_array()を繰り返したほうが高速になります。

著者プロフィール

嶋田裕二(しまだゆうじ)

1986年8月生まれ。Gaiaxなど数社を経て,現在はDeNAのプラットフォームシステムグループに所属。Mobagae APIやGadget Serverを担当し,日々増え続けるデータやアクセスに苦悩する日々。

CPANモジュールに「Windows対応用のパッチを送る迷惑な人」として一部で有名。

「Yokohama.pm」や「PerlCasual」,「YAPC::Asia」でスピーカをするなど,Perl関連のコミュニティへ積極的に参加している。

ブログ:http://blog.livedoor.jp/xaicron/

ハンドルネーム:xaicron

コメント

コメントの記入