読者です 読者をやめる 読者になる 読者になる

tom__bo’s Blog

情報系学生がプログラミングしたり、ボルダリングしたりボルダリングしたことを書くブログ。もはやダイアリー

Systems Performance 読んでいく (2章 その2)

Book Linux Performance SystemsPerformance

Systems Performance: Enterprise and Cloudを読んでいく。

前回に引き続き自分用メモ
2章は長かったので、3つくらいに分ける予定。その2は5節のみ。

2.5 Methodology

このセクションではシステムパフォーマンスを分析するための方法論を紹介する それぞれの手法はobservational analysis, experimental analysis, capacity planningなどに分類されていて、表2.4にまとめられている

比較のためのアンチパターンから始まり、パフォーマンスモニタリングやキューイングセオリーがこの章で挙げられている。

2.5.1 Streetlight Anti-Method

  • この手法は明確な手法がないような手法を指している
  • ユーザが知っているコマンドを使って問題を特定しようとすることを表し、この方法で問題は見つかるだろうが、それが本質をついているわけではない
  • この名前は"streetlight effect"をもじったものである。
    • 警官が酔っぱらいが街灯のそばで何かを探しているのを見かけた
    • 警官「何かを探しているんですか?」
    • 酔っぱらい「鍵を落としてしまって、、、」
    • しかし警官が探しても見当たらない
    • 警官「本当にこのあたりで鍵を落としたんですか?」
    • 酔っぱらい「いいえ、でもここには明かりがあって探しやすいので」
  • これはパフォーマンスを悪くしている原因を探す場合も同じ。
    • topコマンド以外の適切なコマンドを知らないので、topコマンドで原因を探す
    • 何かしらは見つかるがそれが原因そのものではない

2.5.2 Random Change Anti-Method

  • これは実験的なアンチパターンである
  • 適当な推測からランダムにチューニングできる値を変化させ、ベンチマークする。これを繰り返しうまく行くまでやる

2.5.3 Blame-Someone-Else Anti-Method

2.5.4 Ad Hoc Checklist Method

  • チェックリストを利用して短い時間で原因を特定する方法
    • 例えば、「"iostat -x 1"を実行しawaitのカラムが10msを超えていたらdiskが遅いと判断できる」などのリスト
  • チェックリストにある値は環境の変化とともに変わりうることに注意しなければならない
  • とくに分析チームのリーダであればある程度こういった基準を作ることで、作業と知見の共有を効率化できるが、このリストは常にアップデートされていないといけない

2.5.5 Problem Statement

問題を定義することはルーチン業務と言えて、以下の項目を質問していくことで完了できる

  • 何によってパフォーマンスの問題があると考えましたか?
  • 以前はこのシステムはうまく動いていましたか?
  • 最近何か変更したものはありますか?ソフトウェアでもハードウェアでも。
  • 問題はレイテンシにありますか?実行時間にありますか?
  • その問題は他の人にも影響がありますか?それともあなただけの問題ですか?
  • 環境は何ですか? ソフトウェア、ハードウェア、バージョン、設定は? これらの質問をすることで迅速な対応が可能なことは多い。

2.5.6 Scientific Method

科学的なプロセスは問題に対して仮説を立て、検証することである。
それは以下のような手順によって行う

  • Question
  • Hypothesis
  • Prediction
  • Test
  • Analysis

ここでのQuestionはパフォーマンスに関する問題である。これに対して原因の仮説を立て、それを計測可能なテストを構築する。
そして、実験し、結果を収集して、分析する。

例えばメモリの少ない環境にシステムを移行しようたところパフォーマンスが悪くなったとする。
ここでその原因はファイルシステムのキャッシュが少なくなったことだと仮設を立てたとしよう。
ここで、両方のシステムでキャッシュミスの割合を観察してみる、"observational test"を行う
そして、実際にメモリを増やして状況が良くなるか、ファイルキャッシュの設定を小さくしてみて状況が悪くなるかなどを確認する"experimental test"を行う

実験は手当たりしだいにやるのではなく、仮説と実験の変更後の予測を明確にし、結果を分析することが重要。

2.5.7 Diagnosis Cycle

  • Scientific methodとにた手法で
  • hypothiesis -> instrumentation -> data -> hypothesisを繰り返す
  • 医者が患者に対して仮説を立てながら診療をしていくサイクルと同じ
  • scientific methodと同じく、仮説と結果の予想をしたうえで行う

