Anzeige
Anzeige

Más contenido relacionado

Presentaciones para ti(20)

Similar a 大規模ソーシャルゲーム開発から学んだPHP&MySQL実践テクニック(20)

Anzeige
Anzeige

大規模ソーシャルゲーム開発から学んだPHP&MySQL実践テクニック

  1. 大規模ソーシャルゲーム 開発から学んだ PHP&MySQL実践テクニック 株式会社インフィニットループ 松井 健太郎 2011/06/11
  2. 自己紹介(1) 松井 健太郎 ・ 株式会社インフィニットループ 代表取締役 ・ LOCAL PHP部 部長 ・ ke-tai.org 管理人 ・ コーラとバイクが好き
  3. 自己紹介(2) http://ke-tai.org/
  4. 自己紹介(3) →                  ↓ 先日、自販機の営業さんが来て、現在導入予定 無料設定なので、ボタンを押すだけで、 コーラが飲める環境に!!
  5. 会社紹介 株式会社インフィニットループ 所在地: 札幌市中央区 設立: 2007年6月 人員: 27名(契約・アルバイト含む) 業務内容:ソーシャルゲーム開発 • もともと数人規模のよくあるウェブアプリケーション開発会社だったが、ブ ラウザゲーム開発をきっかけに、メイン事業を「ゲーム開発」「高負荷サ ーバサイド開発」にシフト • 絶賛人材募集中!! このスライドを見て興味を持たれた方は是非声を掛けてください
  6. 開発実績 [ブラウザ三国志] ブラウザ三国志] 三国志 運営(株)AQインタラクティブ 開発ONE-UP(株) プログラム開発を(株)インフィニットループが担当 2009年7月正式サービス開始 公式のほか、mixi、Yahoo!モバゲー、ハンゲーム、 ニコニコアプリなど多くのプラットフォーム・チャネリングに対応、 海外にも展開中 [英雄クエスト] 英雄クエスト] クエスト 運営・開発ONE-UP(株) サーバ側プログラム開発を(株)インフィニットループが担当 2010年10月正式サービス開始 Yahoo!モバゲーにて運用中
  7. 本日の内容 1. ソーシャルゲーム案件の特徴 6. アプリ実装のポイント 2. 基本設計とポリシー 7. DBのインデックスについて 3. サーバとアプリの構成 8. DBのロックについて 4. なぜPHP+MySQLなのか 9. ロック処理のコツ 5. DBの多重化について 10. KVSの利用
  8. ソーシャルゲーム案件の特徴 ・ 基本動作は、通常のウェブアプリケーション案件と同じ → HTMLとCSSで作られた画面の遷移 → FlashやJavaScriptによる処理 → DBへの登録・修正・削除 → 培った業務スキルは、そのまま流用出来る ・ 通常案件との違い → アクセス数や負荷が桁違いに大きいため、負荷対策が必要 → 多ユーザの同時操作に耐えるため、ロック等はしっかりと → 開発規模が大きく、スピードが求められる   ・ 個人戦での限界、チーム開発は必須   ・ 開発だけではなくマネジメント的な要素も求められる   ・ 仕様書ありきの仕事ではない、コミュニケーションスキルが必要   ・ リリースしてからが本当の戦い    (感覚的にはリリース時点で、全体の60%くらい)
  9. 基本設計とポリシー(1) 破綻をきたさない設計が重要  【よくある失敗パターン】   1. とりあえず仕様を満たすように開発を進める   2. テストもパスしてオープンした   3. 利用者が増え、負荷が大きくなる   4. サーバ台数を増やすなどして対処するが、設計上の問題からボトルネック     発生し、ある一定数以上の接続数はどうしても捌くことができない   5. 慢性的に重い状態となり破綻 ※テストの段階で、本番と同等の負荷をかけるのはかなり難しい ※ゲームという性質上、利用人数の増加が読めない → サーバ台数を増やすことで、    処理能力を上げられる設計が重要
  10. 基本設計とポリシー(2) 負荷対策を考慮した設計が重要 ・ 負荷を「さばく」よりも、負荷を「かわす」方法を考える ・ データはとにかく溜めないこと  → データには保存期限を設ける  → DELETE文は遅いので、バッチ削除とかは無理が出てきやすい  → データを追加するときに、最も古いデータを消すなどの工夫が必要 ・ 厳密に扱う必要がないところは、どんどんルーズに  → 重要度が低く、変更が頻繁なデータは、DBに保存しない  → 例えばメールの新着チェックは、毎回行わずにn回に1回とする ・ ゲーム企画チームとのすり合わせがすごく大事  → 負荷との戦いは、ゲーム仕様を決めるところから始まっている  → 仕様書が来てから仕事開始ではない
  11. 基本設計とポリシー(3) 仕様はなるべく簡単に  → 面白さに影響が出ないのであれば、仕様は簡単な方が良い  → 仕様を限定しないと、のちのちサーバ負荷に限界が出てくる 難しい仕様の例 簡単な仕様の例 全プレイヤーが1つのワールドでプレイ ワールドで分けられる (分割は不可) (ワールド単位でのサーバ分割が可能) 他者との関わりが多い 他者との関わりが少ない (連携プレイが主のため、ユーザ単位での分割が難しい) (ユーザID単位での分割が可能、排他ロックも不要) 二窓でのプレイを許可する 二窓でのプレイができない/許可しない (同時操作系のバグが起こりやすい) (同時操作系のバグが起こりにくい ※) アイテムに個数制限がある 例:武器Aは世界に10個まで 個数制限はない (厳密なロック処理が必要) (ロック処理は比較的ルーズでも大丈夫 ※) 処理結果が公開され、多くの人の目に触れる 処理結果が1度しか表示されず、1人にしか見えない (処理に間違いが許されない) (処理に多少の間違いがあっても気づかれない ※) ※バグを容認しているわけではないです バグを容認しているわけではないです
  12. サーバとアプリの構成(1) 使用している主なOSとソフトウェア HTTPアクセス ・ Linux ・ Apache ロードバランサ (Varnish) HTTP振り分け ・ PHP ・ MySQL バッチ処理サーバ Webサーバ Webサーバ Webサーバ ・ ・ ・ ・ memcached (Apache) DBアクセス (Apache) (Apache) ・ (+ MongoDB) キャッシュサーバ (memcached) 負荷に応じて 負荷に 台数を 台数を調整 DBマスター (MySQL) ログサーバ レプリケーション (syslogd) この構成でほとんどの ・ ・ ・ ゲームに対応可能 DBスレイブ (MySQL) DBスレイブ (MySQL) DBスレイブ (MySQL)
  13. サーバとアプリの構成(2) サーバ環境にはクラウドサービスを利用している。 ヒットするかどうかで、利用者数の変化の激しいゲーム案件は、 クラウドサービスとの相性が良い。 (可能ならDBマスターなど、要所にリアルサーバを併用できるとなお良い) ・ Amazon EC2  → 他と比べると安価な料金  → コントロールパネルやコマンドから全て操作可  → オートスケーリングが利用可能  → 2011年春には、東京リージョンができ、通信レスポンスも早くなった ・ 国内クラウドサービス  → 料金ちょっと高め  → 日本語による手厚いサービス  → 業者によっては、インスタンスを足すのに、    営業に連絡して数日かかるなど、スピード感に欠ける
  14. なぜPHP+MySQLなのか ・ 高負荷での運用に、数多くの実績がある鉄板構成 ・ ネット上の情報も多く、実務に反映しやすい ・ チームマネジメント上もメリットが多い  → 人材確保が容易、教育も容易  → 開発スピードの向上に繋がる ・ PHPのダメなところはコーディング規約でカバー ・ APCは必ず導入  → 試した範囲では、他の高速化エンジンよりもかなり早い ・ MySQLはなるべく新しいバージョンを
  15. DBの多重化について ・ MySQL標準のレプリケーション機能を使っての、 マスター/スレイブ構成が基本 ・ スレイブは数を増やせば良い、マスターの負荷軽減が課題となる ・ マスター分割は、ゲーム上の仕様も絡んできて、難易度も高い ・ レプリケーション遅延を防ぐ工夫をする → サイズがメモリに収まる範囲なら、スレイブはtmpfs上に展開 → 参照率をアプリ側で制御できるようにする ・ マスター/スレイブの使い分けには主に2つのアプローチがある → 最初マスターしか見ないように作って、    安全な部分から徐々にスレイブやKVSを見るように切り替えていく → 普段はスレイブ、トランザクション開始時にマスターに接続を切り替える ・ 「MySQL Cluster」、「XAトランザクション」ってどうなんだろう
  16. アプリ実装のポイント ・ フレームワークは使わないもしくは自作 → 既存フレームワークを使っても結局改造するはめに → 機能よりも速度重視 → Flashなどのクライアントアプリとの連携部は作り込んだ方がよい ・ O/Rマッパーは使用していない → 管理できないSQLは発行されないようにする → 自作のクエリビルダー的なものを作って利用している ・ アプリを書くときは処理スピードをそれほど意識しなくても大丈夫 → がんばって書いても、それほど負荷は下がらない → それよりもDBの負荷を下げるほうが効果的 → ただし共通処理(毎アクセス処理される箇所)は、気合を入れる → 大量の配列処理は遅いので注意 → Apacheログから重いページランキングを生成し、上から順に潰す
  17. DBのインデックスについて(1) ここが負荷対策の最大のキモ!! ・ インデックスとは → 本でいう索引のようなもの → 適切に利用すると、何十倍・何百倍も速度が変わることも ・ むやみに張ればいいというものではない → 索引を増やすと本が厚くなる(サイズが大きくなる) → INSERT, UPDATE, DELETE時にインデックスを    作り直すので、速度が低下する → インデックスサイズがメモリに収まるサイズを超えると、    その瞬間から大幅に速度が低下する ・ インデックスを適切に使うよう、SQLをチューニングしていく → インデックスを張っても、SQLの書き方によっては使われない → EXPLAINで確認しながら、チューニングしていく
  18. DBのインデックスについて(2) プログラマのインデックスをめぐる一生 1. インデックスなんて知らない期 → インデックスの存在自体を意識したことがない → そもそも利用者が少ないアプリしか作ったことがない 2. インデックス初体験期 ↓ → 初めて負荷のかかるアプリを作り、インデックスの存在を知る → インデックスを張ったところ、それだけで負荷が数分の1に → 興奮し、サルのようにインデックスを張りまくる 3. インデックスわかってきた期 ↓ → インデックスは張りすぎてもダメとようやく気づく → 複合インデックスを活用しはじめる → インデックスサイズを意識しだす
  19. DBのインデックスについて(3) インデックスを使う上での主な注意点 ・ 「!=」、「<>」はインデックスが使用できない ・ LIKE検索時、前方一致以外では、インデックスは使用できない ・ ORや範囲検索(不等号)はインデックスが使用できないことがある ・ ORDER BYは、インデックスを使用できないパターンが多数ある ・ とにかくEXPLAINが大事、MySQLのスロークエリログも参考になる → プロジェクト内の全てのプログラマに周知徹底を! 参考: インフィニットループ技術ブログ ソーシャルゲーム開発者なら知っておきたい MySQL INDEX + EXPLAIN入門      http://www.infiniteloop.co.jp/blog/2011/03/mysql-index-explain/
  20. DBのロックについて(1) これをしっかりやらないと、リリース後バグだらけに!! ・ ロックはとても大事 → ロックをしっかりかけていないと、連打や同時操作でバグが起こる → テスト環境では、再現しないことも多いのでやっかい ・ 行ロックを使う、テーブルロックは使っていない ・ ストレージエンジンには「InnoDB」、 分離レベルには、「REPEATABLE READ」を使っている ・ ロックの挙動は複雑で、しっかり理解することが重要 ・ 特に行ロック時に、インデックスが使われなかった場合は、 テーブルロックがかかってしまうため注意が必要
  21. DBのロックについて(2) プログラマのロックをめぐる一生 1. ロックなんて知らない期 → ロックの存在自体を意識したことがない → そもそも複数人数が同時に使うアプリを作ったことがない 2. ロック初体験期 ↓ → 初めて負荷のかかるアプリを作り、同時更新系バグを出す → ここで初めてロックの重要性を知り、恐怖する → 興奮し、サルのようにロックをしまくる、とにかくロック → 「Deadlock」、「Lock Wait Timeout」祭りがはじまる ↓ 3. ロック青年期 → ロックしすぎはダメと気づく → 「SHOW ENGINE INNODB STATUS」の情報を活用 → ロックの内部処理や挙動を意識しだす
  22. DBのロックについて(3) 行ロックの挙動 ※ 例は全てMySQL5.1系で検証 例1: 存在するレコードを行ロックした場合 SELECT * FROM t WHERE c = 2 FOR UPDATE Gap(Infimum) DELETE FROM t WHERE c = 2 1 Gap × 2 L Gap 5 × INSERT INTO t (c) VALUE(2) Gap(supremum) 参考: ・インフィニットループ社内勉強会資料 佐々木 亨基 MySQL InnoDB によるロック処理入門  ※近日公開予定      ・技術評論社  奥野幹也 著 エキスパートのためのMySQL運用+管理トラブルシューティングガイド
  23. DBのロックについて(4) ギャップロックの挙動 例2: 存在しないレコードを行ロックした場合 SELECT * FROM t WHERE c = 4 FOR UPDATE Gap(Infimum) SELECT * FROM t WHERE c = 3 1 FOR UPDATE Gap ○ 2 × INSERT INTO t (c) VALUE(3) × Gap L 5 INSERT INTO t (c) VALUE(4) Gap(supremum) レコードが存在しないため、ギャップがロックされる レコードが存在しないため、ギャップがロックされる しないため
  24. DBのロックについて(5) デッドロックの挙動 二つ以上のセッションが互いの処理待ちとなり、各セッションの処理が進まなくなった状態 例3: ロックして存在確認後、レコードがなければインサートする ※ t に c < 200 のデータしか無い場合 A B SELECT * FROM t WHERE c = 200 FOR UPDATE SELECT * FROM t WHERE c = 300 FOR UPDATE INSERT INTO t (c) VALUE(200) INSERT INTO t (c) VALUE(300) これがデッドロックになる
  25. ロック処理のコツ ・ MySQLのロック処理は複雑で、新米プログラマを含めた全員が、 完全に理解するのは難しい(INSERTが絡むと特に複雑) ・ 基本指針を示し、難しい箇所はリードエンジニアがレビューで対応 ・ 基本は、「トランザクション開始後に、すぐ更新対象をロック」 ・ ロック時にインデックスが使用されていることをEXPLAINで確認 ・ 値を加算/減算をするときは、なるべくSQLの中で行う → UPDATE example_tbl SET a = a + 1 WHERE foo = ‘bar’; とても書き切 ・ ロックで取ったもの以外、値が正しいことを信じない れないので、 → スレイブ遅延やファントムリードに気をつける 近日中に弊社 技術ブログで ・ デッドロックは、ロック範囲の見直しと、リトライで対処する 別途資料を 公開予定 ・ MySQLの気持ちになって考えるのが大事
  26. KVS(キーバリューストア)の利用 ・ KVS(memcachedなど)は、一時期積極的に利用したが、 今は一部での利用に留めている ・ 開発やテストのコストがかかる → キャッシュのクリア漏れによるバグを生む → トランザクション中にKVSのデータを扱うのは難しい ・ システム全体のトータルコストで考える → KVSから値を取得し、それをアプリ側で結合するくらいなら、    MySQLのJOINの方が早い ・ 使うところにはもちろん使う → PHPのセッション管理 → 変更が入らないマスタテーブル類のキャッシュ → 読み込み回数が著しく多い箇所
  27. まとめ ・ ゲーム案件であっても、特に変わったことはしておらず、 基本が大事、基礎に忠実に淡々と ・ なるべく負荷をかけないゲーム仕様になるようすり合わせを ・ SQLチューニングとインデックスの見直しが 負荷対策の中核 ・ ロックは大事、しっかりとした理解が必要 ・ キーバリューストアは、全体のコストを考えて 使いどころを検討して使う ・ MySQL(というかデータベース)は本当に難しい!! → オレたちは、このMySQL坂を登りはじめたばかり
  28. 最後に ・ ゲームの仕事は、大変なこともあるが面白い 仕事を楽しんでやることが重要 ・ 参考ゲームや自分の作ったゲームを、きちんとプレイすること が大事、ゲームを理解せずにゲームは作れない ・ 皆に愛されるものを作れたときは、本当に幸せ ・ プレイヤーやパートナーに対し、 いつも感謝の心を忘れずに
  29. おまけ(1) スタッフ募集のお知らせ 株式会社インフィニットループでは、一緒に楽しんで ゲームを作ってくれるスタッフを募集しています ・ PHPプログラマ、Rubyプログラマ ・ ActionScriptプログラマ ・ データベースエンジニア ・ サーバエンジニア ・ ゲーム企画・運営経験者 興味のある方は、直接声を掛けていただくか、 HPからお問い合わせください
  30. おまけ(2) アルバイト募集のお知らせ 株式会社インフィニットループでは、 アルバイトも募集しています。 ・ プログラマ見習い ・ テスター(プログラムのテスト、バグ検証) ・ その他雑務 せっかくプログラムを書けるスキルを持っているのに、 コンビニ等でバイトするのは勿体ない!! 学生歓迎、ノートPC貸与 興味のある方は、直接声を掛けていただくか、 HPからお問い合わせください
Anzeige