49
10 Performance Improvements 性性性性 10 性性 Feb. 18, 2016 Acroquest Technology Co., Ltd. Satoyuki Tsukano

10 performanceimprovements 性能改善10事例

Embed Size (px)

Citation preview

Page 1: 10 performanceimprovements 性能改善10事例

10 Performance Improvements性能改善 10事例

Feb. 18, 2016Acroquest Technology Co., Ltd.

Satoyuki Tsukano

Page 2: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.2

この発表は、私が遭遇した

10個の性能問題とその改善に関する話です。

Page 3: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.3

実際どんな問題が起きたか、具体的な事例を

セキララに紹介します。

Page 4: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.4

とても苦労するので、これを聞いた人は、

二度とこのような問題を起こさないようお願いし

ます。

Page 5: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.5

マジで!

Page 6: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

目次

1. 背景① どんなシステムなの?② 性能問題への取り組み方③ 使ったツールなど

2. 性能改善 10事例3. 振り返り

6

Page 7: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.7

背景

Page 8: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

どんなシステムなの?

1. とあるWebシステムのバックエンド→ここの性能問題に取り組んだ

2. 言語は Java3. XMLをインプットにして、加工した XMLをアウトプットする処理たち

4. Spring、 PostgreSQL(MyBatis)、 Couchbase、 Elasticsearch等のミドルウェアを利用

8

Page 9: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

性能問題への取り組み方

「遅いよ~」と報告のあった処理に対して、

このステップを繰り返す。 (基本パターン )1. 処理時間を測定2. 遅い処理に対して、プロファイリングを実施

3. プロファイリング結果を分析し、遅い箇所を特定

4. 対策を検討5. 対策を実施 → 1に戻って、効果が出たか再測定

9

Page 10: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

性能問題への取り組み方

10

プロファイリングをベースに、あくまでも、

科学的に取り組みます。

Page 11: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

性能問題への取り組み方

(真偽はともかく )「 Stringの結合があるから、遅いのでは?」「正規表現を使った文字列マッチングは、遅いのでは?」噂や推測だけで、動くのは NG。

実際に測定すると、ボトルネックは思いもよらぬ所にあったりします。

11

Page 12: 10 performanceimprovements 性能改善10事例

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

Page 13: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

使ったツールなど

5. NetBeans profilerhttps://profiler.netbeans.org

各メソッドの処理時間を call treeで見ることができる。ENdoSnipeと使い分けましょう。

13

Page 14: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.14

性能改善 10事例

Page 15: 10 performanceimprovements 性能改善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

Page 16: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 1: Couchbaseアクセスの高速化2. 分析

① アプリの処理を確認すると、Couchbaseアクセス用の共通クラスを作り、そこで以下の処理を行っていた。I. Couchbaseに該当のキーが登録されているか確認

