my sqlで2億件のシリアルデータと格闘した話

Post on 11-Apr-2017

7.333 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

MySQL で 2 億件のシリアルデータと格闘したチューニングの話

YAPC::Asia Tokyo 2015Kenji Saito / @saiken3110

自己紹介

・斉藤 健二  Kenji   Saito・ @saiken3110・ Java   PHP   Perl・ Oracle   MySQL

今日の内容

MySQL で2 億件のシリアルデータを

つかった話

主にチューニングの話です。Perl も最後にちょっとでてきます。。

Topic・システムの概要・負荷テストした話・ 2 億件登録したときの話・ update ではまった話・今後の課題 ・まとめ

システムの概要(フロント)

商品購入

シリアル入力

入力

・商品 A・サイズ

商品サイズ選択

登録

XXL     ▼

商品シリアル紐付 利用履歴

システムの概要(バックエンド)

シリアルマスタ

商品名

シリアル数

商品・シリアル紐付け

紐付け

商品シリアル紐付

2 億件!! 1億件!!

・ Red Hat 5.6・ Perl 5.20・ MySQL 5.6

DB サーバのインフラ事情①

・ CPU   2 コア・メモリ 8 G・ディスク  450G・ /tmp   2G

DB サーバのインフラ事情②

 →  2 コア、 8G 。。。 2 億件。。。

Topic・システムの概要

・負荷テストした話・ 2 億件登録したときの話・ update ではまった話・今後の課題 ・まとめ

□ 対象テーブル ・シリアルマスタ(2億件) ・商品シリアル紐付(1億件)

□ 内容 ・インデックスを使った検索 ・プライマリーキーでの検索 ・フルスキャンでの検索 ・フルスキャンでの count ・フルスキャンでの order by ・ insert ・ alter table (カラム追加)

負荷テスト

いろいろと問題が・・・

○count に 84 秒、 CPU を 80 ~ 95 % 使用  → アプリケーションからは    実行しないため、対応不要とした

○order by や alter で /tmp が枯渇

  →  tmp_dir を物理ディスクに変更    → エラーがでなくなったが、       50G くらい一時領域を使ってた。。       → 運用で回避することにした

負荷テスト 結果①

ERROR 3 (HY000) at line 1: Error writing file '/tmp/MY3p25s8' (Errcode: 28 - No space left on device)

○ 商品シリアル紐付のデータファイルが 28G に。。  → パフォーマンスのために、    各レコードで商品情報を持っていたのをやめた     → 管理用の TBL を作り、       正規化、 15G に縮小!

○insert が意外と早い  「 LOAD DATA 」で 3 億件の登録が 70 分   → 後でいろいろ問題が発生。。

負荷テスト 結果②

Topic・システムの概要・負荷テストした話

・ 2 億件登録したときの話・ update ではまった話・今後の課題 ・まとめ

2 億件登録したときの話①

シリアルマスタ

商品名

シリアル数

商品・シリアル紐付け

紐付け

商品シリアル紐付

2 億件!! 1億件!!

ココ

負荷テストのときに、3億件が 70 分で登録できた

実際のデータで2億件登録しようとしたら、、       

75時間かかった。。

2 億件登録したときの話②

□ 実行時間の推移

2 億件登録したときの話③

※500 万件ずつ「 LODA DATA 」で登録

8000万件から急激に遅延

□ 負荷テストのときより遅くなった原因 → 負荷テストのときはシリアルが連番   実際は、ランダムな数字   →  insert 時に index の再作成が発生!

□8000 万件くらいから急激に遅くなった原因 →  innodb_buffer_pool が枯渇   → 検証してみた

2 億件登録したときの話④

innodb_buffer_pool と insert①

さすがに 75 時間を何度もは無理なので、

innodb_buffer_pool_size を 10 分の1くらいで

試してみた

40 時間くらいかけて。。

innodb_buffer_pool と insert②

innodb_buffer_pool_size を 1G 、 500M 、 250M で10 万件の insert × 100 回にかかる時間を計測

250M で実行した場合、340万件から遅延が発生

500M で実行した場合、700万件から遅延が発生

innodb_buffer_pool と insert③

