Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
PHP+MySQLを使ったスケーラブルなソーシャルゲーム開発
Search
Infiniteloop
July 12, 2023
Programming
0
75
PHP+MySQLを使ったスケーラブルなソーシャルゲーム開発
OSC 2013 Hokkaidoで発表された「PHP+MySQLを使ったスケーラブルなソーシャルゲーム開発」のスライド資料です。
Infiniteloop
July 12, 2023
Tweet
Share
More Decks by Infiniteloop
See All by Infiniteloop
俺の PHP プロファイラの話 PHP スクリプトで PHP 処理系のメモリをのぞき込む
infiniteloop_inc
0
270
心理的安全性を学び直し、 「いい組織とは何か?」を考えてみる
infiniteloop_inc
0
340
ゼロからつくる 2D物理シミュレーション ~物理現象をコードに落とし込む方法~
infiniteloop_inc
0
410
詫び石の裏側
infiniteloop_inc
0
370
[新卒向け研修資料] テスト文字列に「うんこ」と入れるな(2024年版)
infiniteloop_inc
6
25k
リファクタリングで実装が○○分短縮した話
infiniteloop_inc
0
140
ADRという考えを取り入れてみて
infiniteloop_inc
0
130
500万行のPHPプロジェクトにおけるログ出力の歩み
infiniteloop_inc
0
110
I ❤ Virtual Machines 仮想環境をより便利に使うツールたち
infiniteloop_inc
0
83
Other Decks in Programming
See All in Programming
ふかぼれ!CSSセレクターモジュール / Fukabore! CSS Selectors Module
petamoriken
0
150
リアーキテクチャxDDD 1年間の取り組みと進化
hsawaji
1
220
Flutterを言い訳にしない!アプリの使い心地改善テクニック5選🔥
kno3a87
1
180
Compose 1.7のTextFieldはPOBox Plusで日本語変換できない
tomoya0x00
0
190
タクシーアプリ『GO』のリアルタイムデータ分析基盤における機械学習サービスの活用
mot_techtalk
4
1.4k
受け取る人から提供する人になるということ
little_rubyist
0
230
役立つログに取り組もう
irof
28
9.6k
Amazon Qを使ってIaCを触ろう!
maruto
0
410
とにかくAWS GameDay!AWSは世界の共通言語! / Anyway, AWS GameDay! AWS is the world's lingua franca!
seike460
PRO
1
860
Jakarta EE meets AI
ivargrimstad
0
160
シールドクラスをはじめよう / Getting Started with Sealed Classes
mackey0225
4
640
NSOutlineView何もわからん:( 前編 / I Don't Understand About NSOutlineView :( Pt. 1
usagimaru
0
330
Featured
See All Featured
How To Stay Up To Date on Web Technology
chriscoyier
788
250k
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
The Invisible Side of Design
smashingmag
298
50k
For a Future-Friendly Web
brad_frost
175
9.4k
Why You Should Never Use an ORM
jnunemaker
PRO
54
9.1k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
31
2.7k
A Modern Web Designer's Workflow
chriscoyier
693
190k
The Power of CSS Pseudo Elements
geoffreycrofte
73
5.3k
Automating Front-end Workflow
addyosmani
1366
200k
Fantastic passwords and where to find them - at NoRuKo
philnash
50
2.9k
Facilitating Awesome Meetings
lara
50
6.1k
Code Reviewing Like a Champion
maltzj
520
39k
Transcript
PHP+MySQL を使った スケーラブルなソーシャルゲーム開発 株式会社インフィニットループ 佐々木 亨基 2013/09/14 OSC Hokkaido 2013
自己紹介 ・佐々木 亨基 ・ゆきこ yukicon ・ Twitter:@yukiconEx ・株式会社インフィニットループ所属 ・札幌 MySQL
勉強会代表 ・ゲームと戦車とお人形さんが好き ・隠居して一日中 MMORPG をして過ごすのが夢 ・超適当 ・のんびりゆったりまいぺーす
自己紹介 社内での役割 ・平エンジニア ・名前を出せないものを担当する事が多くて切ない ・普段は機能開発や運用 ・ひたすら負荷軽減だけを行ったりする事も ・トラブル時はプロジェクト間を横断して火消し ・最近トラブルが少なくて寂しい
インフィニットループについて ・北海道札幌市にあるシステム開発会社 約 90 名(契約スタッフ・アルバイト含む)で活動中 社長も含め、ほぼ全員がエンジニア ・主な開発実績(主にサーバサイドを担当) ブラウザ三国志 (2009) 英雄クエスト
(2010) Lord of Knights(2012) フォトバトラー (2012) Vim 検定 (2012) PHP 検定 (2013) その他いろいろ
スケーラブルなシステム構築について解説 負荷対策や DB 分割のノウハウを紹介 高負荷に対して冷静に向き合えるようになろう 原因と対処方法を知っていれば怖いことはない 今日のお話
▪ はじめに ・ソーシャルゲーム案件 ・スケーラブル? ▪ 架空戦記 ・ [Ⅰ] の時代 サービス開始
・ [Ⅱ] の時代 Web サーバ追加 ・ [Ⅲ] の時代 DB スレーブ追加 ・ [Ⅳ] の時代 垂直分割 ・ [Ⅴ] の時代 水平分割 お題目
▪ 実際のところ ・アプリのチューニング ・負荷状況の洗い出し ・スケールアップとスケールアウト ・ DB 分割アレコレ お題目
・規模の予測が難しい ・流行ると爆発的にユーザ数が増加する ・成功が約束されている案件は少ない 最初は細々とサービス開始可能 かつユーザ数の増加に対応できるシステムが理想 つまりスケーラブルなシステム ソーシャルゲーム案件
・スケールアップ サーバを強くする事 CPU 、メモリの増強 高速なストレージへの換装 ・スケールアウト サーバの台数を増やす事 スケーラブル?
・スケールアップ サーバを強くする事 CPU 、メモリの増強 高速なストレージへの換装 ・スケールアウト サーバの台数を増やす事 今回は特にスケールアウトに焦点を当てたお話 スケーラブル?
架空戦記
あらすじ とある架空のソーシャルゲーム運用物語 サービス開始当初、そのゲームには誰も期待なんてしていなかった しかし徐々に人気が上がり、ユーザ数が爆発的に増加していく ユーザが増える度に悲鳴を上げるサーバ 開発運営はあの手この手でサーバ増強を試みるのだった ※ この物語はフィクションです 架空戦記
いよいよリリースの時 誰も期待していないこのゲーム とりあえず動けば OK まずは最小の構成でスタートしよう! プロローグ
スモールスタート!
ひとまず最小の構成 Web DB Web 1 台 DB 2 台 DB
[Ⅰ] の時代
・ DB サーバはデータ損失を防ぐため ホットスタンバイ状態のスレーブサーバを用意 ・ホットスタンバイさせているサーバは参照しない ・ Web サーバが落ちたらごめんなさい とりあえず動く! [Ⅰ]
の時代
ユーザ数が想定外の増加!
Web サーバが悲鳴を上げる! Web DB DB [Ⅰ] の時代
▪ 現状 Web サーバの性能が限界 ピークタイムでは CPU 使用率が常に 100% に近い 1
台では耐え切れない Web サーバの増強が急務! [Ⅱ] の時代への遷移
-- Web サーバを増やすには ・ LB( ロードバランサ ) の導入 複数の Web
サーバに振り分けを行う ・セッションを管理するキャッシュサーバを設ける サーバ間を跨いでログインセッションを管理 memcached を使用 ・必須ではないがログサーバも用意 アプリのログを一元管理 syslog を使用 [Ⅱ] の時代への遷移
Web サーバ他を追加 Web Web 3 台 DB 2 台 Cache
1 台 Log 1 台 Web Web Cache Log LB DB DB [Ⅱ] の時代
・ Web サーバはどんどん追加可能 ・ Web サーバが 1 台くらい落ちても平気 ただし LB
から切り離す対応は必要 ・ Cache サーバはセッション以外もキャッシュ可 ・ Cache サーバはバッチサーバとしても使用可 CPU を使う PHP のバッチ処理と メモリを使う memcached は同居しやすい ・ Cache サーバも増やせる ・ Log サーバを立てた事でアプリログは今まで通り これで一安心! [Ⅱ] の時代
そんな訳なかった!
今度は DB サーバが高負荷に! Web Web Web LB DB DB Cache
Log [Ⅱ] の時代
▪ 現状 DB サーバの性能が限界 参照クエリも更新クエリも全て 1 台へ発行している しかし 1 台だけ参照していたのでは耐え切れない
DB サーバの増強が急務! [Ⅲ] の時代への遷移
-- DB サーバを増やすには ・複数のスレーブサーバを用意 ・マスタ、スレーブの参照先切り替えを実装 トランザクションや更新クエリはマスタに 参照クエリはスレーブに ・なんらかのスレーブ参照先振り分け方式を用意 アプリレベルで実装 DNS
サーバを立てて振り分け LB の使用 など [Ⅲ] の時代への遷移
DB スレーブを追加 Web Web 3 台 DB 4 台 Cache
1 台 Log 1 台 Web Web LB DB DB DB DB Cache Log [Ⅲ] の時代
・ DB スレーブも追加可能 スケールアウト可能な構成と言える [Ⅲ] の時代
Web Web Web LB DB DB DB DB Cache Log
[Ⅲ] の時代
スケールアウト!
Web と DB スレーブを追加 Web Web 5 台 DB 6
台 Cache 1 台 Log 1 台 Web Web LB DB DB DB DB Web Web DB DB Cache Log [Ⅲ] の時代
・ Web サーバや DB スレーブを追加して耐えられる ・単一 DB としての完成形 ・この先は DB
分割が必須 ・この方式のサーバ群を増やしていくという手もある ブラウザ三国志がその方式 ( 通称ワールド分け方式 ) ワールド間で関わりは持てない ユーザ数増加には新規ワールドをオープンする事で対応 アクティブユーザが減少したらワールドを統合 今度こそ安心? しかしこの案件にワールド分けは許されなかった… [Ⅲ] の時代
順調に増え続けるユーザ
遂に恐れていた時が!
DB マスタが限界を迎える Web Web Web LB DB DB DB DB
Web Web DB DB Cache Log [Ⅲ] の時代
マスタサーバは 1 台きりで増やせない 更新性能がネックとなりいずれ限界が来る Master Slave Slave Slave ・・・ ×n
SELECT UPDATE SELECT SELECT [Ⅲ] の時代
▪ 現状 DB マスタの更新性能が限界 案件的にワールド分けも許されない 意を決して DB 分割をするしかない! [Ⅳ] の時代への遷移
DB 分割 (DB Sharding) [Ⅳ] の時代への遷移 A テーブル B テーブル
E テーブル F テーブル E テーブル F テーブル E テーブル F テーブル … 垂直分割 ( テーブル単位での分割 ) 水平分割 ( 同テーブルの ID 単位による分割 ) C テーブル D テーブル
難易度の低い垂直分割を採用! [Ⅳ] の時代への遷移 A テーブル B テーブル E テーブル F
テーブル E テーブル F テーブル E テーブル F テーブル … 垂直分割 ( テーブル単位での分割 ) 水平分割 ( 同テーブルの ID 単位による分割 ) C テーブル D テーブル
-- 垂直分割するには ・分離するテーブルを選択 イベント時のみ重くなるため イベント用のテーブルを分離する など、アプリによって様々 ・アプリを複数 DB への問い合わせに対応 対象
DB の切り替え 複数 DB 間でのトランザクションの管理 [Ⅳ] の時代への遷移
DB を垂直分割 Web Web 5 台 DB 8 台 Cache
1 台 Log 1 台 Web Web LB DB DB DB DB Web Web Cache Log DB DB DB DB DB1 DB2 [Ⅳ] の時代
・困ったらさらに垂直分割をして対応 ・垂直分割で対応が難しいなら水平分割が必要 作ってて思ったけどなんだか嫌な予感が・・・ [Ⅳ] の時代
止まらないユーザ増加
DB1 をこれ以上垂直分割するのが難しい! Web Web Web LB DB DB DB DB
Web Web Cache Log DB DB DB DB DB1 DB2 [Ⅳ] の時代
知ってた!
▪ 現状 膨らみ続けるユーザデータに対し 垂直分割のみでの対応が困難 水平分割もやるしかない! [Ⅴ] の時代への遷移
やるしかない! [Ⅴ] の時代への遷移 A テーブル B テーブル E テーブル F
テーブル E テーブル F テーブル E テーブル F テーブル … 垂直分割 ( テーブル単位での分割 ) 水平分割 ( 同テーブルの ID 単位による分割 ) C テーブル D テーブル
-- 水平分割するには ・分割するテーブルを選択 ユーザに紐付いたデータを水平分割 更新の激しいイベントデータを水平分割 など、垂直分割とは思想が違うため再設計 ・共通データ Global + User
× n が王道 ・アプリを水平分割に対応 各 DB へのデータ振り分け DB 間を跨いだ串刺し検索 [Ⅴ] の時代への遷移
ユーザデータを水平分割 Web 5 台 DB 12 台 Cache 1 台
Log 1 台 LB Cache Log DB DB DB DB Global [Ⅴ] の時代 DB DB DB DB User1 DB DB DB DB User2 Web Web Web Web Web
・増え続けるデータ、更新の多いデータは水平分割 データが増えるならサーバも増やす 更新ネックになりそうならサーバを増やす ・もちろん今までの手法と合わせて対応可能 Web サーバの追加 スレーブ DB の追加 垂直分割
今度こそ安心! [Ⅴ] の時代
スケールアウト Web 9 台 DB 16 台 Cache 1 台
Log 1 台 LB Cache Log DB DB DB DB Global [Ⅴ] の時代 DB DB DB DB User1 DB DB DB DB User2 DB DB DB DB User3 Web Web Web Web Web Web Web Web Web
もっとスケールアウト! Web 16 台 DB 20 台 Cache 1 台
Log 1 台 LB Cache Log [Ⅴ] の時代 DB DB DB DB User1 DB DB DB DB User2 DB DB DB DB User3 Web DB DB DB DB Global DB DB DB DB Event Web Web Web Web Web Web Web Web Web Web Web Web Web Web Web
最初はこんなのだったのに・・・ Web DB Web 1 台 DB 2 台 DB
思い出
ユーザ数の増加に伴い何度も立ちはだかる壁 その度に新たな方法でスケールアウトに挑む開発陣 ソーシャルゲームはこうした影の努力により運用されている エピローグ
架空戦記 完
こんにちわ現実
現実の問題はもっと複雑で泥臭い ・現状の理解 今のサーバ構成は 負荷の状況は ・問題の把握 何がネックになっているのか ・対策の打ち出し 解決するために何をしたら良いか ・対策にかかる期間の見積もり どれくらいで対応が済むか
根本対応までの緩和策は必要か これらを正確に 実際のところ
「とりあえずサーバ追加したら解決するんでしょ?」 特にプロデューサ、企画レベルではそう考えがち それもそのはず、アプリの事がわからないのだから仕方がない 自分に出来る範囲での対策を提案しているだけ エンジニアはアプリの事がわかる とりあえずサーバ増やそう…ではなく 別の考え方をするべき アプリのチューニング
・サーバ追加に意味があるか 例えば DB マスタネックであれば意味は無い ・アプリの品質に問題はないか アプリにいくつもの改善点を抱えたまま いたずらにサーバを追加するのは無駄 心構えとしてサーバ追加は最後の手段と考えておく まずはアプリのチューニング やる事をやってからサーバ追加
ただし対応が済むまでの一時しのぎで追加はあり アプリのチューニング
・グラフで負荷状況を監視 サーバリソースを確認 munin cacti ・スロークエリログを確認 特に重いクエリを発見 mk-query-digest との組み合わせも効果的 ・ tcpdump
+ mk-query-digest 実行時間は短いが実行回数の多いクエリを発見 ・ MySQL の binlog を解析 更新の多いテーブルを特定 負荷状況の洗い出し
・デッドロック検出時にログに残す 頻繁にデッドロックが起こる箇所の特定 MySQL5.6, MySQL5.5.30 以降 アプリレベルで実装もあり ・アプリレベルでサンプリングツールを用意 リクエスト時に 1/10000 の確率で情報を記録
実行時間、ページ・ API ごとの実行回数を調査 重いページ・ API を特定 リリース前の社内テストレベルでも有効 負荷状況の洗い出し
・ xhprof の活用 本番に近いデータ量を開発環境に用意して実行 クエリキャッシュは無効にして行う 具体的に重い処理をメソッドレベルで特定 ・ DB ライブラリで実行時にクエリ数をカウント どのテーブルに何が何クエリ流れたかを計測
1 リクエスト辺りのクエリ数を明確にする 1 リクエスト単位で問題となっているクエリを特定 負荷状況の洗い出し
・高負荷は 9 割方 DB 操作に起因 クエリ数の削減 クエリの見直し インデックスの見直し ロック範囲の見直し デッドロック時はリトライ
やむを得ず重いクエリを流すならキャッシュする といった対策を 負荷状況の洗い出し
・スケールアップとスケールアウトは上手く行う 月額 10 万円のサーバ 8 台で運用していたが 実は月額 20 万円のサーバを使えば 3
台で運用できるなんて事もある ・サーバ台数を試算 性能の差をテスト 現状の負荷状況と照らし合わせる ・実際の導入は段階的に行うと安全 月額 20 万円のサーバ 3 台で賄えそうであっても ひとまず 4 台用意しておいて 負荷状況を確認しながら減らしていく スケールアップとスケールアウト
DB 分割は管理・運用・実装どれも大変 いろんなところで いろんな問題が 発生する・・・ DB 分割アレコレ
・単一 DB の場合 // DB から SELECT $dba->select('user_tbl'); ・ DB
分割対応後 // グローバル DB から SELECT $dba->gb()->select('user_id_tbl'); // 対象ユーザ ID のデータがある DB から SELECT $dba->user($user_id)->select('user_tbl'); // 複数のユーザ DB から SELECT $dba->user_multi($user_id_arr)->select('user_tbl'); コードの一例
▪DB 間を跨いだ JOIN ができない ・基本はアプリレベルで結合する事になる ・敢えて冗長なデータの持ち方をするのもあり Global と User で同じデータを持ってしまう
更新時には必ず両方とも更新する ・特にマスタデータは顕著なので全 DB に持つ マスタデータは Global なデータだが ユーザデータと JOIN したい事が多い 直に SQL を叩いて更新するのは禁止 必ず管理画面、専用スクリプトなどで更新 DB 分割アレコレ
▪ ランキング集計が大変 ・データが各サーバに分散している ・ FEDERATED ストレージエンジンを活用 別サーバのデータが参照できる 遅いが集計バッチでの利用なら使えるレベル INSERT SELECT
で Global にデータを集める ロックがかかるため必ずスレーブを参照する DB 分割アレコレ
▪ ちょっとした抽出作業が大変 「レベル上位者 100 人を抽出して」 という感じの依頼に対して SQL で抽出する場合 全 UserDB
に対して逐次実行 テキストや Excel 表などに手でまとめる というのを毎回やるのは辛い ・専用の管理画面を用意 SQL を投げると SELECT して結果をマージ テーブル表示してくれるだけの画面 DB 分割アレコレ
▪ 串刺し検索が大変 ・ライブラリの実装で吸収 複数 DB でも簡単に扱えるように ・水平分割すればする程コストが増大する 分割数は最低限にとどめておく ・検索結果をキャッシュする 串刺し検索のコストは大きい
同盟員のリストのような何度も参照する情報は 検索結果そのものをキャッシュしてしまう DB 分割アレコレ
▪ トランザクションの管理が煩雑 ・ライブラリの実装で吸収 可能な限り単純化する ・データ不整合発生時には必ずログを残す データ不整合の発生頻度は低い ログを頼りに手で対応 DB 分割アレコレ
▪ 分割数を増やすタイミング ・基本的にはグラフを監視して対応 DB サーバの負荷状況 ユーザ増加傾向を照らしあわせて先手を打つ ・大型プロモーションなどがあるなら試算して対応 ◦◦ 万人のユーザ数増加を見込み 同時接続数が
×× になるので対応 など DB 分割アレコレ
▪ 逆に縮小する場合 ・サーバリソースが余っているなら縮小を検討 ・サーバのスペックを落とす ・複数 DB を 1 つのサーバに同居させる サーバ
A に User1 と User2 サーバ B に User3 と User4 のように配置するとアプリの改修が不用 DB 分割アレコレ
弊社技術ブログでスライドを公開 サンプルコードを交えて紹介しています インフィニットループ技術ブログ PHPMatsuri2013 で発表した資料を公開しました「ソーシャルゲーム案件における DB 分割の PHP 実装~とにかく分割ですよ。 10
回じゃ足りない。 20 回くらい分 割。~」 http://www.infiniteloop.co.jp/blog/2013/07/phpmatsuri-db-partition/ 実装について詳しくは
・スケールアウト可能なシステム構成を取る ・スケールアウトに必要な事項を理解する ・安易なサーバ追加をしない まずはアプリのチューニングを ・サンプリングを行って負荷の原因を特定する 必要であればツールを自作する ・スケールアップとスケールアウトは合わせて検討 案件にあった構成と設計を ・ DB
分割は大変だが避けては通れない道 破綻しないように設計レベルから意識する 運用を楽にするための工夫をする まとめ
インフィニットループでは、エンジニアを募集しています ・社長も含めほぼ全員がプログラマで技術者に優しい環境 ・勤務地は北海道札幌市、他社出向などは無し ・おいしい食べ物、自然いっぱい、花粉少ない、涼しい ・短い通勤時間、徒歩や自転車で通勤が可能 ・ U ターン、 I ターン大歓迎
・ PHP 開発エンジニア ・スマホ開発エンジニア ・ MySQL エンジニア ・インフラエンジニア 求人募集
ご清聴ありがとうございました