(CouchbaseBucket#queryを利用 )II. キーの部分一致で検索して、検索結果に対して該当するキーと一致したものがあるか確認

III. キーが存在する場合、CouchbaseBucket#getの結果を返す。 (キーが存在しない場合、 nullを返す )

② キーの部分一致で検索したら、時間かかるのは当たり前。一方、CouchbaseBucket#getは数ミリ秒で完了した。

16

Page 17: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 1: Couchbaseアクセスの高速化

3. 対策① 存在確認をバッサリ消した。② 1アクセス 200ms→2msになった。

4. 教訓API仕様をよく読むこと。「 Couchbaseが遅い」とか言って、ゴメンナサイ。

17

Page 18: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 2: Couchbaseアクセス数の削減

1. 状況Couchbaseアクセスが遅いのは、解決。しかし、処理全体はまだ遅かった。

2. 分析① Couchbaseに存在するか分からないデータに、アクセスしている。

② 「 getして nullが返ってくる」ケースが多く、実際にデータが存在するケースは 5%程だった。

18

Page 19: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 2: Couchbaseアクセス数の削減

3. 対策次の処理にする。① CouchbaseBucket#queryで存在するキーのリストを取得。

② 存在するキーのみ CouchbaseBucket#getする。

Couchbase周りの対応により、処理全体が 40秒→ 5秒に短縮。

4. 教訓実データの特徴を考慮したアルゴリズムにすること。

19

Page 20: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 3: ディスク経由のコピー処理

1. 状況多くのシーケンスで、JAXB#marshal、 unmarshalが複数回あり、2~ 5秒かかっている。

20

Page 21: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 3: ディスク経由のコピー処理2. 分析

① 物理ディスク (XMLファイル )に書き込み→読み込み、という流れで JAXB オブジェクトをコピーしていた。

② このプロジェクトでは、通常の JAXB オブジェクトを加工してあり、親子間で参照を持っていた。org.apache.commons.beanutils.BeanUtils#copyPropertiesは使えない。

③ XMLを経由する処理は尊重する。ただし、メモリ上で XMLを経由して、コピーする。OutputStreamから InputStreamに、高速にコピーしたい!

21

Page 22: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 3: ディスク経由のコピー処理

3. 対策 (java.io.PipedInputStream)① PipedInputStreamを利用できないか?② 試しに使ったら、本当にデッドロックしました。authorは James Goslingさんでした。

③ javadocに書いてあった。スレッド間でStreamをやりとりする場合に使うもの。

⇒ 別のライブラリを探そう。 22

単一のスレッドから両方のオブジェクトを使用することは、スレッドがデッドロックする可能性があるため推奨されていません。 (javadocより引用 )

Page 23: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 3: ディスク経由のコピー処理

3. 対策 (org.apache.commons.io.IOUtils)① IOUtilsを利用できないか?② IOUtils#copyがあるが、

InputStreamを OutputStreamにコピーするもの。

③ 今回は逆なので、使えない。⇒ 別のライブラリを探そう。

23

Page 24: 10 performanceimprovements 性能改善10事例

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 アプリ

Page 25: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 3: ディスク経由のコピー処理

4. 教訓不必要にディスクアクセスしないこと。(「 netty-bufferなんて、知らないよ」との声も )

25

Page 26: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 4: JAXBContextの初期化処理

1. 状況ディスク経由のコピーで遅いのは、解決。

しかし、処理全体ではまだ遅かった。

2. 分析① ときどき、 JAXB#marshal、 unmarshalそのものが遅い。 1回の呼び出しで数百 msかかることがある。

26

Page 27: 10 performanceimprovements 性能改善10事例

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

Page 28: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 4: JAXBContextの初期化処理

2. 分析④ javadocを見てみると、ちゃんと書いてありました。

⑤ すみません、こちらが悪かったです。

3. 対策① JAXB オブジェクトのクラス毎に JAXBContextを

自力でキャッシュするようにした。② 1回目は遅いが、 2回目以降の処理は高速になった。

28

一般に、性能は必ずしも最適とは限りません。性能が重視されるコードを記述する必要のあるユーザーは残りの JAXB API を直接使用するものと見られています。(javadocより引用 )

Page 29: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 4: JAXBContextの初期化処理

4. 教訓API仕様をよく読むこと。「使えない」とか言って、ゴメンナサイ。

29

Page 30: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 5: DBアクセス時のリフレクション処理

1. 状況DBアクセス時にエンティティクラスのコピーがある。 (このシステムでは、この処理は必要な前提 )ここでリフレクションを利用しており、各処理が 1-2秒ずつ遅くなっていた。

2. 分析状況に書いた通り。

30

Page 31: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 5: DBアクセス時のリフレクション処理

3. 対策① リフレクションを利用しないようにする。

getter/setterメソッドでコピーする。② 50テーブル (=エンティティ )とか、手じゃ書けない。

③ Velocity を使い、MyBatisの設定ファイルから、コピー処理を自動生成した。

4. 教訓大量に実行する処理では、リフレクションを使わないこと。

31

Page 32: 10 performanceimprovements 性能改善10事例

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

Page 33: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 6: DBアクセス時の大量 insert処理

3. 対策テーブル毎に、 1SQLにまとめてselect & insertを行うようにする。80秒かかった処理が 2秒になりました。

4. 教訓大量の SQL文を発行せず、まとめて処理すること。

33

Page 34: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 7: Objectの getClass処理

1. 状況巨大なデータを処理したところ、 7分かかった。もっと短くしたい。

2. 分析Object#getClassが累積 2分半程度かかっていた。

34

Page 35: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 7: Objectの getClass処理

3. 対策① クラス名により case文を切り替える共通処理があり、ここで getClassを呼び出していた。この処理の呼び出し回数が多いため、処理時間がかかっている。

② getClassを使わなくて済むように、 case文での処理を各クラスで実行するようにした。 ( 設計的にも、その方が自然だった )

4. 教訓大量の getClassには注意すること。

35

Page 36: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 8: デバッグログ出力処理

1. 状況巨大なデータを処理は 4分半になったが、もっと短くしたい。

2. 分析① デバッグログに出力する文字列の作成に累

積 30秒かかっていた。② Info レベルで実行しているにも関わらず!

36

Page 37: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 8: デバッグログ出力処理

3. 対策① デバッグ文は isDebugEnabledで囲うようにした。

② あまりに基本的なケアレスミスなので、コードを埋め込んだ担当者に食事に奢ってもらう約束をした。

③ Objectの getClass処理改善と合わせて、巨大なデータ処理が 7分→ 4分になった。

4. 教訓デバッグ文は isDebugEnabledで囲うこと。 37

Page 38: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 9: 無駄なスレッド生成処理

1. 状況48時間連続稼働試験を行った際に、スレッド数がじわじわ増加していくのをENdoSnipeで検知した。

2. 分析スレッドダンプを取得し、増加しているスレッドを特定した。

38

Page 39: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 9: 無駄なスレッド生成処理

3. 対策① 特定シーケンスで生成したスレッドが残り続けていた。

② 担当者に確認したところ、以前、不要になったスレッド処理だったことが判明。そのスレッド処理をバッサリと削除した。

4. 教訓① 不要になった処理は削除すること。② ENdoSnipeを使ってチェックすること。 ( 今回はチェックしたので検出できた )

39

Page 40: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 10: メモリリークによるOOM-Killer

1. 状況48時間連続稼働試験を行った際に、OSのメモリ使用量がじわじわ増加する。挙句の果てに、OOM-Killerが発動してしまう。

2. 分析① OOM-Killerの発生時間とアプリのログから、

引き金になったと思われる処理を特定した。② その処理を追っていくと、 RAMディスクにファイルを作成する処理があった。また、そのファイルは削除されることなく残り続けていた。

③ 処理の都合上、一時的にファイル出力していたが、処理完了後は不要なファイルだった。

40

Page 41: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

改善 10: メモリリークによるOOM-Killer

3. 対策① 極力、ファイル出力しないよう、処理を変

更した。② ファイル出力が必要な場合も、最終的にファイルを削除する処理に変更した。

③ ファイルの出力先を RAMディスクでなく、物理ディスクにした。

4. 教訓RAMディスクの使い方には注意すること。

41

Page 42: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.42

振り返り

Page 43: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.43

問題の特徴を理解し、二度と発生させないよう

手を打ちましょう。

Page 44: 10 performanceimprovements 性能改善10事例

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ディスクの使い方には注意する

Page 45: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.45

教訓①1回の処理では問題なくて

も、大量処理で問題となるケースを理解すること。

Page 46: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.46

教訓②API仕様を良く読み、理解して実行すること。

Page 47: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.47

教訓③難しい箇所は

検討会・レビューなどを実施すること。

Page 48: 10 performanceimprovements 性能改善10事例

Copyright © Acroquest Technology Co., Ltd. All rights reserved.

という訳で

48

とても苦労するので、これを読んだ人は、

二度とこのような問題を起こさないようお願いし

ます。

Page 49: 10 performanceimprovements 性能改善10事例

49

ご清聴ありがとうございました。これら事例を他山の石にしてくださ

い!