データ量(登録件数)が増加し、innodb_buffer_pool が枯渇すると、insert が大幅に遅延し始める。

 → メモリからあふれて、   ディスク I/O が発生しているため。

   → メモリを増やすことで、     データ量が多くても遅延が発生しない

ついでに、、

主キーがシーケンスならインデックスの再構築が

早いんじゃないかと思った

試してみた

再びの 40 時間。。

主キーと insert①

主キーをシリアル(ランダムな数字)からシーケンスに変更して、 2 億件の登録にかかる時間を比較

○ 変更前 ・主キー:シリアル ・ユニークキー:シーケンス

○ 変更後 ・主キー:シーケンス ・ユニークキー:シリアル

主キーと insert②

○ 2億件の登録にかかった時間   75時間 → 30時間に改善!   → 主キーが連番になったことで、     主キーのインデックス構築にかかる時間が減少

変更前は2億件の登録に約 75時間

変更後は2億件の登録が約 30時間で完了

Topic・システムの概要・負荷テストした話・ 2 億件登録したときの話

・ update ではまった話・今後の課題 ・その他  Perl のチューニング・まとめ

update ではまった話①

シリアルマスタ

商品名

シリアル数

商品・シリアル紐付け

紐付け

商品シリアル紐付

2 億件!! 1億件!!

ココ

負荷テストのときは、100 万件の紐付が74秒だった

お客さんの前でデモしたら、、       

1時間かかった

update ではまった話②

update ではまった話③

□ アプリケーションの動き ※1回の max が 100 万件で1万件ごとにコミット

 1)シリアルマスタからステータスが   「未使用」のものを取得

 2)商品シリアル紐付へ、   入力した商品の情報をつけてシリアルを insert

 3)シリアルマスタのステータスを「使用済み」に update   → 1回の update で 35 秒かかっていた     →  100 万件の場合、 35 秒 ×100 回! 

update ではまった話④

□update が遅かった原因 →  update 時に index の再構築が発生    → シリアルがランダムなため、      紐付く主キーの読込みが重い。。

read_buffer_size ( 16k)ずつ読み込まれる紐付く主キーがバラバラなため、読込が毎回発生

update ではまった話⑤

□ 対応 ステータス管理をやめ、 管理テーブルを作成し、  update 自体を不要にした

 → 60分が45秒に改善!    → インデックスの再構築怖い。。。

そんなこんなで、なんとか無事リリースできました

よかった

Topic・システムの概要・負荷テストした話・ 2 億件登録したときの話・ update ではまった話

・今後の課題 ・その他  Perl のチューニング・まとめ

今後の課題①

□ 増分バックアップ 現状mysqldump でフルバックアップ  → 今後さらにデータが増えてくると、    バイナリログを使った    増分バックアップの方がよさそう

今後の課題②

□ データ退避とかパーティショニング  → 古いシリアルの退避とか、    できれば「 xxxx_2015 」とか作りたくないので、    うまくパーティションとか使えると。。

Topic・システムの概要・負荷テストした話・ 2 億件登録したときの話・ update ではまった話・今後の課題

・その他  Perl のチューニング・まとめ

その他  Perl のチューニング①

□ コネクションプーリングっぽいこと

 コネクションオブジェクトを シングルトンにし、 1worker 1 コネクションを共有

  → コネクション生成のコストをなくした

その他  Perl のチューニング②

□ マスタデータをキャッシュ

  PSGI サーバ起動時に、メモリに DB のマスタデータを保持  →  worker 内でメモリは共有されるため、     DB アクセスが不要になる

    ※ただし、「 Copy-On-Write 」なので、     書き換えようとすると、メモリリークの原因になる

    ※ただし、マスタデータを変更する場合には、     再起動が必要になるので、     本当は memcached とかを使った方がよさそう

まとめ①

□innodb_buffer_pool_size は大きい方がいい

□ 主キーはシーケンスにした方が insert が早い

□ インデックスの再構築は意外とばかにならない

まとめ②

□ 負荷テスト大事 実際のデータに近いデータでやる

□ 結局計測してみないとわからないことは多い  → 効果測定にすごく時間がかかるので、    負荷テストとかは、早めにやる

ありがとうございました!

top related