Pyrocope ( OSS )によるPythonのデバッグパフォーマンスの問題


プロファイラによるPythonでのパフォーマンス問題のデバッグ方法


問題の根源を得るための炎グラフの使用


私は個人的な経験から、Pythonサーバ上でのパフォーマンスの問題をデバッグすることは信じられないほどイライラすることができます.通常、増加したトラフィックや一時的なバグは、エンドユーザーが何かが間違っていることを報告する原因となります.
多くの場合、バグが発生した状況を正確に再現することは不可能ですので、私たちのコード/インフラストラクチャのどの部分がサーバー上のパフォーマンスの問題に対して責任があるのかを理解しようとしていました.
この記事では、あなたのコードを連続的にプロファイルして、どの線がそれらの厄介なパフォーマンス問題に対して責任があるかを明らかにするために、炎グラフを使用する方法について説明します.

なぜCPU性能に気をつけるべきか


CPUの利用率は、一般的にクラウドで自分のソフトウェアを実行する企業によって使用されるアプリケーションのパフォーマンスのメトリックです.
実際、Netflixのパフォーマンス・アーキテクトのBendan Greggは、CPUの使用量を1 %削減することは、その規模で発生するリソースの節約によって、大きな改善とみなされている.しかし、小さな会社は、サイズに関係なく、CPUがしばしば実行中のソフトウェアの2つの非常に重要な面と直接相関しているので、パフォーマンスを改善するとき、同様の利点を見ることができます:
  • サーバにどのくらいのお金を費やしているのか- CPUのリソースが必要で、サーバーを走らせるのに要するコスト
  • エンドユーザーエクスペリエンス-あなたのサーバーのCPUに置かれたより多くの負荷、低速のウェブサイトやサーバーは
  • になります
    したがって、以下のようなCPU使用のグラフを参照してください.

    100 % CPU利用の期間中は、次のようにします.
    エンドユーザーはイライラする経験を持っています(すなわち、アプリ/ウェブサイトはスローロードされます)
  • サーバーコストは、追加の負荷
  • を処理するために新しいサーバーを提供した後に増加します
    問題は:コードのどの部分がCPUの利用の増加に責任がありますか?それは炎のグラフが来るところです!

    フレームグラフを使用してパフォーマンスの問題をデバッグする方法


    以下のフレームグラフは、CPU使用がスパイクされた画像の「インシデント」に対応するtimespanを表します.このスパイクの間、サーバーのCPUは費やされました:foo()の時間の
  • 時間
  • bar()の時間の
  • 時間
  • ドルのサーバー経費
  • ドル

    あなたは、超詳細円グラフのような炎グラフを考えることができます.
  • 炎グラフの幅は、時間範囲
  • の100 %を表します
  • 各ノードは、関数
  • を表す
    最大のノードがCPU資源の大部分を占めている
  • 各ノードはそれより上のノードによって呼ばれます、
  • この場合、24579142はトータルの時間範囲の75 %を占めているので、私たちはCPU使用率を減少させるためにfoo()とそれが呼ぶ機能を改善することができます(そして$ $を保存してください).

    炎のグラフとテーブルを作成する


    この例を実際のコードで再現するには、パフォーマンス問題をデバッグするために特別に構築されたオープンソースの連続プロファイラPyrosCcopeを使用します.仕事をしているサーバーをシミュレートするために、私は、通過される期間のために仕事をすることをシミュレートするfoo()機能を作成しました.このように、私たちは、以下のコードからこの炎グラフを生成することによって、時間の75 %とwork(duration)を時間の25 %をとっているfoo()を複製することができます

    # where each iteration simulates CPU time
    def work(n):
        i = 0
        while i < n:
            i += 1
    
    # This would simulate a CPU running for 7.5 seconds
    def foo():
        work(75000)
    
    # This would simulate a CPU running for 2.5 seconds
    def bar():
        work(25000)
    
    次に、75000から8000までのbar()時間を減らすためにコードを最適化するとしましょう、しかし、コードの他のすべての部分は同じままにしました.新しいコードとフレームグラフは次のようになります.

    # This would simulate a CPU running for 0.8 seconds
    def foo():
        # work(75000)
        work(8000)
    
    # This would simulate a CPU running for 2.5 seconds
    def bar():
        work(25000)
    

    foo ()の改良


    火炎グラフのおかげで、私たちは、foo()が我々のコードのボトルネックであることをすぐに確認することができました.最適化した後、CPUの利用率を大幅に減らすことができました.

    これは合計CPU使用率が66 %減少したことを意味します.あなたのサーバーのために10万ドルを支払っていたならば、あなたは今ちょうど$ 34000のために同じ荷を管理することができました.