天然パーマです。

「ボケて」のスケールアップとスケールアウト

オモロキで鎌団子さんと二人で開発している写真で一言ボケるWebサービス「ボケて」。 バックエンドの改修作業、それに伴うバグ等の修正を施し、やっと落ち着いて来たので、 そのことについて書いておこうと思います。

ボケてとは?

改修作業の詳細に入る前に「ボケて」とは、を紹介します。 ボケては「お題」と呼ばれる「写真」に一言「ボケ」を加えて笑いをつくりだせるWebサービスです。

スクリーンショット 2012-08-21 17.43.31.png

ユーザーはお題写真のアップロードやそうした写真に対するボケのテキストを入力でき、 最新のものや評価されたお題とボケを見ていくことができます。 評価の高いものはやっぱり面白くて見てると吹き出しちゃうものもたくさんあります(当社比)。

開発は上記した通り鎌団子さんと二人でやっていて、 鎌団子さんがデザインやHTML絡み、 僕がバックエンドやシステム周りを行っています。

5月13日、爆発

さて、そのボケてですが、今年の「5月13日」にアクセスが急増します。 2chまとめサイトもしくはNAVERまとめに掲載されたのが主な原因だと思われます。 そのPVは今までと比べておよそ10倍弱。 いわゆる「スラッシュドット効果」が起こり、 その時点でのスペックのサーバでは捌ききれなくなってしまいます。 しかも、このPVの増加は一時的なものではなく、常に高いまま... 監視ツールで「アクセスして30秒経ったらタイムアウトエラー」と見なし、アラートをメールさせる設定にしていたのですが、それがiPhoneに飛びまくり... サーバ側のアプリケーションやDBをそのアクセスに対応できるよう改善しようとしたところ...

フレームワークの変更とリライト

アクセスが増加した当時のボケては3年前に書かれたシステムだったのですが、 それがPerlのフレームワークCatalystでつくられてたんですよね。 で、そのソースを手元の環境に持ってきて立ち上げようとしたんですが、 モジュールのバージョンの差やPluginモジュールを多様して依存したために、 「動かない」んですよ、これがまた。

動かないってことは当然アプリケーション側を書き換えなくていけないわけですが、 その量が大きくなってしまいそうな予感。さらには最近僕は個人的にCatalystを触っておらず、 Mojoliciousばかり。WAFにCatalystほど重厚なものはいらないと思いだしていました。 てことで「いっちょ頑張るか」という具合でフレームワークをCatalystからMojoliciousへと変更させたボケてのアプリをつくることにしました。

Controller部分はもちろん全部書き換えて、さらに内部で使っているAPI部分もかなり変更して、 コーディングすること1ヶ月ほどでした。

スケールアウトしやすい構成と実装

その際、アクセスが増加している状態に耐えうるような設計にしました。 後述するキャッシュの利用ももちろんですが、以下のような項目です。

  • DBのレプリケーション構成
  • DBの参照系は生DBIを使った、更新系はDBIx::Skinnyを現在使用中
  • DBはMySQL InnoDBで
  • KVS等の技術は使わず、使い慣れているMySQL+Memcachedで
  • フロントサーバとアプリケーションサーバを物理的に分ける

また、Mojoliciousをうまいこと使って、Controllerから内部APIやModelを呼び出すときには、

my ($bokes, $pager) = $self->model('Boke')->get_recent_entries();

と直感的な記述で行えるようにしました。Validationの処理もFormの定義をしておけば、こんな感じでできます。

if($self->form('Boke')->has_error) {
    return $self->render_fill('/boke/post');
}

キャッシュ戦略

参照されるものを種類に分けてmemcachedで一定時間キャッシュさせています。 まぁありきたりなことですが、これによりDBサーバへの負荷を低減できます。

で、参照系は生のDBIを使って参照させてるのですが、簡単なラッパーをつくってその生DBIを使いやすくしてます。O/R Mapperは結果をオブジェクトを返しますが、そのラッパーはハッシュレフで返してくれます。以下の例だと「$self->dbx」がそれなんですが、「search」メソッドはこのように使います。

$bokes = $self->dbx->search(
    'boke', [ $cond ], [ { -desc => 'id' } ],
    {
        limit  => $limit,
        offset => $offset,
        expire => 60 * 60,
    }
);

条件にあう、最新のボケ一覧を取得していますが、「expire」という引数を与えると自動的にクエリーからキーを生成してそのキーに結果をキャッシュするという仕組みになっています。強制的にキーを組み立てて、そのキーに当てはまるキャッシュを強制的に削除するメソッドも用意しているので、場合によってキャッシュのコントロールができるわけです。

また、オブジェクトやオブジェクト全体のキャッシュだけではなく、右側のサイドバーのHTMLをキャッシュさせるなどの工夫もしております。

デルタ版リリース

ってことでスケールアップしたサーバを用意してそこへデプロイ。「ボケてデルタ版」を7月19日にリリースしました。うまいこと割とサクサクに動くようになりました。ただ、案の定漏れていたバグが多数あり、都度都度対応しました。テストが少ないのも原因なのでこの辺はしっかりさせたいところです。

まとめ

以上、ボケての改修作業について紹介しました。より細かい解説はYAPC::Asiaというカンファレンスで紹介したいと思いますので是非お越しください。そしてボケてをよろしくお願いします!