Contenu connexe
Similaire à MySQL Casual な生活
Similaire à MySQL Casual な生活 (20)
MySQL Casual な生活
- 2. 自己紹介
• hatak (@hisashi)
• 株式会社コロプラ (2010/01-)
• 開発からインフラ運用・障害対応まで
• 最近はスマフォアプリを少々
• わりと何でもやります
• インフラ / Perl な場所に時々います
• 写真好きです
- 5. コロプラ とは
• 位置ゲーのプラットフォーム
• 「コロニーな生活」などの
モバイル向けゲームを自社運営
• パートナー様へのAPI提供
• プラットフォームの規模感
(2011年12月現在)
• ユーザ数 : 250万人
• 位置登録回数 : 4,300万回/月
• 総PV数 : 37億/月
(パートナー様コンテンツを除く)
- 6. 全体的な構成
• コロプラ(プラットフォーム)
• ユーザ情報
• 課金情報
• 位置情報
• コロプラ上に各アプリが存在
• それぞれのサービスとして開発 アプリ アプリ アプリ
• コロプラのAPIをJSONで呼び出し
• パートナー様のサービスからも利用
COLOPL PF
- 7. 基本的な構成
• サーバ
• 自社運用の物理とクラウドを併用
App
• CentOS 5.x/6.x
INSERT
UPDATE SELECT
• 開発言語 DERETE
• Java/PHP
MasterDB LVS
• データベース
rep
lica
tion
• MySQL CommunityServer 5.1/5.5
• ほぼ InnoDB
SlaveDB SlaveDB
• master : slave = 1 : n の構成
• LVSでslaveを束ねて利用
- 8. MySQL 5.5 使ってます
• 本番系DBサーバの7-8割がMySQL 5.5
• InnoDBのパフォーマンス と utf8mb4 が目的
• 5.5.12 (2011/04) 頃から、新規構築 or サーバ交換の際にアップデート
• 今のところは大きなトラブルなく運用中
• my.cnf の修正を忘れずに my.cnf
• 廃止されたオプション -default-character-set = utf8
+character-set-server = utf8
• default-character-set -default_table_type = InnoDB
DB
+default_storage_engine = Inno
• default_table_type
• InnoDB Plugin がビルトインのため plugin-load 等の記述が不要
前回(#2)の @oranie さんのLT資料にまとまってました (@oranie++)
- 11. データベースサーバには運用が必要
• 長く運用していると様々なメンテナンスが必要となる
• 論理な事情(件数の多いインデックス張り替え、スキーマ変更、etc...)
• 物理な事情(ディスク故障、筐体交換、etc...)
• Slaveの場合はわりと簡単
• 代替サーバを構築して入れ替え
• Masterの場合は面倒
• うっかりやると刺さる(処理が詰まってしまう)
• でもサービス停止してのメンテナンスは告知などが大変
• 停止させれば作業は楽になるところもあるけど
• ゲームバランスや仕様の兼ね合いからも避けたい
- 12. オンラインマスタ切り替え方法
• マニュアルオペレーションで対応する一つの例です
• メリット:無停止で切り替えられる
• デメリット:入れ替え分のサーバ台数が必要
• 前提条件
対象DB系統だけでユニークキーが決定できる
• 大まかな流れ
• 現在のSlaveを基に、新規のMaster&Slaveセットをまるごと準備
• 新SlaveをLVSに入れ、代わりに現Slaveを外す
• 現Masterから新Masterに変える
- 13. 切り替えの流れ
• 右図のような構成の場合 App
• 更新系:MasterDB INSERT
UPDATE SELECT
• 参照系:LVS経由でSlaveDBに分散 DELETE
MasterDB.cur LVS
replication
SlaveDB.cur SlaveDB.cur
- 15. 切り替えの流れ
• MasterDB.newの下にSlaveDB.newを構築 App
• 新系統は十分にpreloadしておく INSERT
UPDATE SELECT
DELETE
MasterDB.cur LVS
replication
MasterDB.new SlaveDB.cur SlaveDB.cur
replication
SlaveDB.new SlaveDB.new
- 16. 切り替えの流れ
• SlaveDB.newをLVSに入れていく App
INSERT
UPDATE SELECT
DELETE
MasterDB.cur LVS
replication
MasterDB.new SlaveDB.cur SlaveDB.cur
replication
SlaveDB.new SlaveDB.new
- 17. 切り替えの流れ
• 代わりにSlaveDB.curをLVSから外す App
INSERT
UPDATE SELECT
DELETE
MasterDB.cur LVS
replication
MasterDB.new SlaveDB.cur SlaveDB.cur
replication
SlaveDB.new SlaveDB.new
- 18. 切り替えの流れ
• これでSlaveDBの切り替え完了 App
• MasterDB.new の auto_increment INSERT
値を少し増やしておく UPDATE SELECT
DELETE
• 重複を避けるため
MasterDB.cur LVS
replication
MasterDB.new
replication
SlaveDB.new SlaveDB.new
- 19. 切り替えの流れ
• AppからのMasterDB参照先を変える App
• DNS 設定を書き換えるなど INSERT
UPDATE SELECT
• MasterDB.curからのレプリケーショ DELETE
ンが完全に止まるまで待つ
MasterDB.cur LVS
replication
MasterDB.new
replication
SlaveDB.new SlaveDB.new
- 20. 切り替えの流れ
• 切り替え完了! App
INSERT
UPDATE SELECT
DELETE
LVS
MasterDB.new
replication
SlaveDB.new SlaveDB.new
- 21. preloadとは
• 事前に InnoDB Buffer pool にデータを読み込ませておく作業
• 本番投入直後でも Buffer pool hit rate をあげるため
• ディスクI/O が極端に上がることを避ける
• 特にMaster切り替えはいきなり本番投入 & しかも切り戻せない
• いったん全テーブルのデータを読み込ませる
• 全テーブルに対して SELECT * FROM ... でも読み込める
• ダミーでINSERTするとbinlogに書かれるのでslaveにも伝播できる
mysql> CREATE TABLE _preload LIKE <table_name>;
mysql> ALTER TABLE _preload ENGINE = BLACKHOLE;
mysql> INSERT INTO _preload SELECT * FROM <table_name>;
mysql> DROP TABLE _preload;
- 22. より現実に即したpreload
• やっぱり本番DBと同じ状況を再現してあげるのが良い
• 現実のクエリを受ける方が最適化される
• Weightを低めにしてLVSに入れてしまう
• 他の本番DBからリレーする
• tcpdump + pt-query-digest
• 特にMasterからリレーする場合はSELECTだけにするように注意
$ sudo /usr/sbin/tcpdump -i eth0.100 port 3306 -s 65535 - x
-n -q -tttt | pt-query-digest --type=tcpdump --no-report --
execute h=server.new -u'hoge' -pfuga --filter='$event-
>{fingerprint} =~ m/^select/'
- 23. 気をつけるところ
• 応用すればだいたいのケースには対応できる
• mk-slave-move でSlaveをつなぎ替えるとか
• 障害の時でもまずはMasterを切り替えてしまって復旧するとか
• ただしエラーになる可能性はある
• Master切り替え時に Duplicate Key などのエラーになる可能性はある
• Masterを手早く切り替えられるようにしておく必要
• 新旧のMasterに更新クエリが来ている状態は極力短く
• トランザクションを意識した作りでないとデータ不整合も起こりうる得る
- 28. よくある設定箇所
• sync_binlog = 0
• ディスクに同期するとやはり遅いので。。
• innodb_flush_log_at_trx_commit = 0 [Default: 1]
• クラッシュ時の信頼性を犠牲にパフォーマンスを得る設定
• 0 のとき、メンテナンス等で更新クエリが止まったときに
一気にディスクI/Oが発生したりする挙動がありました
• innodb_support_xa = 0 [Default: 1]
• ディスクへのFlushを減らすため
• そのほかもDBの系統ごとに試してみたりしている
• サービスによってクエリの傾向が違うので個別に調整が必要
- 29. サーバ自体もチューニング
• ディスクのマウントオプションを変えてみる
• atime周りやI/Oスケジューラを変えてみるとか
• ext4でのライトバリア無効化
• メモリを詰めるだけ積む
• 自社運用の物理サーバであればメモリを積みまくるのも一つ
• 標準的なDBサーバには72GBのものを採用しています
• ただし、落とし穴が...
• 「空のデータセットにデータが溜まっていくとswapしてしまう事件」
• 続きはLTで...
- 31. MySQL Connector/J
• Java系サービスではJDBCドライバとして MySQL Connector/J を利用
• 設定できるプロパティは結構多い
• 設定値のプロパティファイルがバンドルされている
• ソースを見るとよく分かる ( https://launchpad.net/connectorj )
• maxPerformance, fullDebug などは設定の参考に
$ cat maxPerformance.properties
...
cachePrepStmts=true
cacheCallableStatements=true
cacheServerConfiguration=true
useLocalSessionState=true
elideSetAutoCommits=true
alwaysSendSetIsolation=false
enableQueryTimeouts=false
- 35. 未然に防ぐことは大事
• デプロイ時に担当者が異常がないかを見ることは当然
• でも、デプロイ以外のトリガーのケースも多々ある
• 時々巡回したりしてチェック
• メトリクス監視(Cacti など)の値の変化
• 負荷をバルクチェックしてみたり (SNMP使う自前スクリプトとか)
• アラートが上がったら何かある
ステータス監視(Nagios など)からの通知
サービス内掲示板やTwitterに投稿されているユーザさんの声
ユーザサポートからの確認
- 36. なにかおかしい?ときのチェック箇所
• 何がおきてるか、を把握
• アプリケーションサーバ
• エラーログ
• MySQLサーバ
• SHOW FULL PROCESSLIST コマンド
• slowlog
• tcpdump ¦ pt-query-digest でクエリ読む
• 何があったか、を把握
• ソースツリー & git log を追っていく
AdventCalendar の @riywo さんの記事にまとまってました (@riywo++)
- 37. MySQL設定/テーブル定義に起因する障害
• RANGE PARTITION 作り忘れ
• cron で作るようにしていても、サーバ切り替え時に移行漏れ。。
• 切り替え時の接続ユーザ権限修正忘れ
• MasterDB/SlaveDB などで権限を変えてるケース
• auto_increment 桁あふれ
• 設計時、そんなに長く使うとは思っていないことも多々あったりします
このような障害は、多くの場合 Nagios 監視などで未然に防げる
- 38. サーバに起因する障害
• SHOW PROCESSLIST で見たときに Commit が滞留するなど
• ディスクI/Oがボトルネックになってるケースが多い
• OSレベルでのエラー検知ができないケースもある
• syslogなどにはエラーは見受けられないがパフォーマンスが上がらない
• サーバベンダー提供のツールで見るとRAID構成ディスクの障害予兆が。。
• 自動での定期チェック時にパフォーマンス低下してたケース
HWレベルでもしっかりとチェックしておく必要がある
- 39. アプリケーションに起因する障害
• クエリが詰まる
• 適切にインデックスが張られているかチェック
• クエリ自体に無理がないか確認
• 元々想定していた以上のデータが蓄積されていることも。。
• Sleep が溜まる
• アプリケーション側で処理がブロックされている
• 挙動がおかしいアプリケーションサーバがあることも
複合的な要因のこともあるので、コード読んだりすることも必要