2.5.8 Tools Method

ツールに基づいたこのアプローチは以下の手順で行う

  • 利用可能なパフォーマンスツールをリストにする
  • それぞれのツールに対して、それでわかる有用なメトリクスをリストにする
  • それぞれのメトリクスに対して、それが何を意味するかのルールをリストにする この結果として、どのツールを実行してその結果をどう読みとくかがリストになる。

この手法は一般に効果的である一方で、ユーザが知っていたり、実行可能なツールに依存して、システムの全体が見えない可能性がある。
ともするとstreetlight anti-methodと同じで、ユーザが知らない領域は知らないまま放置されることになる。
この手法はツールや得られる情報が膨大にあり、内部では同じことを実行していて、似たようなことを何度もしていた、という状況を避けるのには効果的である。

2.5.9 The USE Method

このUSE(Utilization, Saturation and Error) メソッドはパフォーマンス調査の初期の段階で、システムのボトルネックを見つけるために行われる
すべてのリソースに対してこの3つを確認する。 - Utilization - Saturaiton - Error

[USEの概要]

メインメモリのようないくつかのリソースタイプでは、Utilizationはキャパシティベースのものを利用する。
これは時間ベースのものと異なり、100%に達してしまうとそれ以上のリクエストは受け付けられなくなり、キューに貯めるか、エラーを返すようになる。
USEメソッドならこれを特定することができる。

パフォーマンスを悪化させるが、すぐに気づかないことがあるので、エラーを確認することは大切。
特にリトライなどの失敗に対するリカバリーがある場合は冗長な作業に早く気づく必要がある。

Toolメソッドと比較して、USEメソッドは全てのツールではなく全てのリソースに対して調査をする。
これは疑問に思うべき全ての項目を列挙できる助けになり、もしこの疑問に答えられるツールを知らなかったとしても、 この答えられなかった疑問というのは"known-unknown"となり、パフォーマンス分析者にとって非常に重要なものである。

USEメソッドは重要な制限されたメトリクスに焦点を絞った方法なので、できるだけ早く項目を確認し、問題が見つからなければ他の手法に移る必要がある。

以下にUSEメソッドのフローを示す

図2.12 f:id:tom__bo:20161214154429p:plain

この方法でシステムのボトルネックになりそうなものを見つけることができる。
ただ、最初に見つかったものがボトルネックというわけではないので、複数の問題が見つかったらそれぞれを検証する必要がある。

[リソースの列挙]

USEメソッドを使う上で最初にやるべきなのはリソースを列挙することである。できるだけ完璧なリストを作ろう
一般的な例を以下に上げる

  • CPUs: sockets, cores, hardware threads(Virtual CPUs)
  • Main memory: DRAM
  • Network interfaces: Ethernet ports
  • Storage devices: disks
  • Controllers: storage, network
  • Interconnects: CPU, memory, I/O

ほとんどは1つのリソースとして利用されるが、Strage deviceの用にキャパシティとI/Oの両方がパフォーマンスに影響するタイプのものもある。
これに注意して、影響し得るものを列挙しよう

もうひとつの方法として、図2.13のようにコンポーネントのダイアグラムを書く方法がある。
これによりひと目で全容が一望でき、かつボトルネックも理解しやすくなる

図2.13 f:id:tom__bo:20161214154506p:plain

よくCPU, memory, I/O interface, bussesについては概観されている。
しかし幸運なことにこれらがボトルネックになることは少ない。残念なことにここがボトルネックになっていたら問題を解決するのは難しい。
おそらく、マザーボードを取り替えるか、負荷を減らすように考えなければならないだろう。

[メトリクスの列挙]

リソースのリストが完成したら、それらに対するメトリクスを決定しよう

表2.5 f:id:tom__bo:20161214154522p:plain

これらのメトリクスについてツールを使って値を取っていく。
簡単に取れるものや取りづらいもの、全く取れないものがあるだろうが、これにより"known-known"と"known-unknown"を区別することができる

表2.6の計測が難しい物の例を示す。

  • cpu error(ECCの回数など)
  • memory error
  • network saturation
  • 等など...

これらは標準のOSのツールで計測することは難しく、特別な設備が必要なものも多い
付録A,BにLinux,Solarisベースのシステムのハードウェアリソースのチェックリストがある

