2012年8月23日木曜日

HEKK流ソーシャルゲームのアプリ構成

このエントリーをはてなブックマークに追加
エンジニアの草苅(@kusakari)です。

Happy Elements株式会社(以下、HEKK)では、モバイル向けのソーシャルゲームに注力して開発を行っています(PCアプリは中国の Happy Elements Ltd. で開発しています)。

HEKKでは全社的にサーバーサイドのプログラミング言語を Ruby で統一しており、フレームワークは Ruby on Rails を使用しています。

データストレージには Cassandra と MySQL を併用しており、スケールする必要のあるデータ(ユーザーデータ)は Cassandra、マスターデータ(例えばアイテム情報)は MySQL に保存するという形で区別しています。

HEKKで開発しているソーシャルゲームの典型的なリクエストフローは、次の図のようなものです。

今回は Rails より後ろのデータストレージ3つを、どのように利用しているかについて簡単にご紹介します。

Cassandra

Apache Cassandra は facebook で開発された大規模データ処理用のKVS(Key Value Store)です。
利用箇所としては前述の通り、ユーザーデータ用のストレージとして利用しています。
HEKKでソーシャルゲームのデータストレージに Cassandra を選択した主な理由は、次のようなものです(一般的によく使われていると思われる MySQL との比較)。

書き込みがリニアにスケールする
ソーシャルゲームは通常のウェブサービスなどと比較して、書き込みの割合が多くなるため、書き込み処理がボトルネックになりやすい傾向があります。そのため、書き込みがリニアにスケールする必要があります。

単一障害点がない
MySQL の場合、マスターが落ちた際に無停止でサービスを運用し続ける難易度は高めです。特にソーシャルゲームで MySQL をメインのデータストレージとしている場合、必然的にDB分割なども必要になってくるため、さらに難易度は高くなります。しかし、Cassandra であれば単一障害点がないため、シンプルな構成で安定したサービス運用が可能です。

書き込み先のサーバーを意識する必要がない
MySQL の場合、アプリかアプリと MySQL の中間層が、書き込み先の MySQL サーバーを意識する必要がありますが、Cassandra であれば ring 内のどのサーバーに書き込んでも問題ないため、サーバーが増えたとき、減ったときなどにシャーディングに関する面倒な問題が発生しません。

ここまで Cassandra の良い点ばかり書いてきましたが、もちろん実際は良い点ばかりではありません。Cassandra と MySQL を比較した時に弱い点の一つとして、クライアントライブラリがあります。

Ruby 用のクライアントライブラリである cassandra.gem がミニマムな機能であることもあり、HEKKでは、Cassandra 内のデータへ ActiveRecord に近い感覚でアクセスできるように cassandra_object.gem を利用しています。また、実運用に耐えうるように、独自に次のような機能拡張を行っています。
  • Cassandra 0.7 以降に対応。
  • 追加の Callback Methods に対応。
  • register_attribute_type の MessagePack 対応。
  • Ruby 1.9.2、1.9.3に対応。
  • Rails3 専用にリファクタリング。

例えば、CassandraObject::Base を使うと次のように書けます。
class User < CassandraObject::Base
  attribute :nickname, :type => :string
  attribute :date_of_birth, :type => :date
  attribute :joined_at, :type => :time_with_zone
  attribute :preferences, :type => :msgpack
  key :uuid
  consistency_levels :read => :one, :write => :one
end
user = User.new(:nickname => "kusakari")
user.preferences = {:hoge => "A", :fuga => "B"}
user.save
user = User.get(uuid)
 => #<User:0x000000XXXXX @schema_version=nil, @key="YYYYY", @attributes={"nickname" => "kusakari", "preferences" => {"hoge" => "A", "fuga" => "B"}}>

さらに、CassandraObject::Base で対応できない、動的な Column Key のデータに対応するため、 cassandra.gem のラッパーライブラリとして CassandraObject::Lite::Base を開発して使用しています。


Memcached

Memcached はご存じの通り、キャッシュ用のミドルウェアです。
利用箇所としては主に MySQL のマスターデータのキャッシュ用ストレージとして利用しています。

memcached 用クライアントライブラリとしては dalli.gem(または memcache-client.gem) や memcached.gem がありますが、大きな違いは dalli.gem と memcache-client.gem はピュア Ruby、memcached.gem は c で書かれているという点です。HEKKでは memcached.gem を使用しています。
ただ、Windows 機で開発している場合、 memcached.gem が利用できないということもあり、memcached クライアント用のラッパーライブラリを作ることによって、アプリからは内部的に使用している gem を意識しないで済むような作りになっています。また、このラッパーライブラリ内で marshal load 時の Model の自動ロードなどの処理を行うなど、実用的な作りとなっています。

MySQL

MySQL については特筆すべきことはありませんが、前述の通り、基本的にはマスターデータのストレージとして使用しています。それに加えて、検索条件が必要になる場合や 、(Cassandra にはない)トランザクションを使って、強い一貫性を保障したい場合には MySQL にデータを格納するようにしています。
また、テーブルが一定以上の大きさになるような場合は、MySQL 5.1 以降で利用できるパーティショニング機能を使用するようにしています。


ということで、HEKK で開発しているソーシャルゲームのアプリ構成の中から、データストレージ部分について簡単にご紹介しました。

Rails や Cassandra を使って、大量のトラフィックをさばくソーシャルゲームを、京都で開発してみたいというエンジニアの皆さん、ご応募お待ちしています!

0 件のコメント:

コメントを投稿