Upload
acroquest-technology
View
3.575
Download
1
Embed Size (px)
Citation preview
10 Performance Improvements性能改善 10事例
Feb. 18, 2016Acroquest Technology Co., Ltd.
Satoyuki Tsukano
Copyright © Acroquest Technology Co., Ltd. All rights reserved.2
この発表は、私が遭遇した
10個の性能問題とその改善に関する話です。
Copyright © Acroquest Technology Co., Ltd. All rights reserved.3
実際どんな問題が起きたか、具体的な事例を
セキララに紹介します。
Copyright © Acroquest Technology Co., Ltd. All rights reserved.4
とても苦労するので、これを聞いた人は、
二度とこのような問題を起こさないようお願いし
ます。
Copyright © Acroquest Technology Co., Ltd. All rights reserved.5
マジで!
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
目次
1. 背景① どんなシステムなの?② 性能問題への取り組み方③ 使ったツールなど
2. 性能改善 10事例3. 振り返り
6
Copyright © Acroquest Technology Co., Ltd. All rights reserved.7
背景
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
どんなシステムなの?
1. とあるWebシステムのバックエンド→ここの性能問題に取り組んだ
2. 言語は Java3. XMLをインプットにして、加工した XMLをアウトプットする処理たち
4. Spring、 PostgreSQL(MyBatis)、 Couchbase、 Elasticsearch等のミドルウェアを利用
8
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
性能問題への取り組み方
「遅いよ~」と報告のあった処理に対して、
このステップを繰り返す。 (基本パターン )1. 処理時間を測定2. 遅い処理に対して、プロファイリングを実施
3. プロファイリング結果を分析し、遅い箇所を特定
4. 対策を検討5. 対策を実施 → 1に戻って、効果が出たか再測定
9
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
性能問題への取り組み方
10
プロファイリングをベースに、あくまでも、
科学的に取り組みます。
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
性能問題への取り組み方
(真偽はともかく )「 Stringの結合があるから、遅いのでは?」「正規表現を使った文字列マッチングは、遅いのでは?」噂や推測だけで、動くのは NG。
実際に測定すると、ボトルネックは思いもよらぬ所にあったりします。
11
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
使ったツールなど
解析のために使ったもの。1. ENdoSnipe
https://www.endosnipe.com/https://github.com/endosnipe/ENdoSnipe
2. デバッガ3. Java付属ツール (jstack、 jstat等 )4. ログ
① コンポーネントの in/out② 他サブシステムとの in/out③ ミドルウェアとの in/out
12
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
使ったツールなど
5. NetBeans profilerhttps://profiler.netbeans.org
各メソッドの処理時間を call treeで見ることができる。ENdoSnipeと使い分けましょう。
13
Copyright © Acroquest Technology Co., Ltd. All rights reserved.14
性能改善 10事例
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 1: Couchbaseアクセスの高速化
1. 状況① Couchbaseアクセスが遅い、と報告あり。② 1データを取得するのに 200ms③ Couchbaseの javaクライアントを利用。
com.couchbase.client.java.CouchbaseBuckethttps://github.com/couchbase/couchbase-java-client
15
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 1: Couchbaseアクセスの高速化2. 分析
① アプリの処理を確認すると、Couchbaseアクセス用の共通クラスを作り、そこで以下の処理を行っていた。I. Couchbaseに該当のキーが登録されているか確認
(CouchbaseBucket#queryを利用 )II. キーの部分一致で検索して、検索結果に対して該当するキーと一致したものがあるか確認
III. キーが存在する場合、CouchbaseBucket#getの結果を返す。 (キーが存在しない場合、 nullを返す )
② キーの部分一致で検索したら、時間かかるのは当たり前。一方、CouchbaseBucket#getは数ミリ秒で完了した。
16
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 1: Couchbaseアクセスの高速化
3. 対策① 存在確認をバッサリ消した。② 1アクセス 200ms→2msになった。
4. 教訓API仕様をよく読むこと。「 Couchbaseが遅い」とか言って、ゴメンナサイ。
17
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 2: Couchbaseアクセス数の削減
1. 状況Couchbaseアクセスが遅いのは、解決。しかし、処理全体はまだ遅かった。
2. 分析① Couchbaseに存在するか分からないデータに、アクセスしている。
② 「 getして nullが返ってくる」ケースが多く、実際にデータが存在するケースは 5%程だった。
18
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 2: Couchbaseアクセス数の削減
3. 対策次の処理にする。① CouchbaseBucket#queryで存在するキーのリストを取得。
② 存在するキーのみ CouchbaseBucket#getする。
Couchbase周りの対応により、処理全体が 40秒→ 5秒に短縮。
4. 教訓実データの特徴を考慮したアルゴリズムにすること。
19
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 3: ディスク経由のコピー処理
1. 状況多くのシーケンスで、JAXB#marshal、 unmarshalが複数回あり、2~ 5秒かかっている。
20
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 3: ディスク経由のコピー処理2. 分析
① 物理ディスク (XMLファイル )に書き込み→読み込み、という流れで JAXB オブジェクトをコピーしていた。
② このプロジェクトでは、通常の JAXB オブジェクトを加工してあり、親子間で参照を持っていた。org.apache.commons.beanutils.BeanUtils#copyPropertiesは使えない。
③ XMLを経由する処理は尊重する。ただし、メモリ上で XMLを経由して、コピーする。OutputStreamから InputStreamに、高速にコピーしたい!
21
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 3: ディスク経由のコピー処理
3. 対策 (java.io.PipedInputStream)① PipedInputStreamを利用できないか?② 試しに使ったら、本当にデッドロックしました。authorは James Goslingさんでした。
③ javadocに書いてあった。スレッド間でStreamをやりとりする場合に使うもの。
⇒ 別のライブラリを探そう。 22
単一のスレッドから両方のオブジェクトを使用することは、スレッドがデッドロックする可能性があるため推奨されていません。 (javadocより引用 )
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 3: ディスク経由のコピー処理
3. 対策 (org.apache.commons.io.IOUtils)① IOUtilsを利用できないか?② IOUtils#copyがあるが、
InputStreamを OutputStreamにコピーするもの。
③ 今回は逆なので、使えない。⇒ 別のライブラリを探そう。
23
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 3: ディスク経由のコピー処理
3. 対策 (netty-buffer)① netty-bufferを利用すれば、解決する。
(通信フレームワーク Netty 内のライブラリ )② しかも、コピー回数が 2回で済む。
単純に考えると、コピー的な処理が 3回必要。
OutputStreamと InputStreamが保持するバッファを共有すれば、コピー的な処理は 2回で済む。リ
24
アプリ OutputStream InputStream アプリ
アプリ OutputStream & InputStream アプリ
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 3: ディスク経由のコピー処理
4. 教訓不必要にディスクアクセスしないこと。(「 netty-bufferなんて、知らないよ」との声も )
25
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 4: JAXBContextの初期化処理
1. 状況ディスク経由のコピーで遅いのは、解決。
しかし、処理全体ではまだ遅かった。
2. 分析① ときどき、 JAXB#marshal、 unmarshalそのものが遅い。 1回の呼び出しで数百 msかかることがある。
26
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 4: JAXBContextの初期化処理
2. 分析② コードを見てみると、 javax.xml.bind.JAXBContext#getContextでstatic 変数に JAXBContextをキャッシュしていた。
1回前の呼び出しと、 JAXB オブジェクトのクラス毎が同じ場合はキャッシュが利用されて高速。異なるクラスの場合は、 JAXBContextの初期化が走る。
③ 「これじゃ、まともに使えないよ!」と思いました。authorは Kohsuke Kawaguchiさんでした。
27
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 4: JAXBContextの初期化処理
2. 分析④ javadocを見てみると、ちゃんと書いてありました。
⑤ すみません、こちらが悪かったです。
3. 対策① JAXB オブジェクトのクラス毎に JAXBContextを
自力でキャッシュするようにした。② 1回目は遅いが、 2回目以降の処理は高速になった。
28
一般に、性能は必ずしも最適とは限りません。性能が重視されるコードを記述する必要のあるユーザーは残りの JAXB API を直接使用するものと見られています。(javadocより引用 )
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 4: JAXBContextの初期化処理
4. 教訓API仕様をよく読むこと。「使えない」とか言って、ゴメンナサイ。
29
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 5: DBアクセス時のリフレクション処理
1. 状況DBアクセス時にエンティティクラスのコピーがある。 (このシステムでは、この処理は必要な前提 )ここでリフレクションを利用しており、各処理が 1-2秒ずつ遅くなっていた。
2. 分析状況に書いた通り。
30
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 5: DBアクセス時のリフレクション処理
3. 対策① リフレクションを利用しないようにする。
getter/setterメソッドでコピーする。② 50テーブル (=エンティティ )とか、手じゃ書けない。
③ Velocity を使い、MyBatisの設定ファイルから、コピー処理を自動生成した。
4. 教訓大量に実行する処理では、リフレクションを使わないこと。
31
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 6: DBアクセス時の大量 insert処理
1. 状況ある処理に 80秒かかっているが、機能的には、数秒で完了しても良いくらい。
2. 分析① DBに対して大量の insertが発生しており、それだけで半分近くの時間を使っている。
② 特に 4テーブルに対する insertが頻発しており、各テーブルに対して 3~ 4 桁の insertが発生していた。
③ Selectした結果を、そのまま 1 レコードずつinsertしていた。
32
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 6: DBアクセス時の大量 insert処理
3. 対策テーブル毎に、 1SQLにまとめてselect & insertを行うようにする。80秒かかった処理が 2秒になりました。
4. 教訓大量の SQL文を発行せず、まとめて処理すること。
33
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 7: Objectの getClass処理
1. 状況巨大なデータを処理したところ、 7分かかった。もっと短くしたい。
2. 分析Object#getClassが累積 2分半程度かかっていた。
34
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 7: Objectの getClass処理
3. 対策① クラス名により case文を切り替える共通処理があり、ここで getClassを呼び出していた。この処理の呼び出し回数が多いため、処理時間がかかっている。
② getClassを使わなくて済むように、 case文での処理を各クラスで実行するようにした。 ( 設計的にも、その方が自然だった )
4. 教訓大量の getClassには注意すること。
35
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 8: デバッグログ出力処理
1. 状況巨大なデータを処理は 4分半になったが、もっと短くしたい。
2. 分析① デバッグログに出力する文字列の作成に累
積 30秒かかっていた。② Info レベルで実行しているにも関わらず!
36
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 8: デバッグログ出力処理
3. 対策① デバッグ文は isDebugEnabledで囲うようにした。
② あまりに基本的なケアレスミスなので、コードを埋め込んだ担当者に食事に奢ってもらう約束をした。
③ Objectの getClass処理改善と合わせて、巨大なデータ処理が 7分→ 4分になった。
4. 教訓デバッグ文は isDebugEnabledで囲うこと。 37
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 9: 無駄なスレッド生成処理
1. 状況48時間連続稼働試験を行った際に、スレッド数がじわじわ増加していくのをENdoSnipeで検知した。
2. 分析スレッドダンプを取得し、増加しているスレッドを特定した。
38
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 9: 無駄なスレッド生成処理
3. 対策① 特定シーケンスで生成したスレッドが残り続けていた。
② 担当者に確認したところ、以前、不要になったスレッド処理だったことが判明。そのスレッド処理をバッサリと削除した。
4. 教訓① 不要になった処理は削除すること。② ENdoSnipeを使ってチェックすること。 ( 今回はチェックしたので検出できた )
39
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 10: メモリリークによるOOM-Killer
1. 状況48時間連続稼働試験を行った際に、OSのメモリ使用量がじわじわ増加する。挙句の果てに、OOM-Killerが発動してしまう。
2. 分析① OOM-Killerの発生時間とアプリのログから、
引き金になったと思われる処理を特定した。② その処理を追っていくと、 RAMディスクにファイルを作成する処理があった。また、そのファイルは削除されることなく残り続けていた。
③ 処理の都合上、一時的にファイル出力していたが、処理完了後は不要なファイルだった。
40
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
改善 10: メモリリークによるOOM-Killer
3. 対策① 極力、ファイル出力しないよう、処理を変
更した。② ファイル出力が必要な場合も、最終的にファイルを削除する処理に変更した。
③ ファイルの出力先を RAMディスクでなく、物理ディスクにした。
4. 教訓RAMディスクの使い方には注意すること。
41
Copyright © Acroquest Technology Co., Ltd. All rights reserved.42
振り返り
Copyright © Acroquest Technology Co., Ltd. All rights reserved.43
問題の特徴を理解し、二度と発生させないよう
手を打ちましょう。
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
問題の特徴
44
No.
問題 教訓
1 Couchbaseアクセスの高速化 API仕様をよく読む2 Couchbaseアクセス数の削減 実データの特徴を考慮したアルゴ
リズムにする3 ディスク経由のコピー処理 不必要にディスクアクセスしない4 JAXBContextの初期化処理 API仕様をよく読む5 DBアクセス時のリフレクション処理
大量のリフレクションは使わない
6 DBアクセス時の大量 insert処理
大量の SQLはまとめて処理する
7 Objectの getClass処理 大量の getClassは使わない8 デバッグログ出力処理 デバッグ文は isDebugEnabledで
囲う9 無駄なスレッド生成処理 不要になった処理は削除する
ENdoSnipeを使ってチェックする10 メモリリークによる OOM-
KillerRAMディスクの使い方には注意する
Copyright © Acroquest Technology Co., Ltd. All rights reserved.45
教訓①1回の処理では問題なくて
も、大量処理で問題となるケースを理解すること。
Copyright © Acroquest Technology Co., Ltd. All rights reserved.46
教訓②API仕様を良く読み、理解して実行すること。
Copyright © Acroquest Technology Co., Ltd. All rights reserved.47
教訓③難しい箇所は
検討会・レビューなどを実施すること。
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
という訳で
48
とても苦労するので、これを読んだ人は、
二度とこのような問題を起こさないようお願いし
ます。
49
ご清聴ありがとうございました。これら事例を他山の石にしてくださ
い!