いくつかのリソースは似たように検出される。
これらはたいていアプリケーション全体ではなく、システムの一部によるものである。

  • Mutex locks: 利用率は時間ベースであり、サチュレーションはlockによるキュー待ちでも派生する
  • Thread pools: 利用率は時間ベースであり、スレッドプールにより待機しているプロセスによってサチュレーションが起こる
  • Process/thread capacity: システムはプロセスやスレッドに上限がある。これを超えて待っているものはサチュレーションを起こし、割り当てられなければエラーとなる
  • File descriptor capacity: Process/threadと似ているが、ファイルディスクリプターが要因。

[メトリクスの読み方の提案]

メトリクスタイプごとの解釈の提案がある。

  • Utilization
    • 100%のutilizationはそこがボトルネックになっているサイン。
    • 利用率を計測する間隔の問題で、60%であっても短期間のバーストが実は細かく起きていることもある。
    • なので、60%であってもボトルネックである可能性はある
  • Saturation
    • どんな場合であってもサチュレーションが起きていれば問題である。
    • これらはキュー待ちの長さやその時間によって計測できる
  • Errors
    • エラーがある事自体が調査に良くない

2.5.10 Workload Characterization

Workload Characterizationはシンプルだが強力な手法である。
これは内部のシステムのパフォーマンスではなく、単にInputに注目する。システムの構成に問題はないし、設定にも問題がないが、どうもシステムの負荷が高い時に使う

以下の質問に答えることで負荷の分類ができる

  • Who: 誰が負荷を招いているか. Process ID, user ID, IP address?
  • Why: なぜ負荷が高いのか? code path, stack trace?
  • What: 負荷の種類は? IOPS, throughput, ...?
  • How: 時間ごとにどのように変化しているか? 日毎の時間帯によるパターンか?

おそらくここだろうという見当があったとしてもこれらを全て確認する必要がある。
もしかすると変更に合わせてDoS攻撃を受けていたなんてこともある。
この分析方法はアーキテクチャと負荷をうまく分離できる方法である

2.5.11 Drill-Down Analysis

Drill-Down分析は問題の高いレベルから初めて、高いレイヤでの発見から領域を狭めつつ掘り下げていく方法である。
ソフトウェアのレイヤから、必要であればハードウェアの領域まで根本の原因を探して掘り下げる

この方法は"Solaris Performance and Tols"に提供されており、以下の3つのステージからなる

  • Monitoring: 継続的に高いレイヤの統計情報をとっておき必要なときに警告を出す。
  • Identification: 疑わしい問題から始める。ここから範囲を絞っていきボトルネックとなり得る場所を特定する
  • Analysis: 特定のシステム領域をより詳細に調査する。根本原因を定量化できるように努める

Monitoringは会社全体のシステムにおいて行うべきで、それはクラウド上のものも含む。
この伝統的な方法は SNMP(Simple Network Monitoring Protocol)を使うことで、コマンドによって得られる短期間のログではわからないこともわかるようになる。

Identificationはサーバと相互に行う。コマンドラインツールからvmstat, iostat, mpstatを叩くことが多いが、 最近ではGUIのツールも出てきている

Analysisのツールはトレースやプロファイリングをしてくれるものを含み、特定の領域でより詳細な情報を取得するために使われる
これはレイヤーごとに特化したものが必要になり、strace, truss, perf, DTraceなどがある

Analysisの段階で使える方法に"Five Whys"というテクニックがある。
なぜ?という疑問をこれを繰り返すことで予期せぬ自体を見逃さないようにできる
例)

  • なぜDBがクエリに対して応答が遅くなり始めたのか?
  • メモリのページングによってdisk I/Oが遅延し始めたから。Why?
  • DBのメモリ使用率が高くなりすぎているから。Why?
  • アロケータがメモリをより必要とするようになったから。Why?
  • アロケータのメモリフラグメントの問題が発生しているから

2.5.12 Latency Analysis

Latency分析は、処理の完了にかかる全体の時間から、細かい区分に分割していく方法である。
drill-down分析と似ているが、Latency分析ではソフトウェアレイア以上を対象にLatencyのみを考えて掘り下げていく

  • クエリのレイテンシに問題がある?
    • Yes
  • レイテンシはCPUを使用している時間?使用していない時間?
    • 使用していない時間
  • CPUを使用していない時間に何をしている?
    • disk I/O
  • disk I/Oの時間はランダムアクセス?それとも転送時間?
    • 転送時間

このようにレイテンシを更に細かい処理のレイテンシに分解し根本の原因を探っていく

2.5.13 Method R

Method RはOracleによって開発された手法で、Oracle traceイベントに基づいてレイテンシの根源を発見する
これはDBの分野で使われるものだが、システム全体にも適用することができる
(ここでは詳細について説明がない)

2.5.14 Event Tracing

システムは様々なイベントを処理している。
例えば、CPU命令、disk I/Oやdiskのコマンド, network packets, system callsなどなど。。。
パフォーマンスの分析はこれらの集合をまとめて全体の実行時間や平均時間を見ているに過ぎない。
これでは重要なイベントを見過ごしてしまうことになり、個々のコンポーネントを調査するにはイベントを確認するほうがよい

例えばネットワークであればtcpdump, strageのI/Oであればiosnoopを使うことでコンポーネントで発生しているイベントを見ることができる。

システムコールもtraceの対象として一般的な領域である。Linuxではstrace, Solarisではtrussが使われる。
これらのツールは様々な情報を表示することができ、イベントをトレースするときは以下の情報を探すと良い

  • Input: リクエストタイプや方向、サイズなど
  • Times: 開始時間、終了時間、レイテンシ
  • Result: エラーのステータス、結果のサイズ

タイムスタンプの情報は非常に重要で、レイテンシを正確に把握することができる。
あるイベントのレイテンシが高いと思っていたら、実はその前のイベントが長引いたせいで、キューで待機していた時間が含まれていたと言った現象が避けられる

2.5.15 Baseline Statistics

過去のメトリクスを現在のメトリクスと比較することは非常に有効な手段である。
負荷やリソースの利用率の変化の始まりを見極めることで、問題を遡ることができる。
しかし、カーネルがbootした時からの情報を提供してくれるだけでは難しい(ないよりマシだが)

この方法では幅広い観察ツールを使って事前に出録をロギングしておく必要がある。 システムの変更の前と後で、これらの情報を分析することで、異常な変化が起きていないか確認することができる。 更に、"通常の状態"がどんな状態であったかを知ることができる。

2.5.16 Static Performance Tuning

Static performance tuningは、これまでのように動作しているシステムに対して行うのではなく、停止しているか設計時に行う手法である。
この手法では負荷がかかっていない状態で以下のステップで設定を確認する

  • コンポーネントについて理解しているか?
  • 意図して負荷に対して適切な設定をしたか?
  • 意図して負荷に対して、適切な環境で設定がなされたか?
  • コンポーネントがエラーを起こしたことがある場合、それに対応出来ているか?

2.5.17 Cache Tuning

アプリケーションやOSはI/Oのパフォーマンスを向上するために複数のキャッシュを利用しているだろう。
以下は一般的なそれぞれのレベルのキャッシュに対する戦略である。

  • 負荷の環境とできるだけ近い状態でキャッシュが高い割合で使えるようにする
  • キャッシュが有効になっていて機能しているか確認する
  • キャッシュヒット率やミスの割合を確認する
  • 負荷に対してキャッシュを調整する
  • キャッシュを利用する範囲を制限するなどして、ターゲットになる負荷に適切に負荷が使われるようにする

キャッシュを見渡して、同じデータが別のところで重複してキャッシュされていないか確認する必要がある。
またCPUキャッシュを利用できるのであればメインメモリのキャッシュを使わないようにするなど全体でのキャッシュの効率化も考える

2.5.18 Micro-Benchmarking

Micro-benchmarkingテストは単純で人工的な負荷を用いて行う。
これはScientific methodを支持するために行うことが多く、ある仮説を検証するために行う。

”industory benchmarking"と異なる点は、特に現実世界の負荷を模倣して行われることで、特に複雑にしてシステムを理解することもできる。 この手法は準備や理解が難しいことはなく多くの要因が絡みあうこともない。 "micro-benchmark tool"や"load generator tool"が使われることがあり、どちらかを使うだけでも良い。

秒単位でのmicro-enchmarkingの対象には以下のようなものがある。

  • Syscall time: fork(), exec(), open(), read(), close()
  • File system reads: キャッシュのファイルから1byteから1MBのデータを読みだす
  • Network throughput: TCPエンドポイント間でのデータ転送速度を計測

マイクロベンチマーキングは素早く複数回行いその平均を考慮する必要がある。
また、ベンチマークについては12章で再度扱う

f:id:tom__bo:20160611194354p:plain