INTRODUCTION
「Pythonが遅い」と決めつける前に
GISの大量データ移行案件で、 もともと1件単位の処理を前提としていた 移行ツールを引き継ぎました。
大量データを実際に投入してみると、 移行完了までに 約2年半 かかる見込み。
仕様書も十分に残っておらず、 詳しい知見者もいない。
当然、 最初から 「ここがボトルネックです」 と教えてくれる人もいません。
だから、とりあえず実際に動かしてみる。
そして、 処理中のサーバーが どんな状態になっているのかを 見ることにしました。
01
まず使ったのがtopだった
Linuxのプロセス状況を見るときに
まず確認したのが
topです。
top
実行すると、 CPU使用率やメモリ使用量、 実行中のプロセスなどを リアルタイムで確認できます。
大量データ移行処理を実行しながら
topを見ることで、
といったことを 実際の処理と合わせて 確認していきました。
02
CPUが余っていることに気づいた
ここで重要だったのが、 「処理が遅い」という結果だけを見るのではなく、 CPU使用率を見ることでした。
もしCPUが常に100%近く使われているなら、 CPU側がボトルネックになっている可能性があります。
逆に、 CPUにかなり余裕があるのに 処理が遅いのであれば、
「CPUを使い切れていない理由は何だ?」
という疑問が出てきます。
そこから、 Python側の処理構造を調べ、 並列化できる部分がないかを 検討しました。
結果として、
ProcessPoolExecutor
を使った並列処理へつながっていきます。
03
vmstatでサーバー全体を見る
topだけではなく、
システム全体の状態を見るために
vmstatも使いました。
vmstat 1
1を指定すると、
1秒間隔で状態を確認できます。
CPUだけではなく、 メモリやI/Oなども含めて システム全体の状態を見ることができます。
CPU
→ 処理能力を使えているか
Memory
→ メモリが圧迫されていないか
I/O
→ ディスクなどの処理が詰まっていないか
Process
→ 処理がどのように動いているか
こうして、 「Pythonの中」だけではなく 「Pythonが動いている環境」まで 見るようになりました。
04
1秒ごとの状態をログとして残したくなった
vmstat 1を
画面で眺めるだけでも
状態は分かります。
ただ、 性能テストを何度も繰り返していると、
「この時点ではどうだった?」
「さっきのテストと比較すると?」
といったことを 後から確認したくなります。
そこで使っていたのが、
awkと組み合わせた方法です。
vmstat 1 | awk '{print strftime("%y/%m/%d %H:%M:%S"), $0}'
|で
vmstatの出力を
awkへ渡します。
awk側では
strftime()を使って
現在時刻を付けます。
vmstat
↓
1秒ごとのシステム状態
↓
パイプ
↓
awk
↓
タイムスタンプを追加
「その瞬間のリソース状況」を 時刻付きで追えるようにする。
性能テストでは、 こうした小さな工夫が 後から効いてきます。
05
topとvmstatは役割が違う
どちらも性能確認に使えますが、 見ているものは少し違います。
例えば、 Pythonの移行処理だけが CPUを大量に使っているのか。
それとも、 システム全体として I/Oなど別の部分が ボトルネックになっているのか。
それぞれの情報を 組み合わせて判断します。
06
CPU使用率だけで判断しない
性能改善を始めたころは、 どうしても CPU使用率が気になります。
「CPUが余っている」
↓
「もっと使おう」
という考え方です。
ただ、 実際に並列処理を入れていくと、 CPU以外の問題も見えてきます。
CPUを使えるようになった結果、 次はI/Oがボトルネックになる。
そんなこともあります。
性能改善は、 一つの数字だけを見る作業ではありません。
07
Pythonの改修とLinuxの監視をセットで考える
この案件で重要だったのは、 PythonとLinuxを 別々のものとして考えなかったことです。
Pythonを改修
↓
移行処理を実行
↓
top / vmstatで確認
↓
CPU・メモリ・I/Oを確認
↓
処理時間を比較
↓
ボトルネックを判断
↓
またPythonを改修
つまり、 Linuxのコマンドは 「インフラ担当者だけが使うもの」 というより、
アプリケーションの性能を調べるための 観測手段
として使っていました。
08
性能テストは「速くなったか」を確認するだけではない
改修前と改修後で 処理時間を比較する。
これはもちろん重要です。
ただ、 それだけでは 「なぜ速くなったのか」 が分かりません。
そこで、
複数の指標を合わせて、 改修の効果を確認しました。
「速くなった」ではなく、 「なぜ速くなったのか」まで見る。
FIELD NOTE
実際には、最初から監視方法が決まっていたわけではない
この案件を説明すると、
Linuxのリソース監視を実施し、 CPU・メモリ・I/Oを分析。
ボトルネックを特定して Pythonプログラムを最適化した。
と書けば、 きれいな話になります。
でも、 実際はもっと泥臭い。
「なんか遅い」
↓
とりあえず
topを見る。
↓
CPUが余っている。
↓
「じゃあ、 もっと使えるんじゃないか?」
↓
Pythonを調べる。
↓
並列処理を試す。
↓
今度はメモリやI/Oを見る。
↓
またテストする。
そんな繰り返しでした。
仕様書も、 「このコマンドを使って監視する」 という計画書もありません。
問題が出てきたから調べる。
調べたら試す。
試したら測る。
その繰り返しの中で、 少しずつ性能改善の方法が 固まっていきました。
09
最終的に「インフラを見る目」が必要だった
この案件では、 Pythonのコードを書くだけでは 解決できませんでした。
かといって、 インフラだけを見ても 解決できません。
必要だったのは、
Python
+
Linux
+
GIS
+
性能テスト
を一緒に見ることでした。
「アプリケーションが遅い」 という問題を、 アプリケーションだけで解決しない。
これは、 この案件を通してかなり実感したことです。
SUMMARY
Linux監視から学んだこと
GISの大量データ移行を 高速化していく中で、 Linuxのコマンドは 単なる運用知識ではありませんでした。
そして、 これらを組み合わせながら 少しずつボトルネックを潰していきました。
既存ツール
↓
大量データ投入
↓
約2年半かかることが判明
↓
Linuxでリソース確認
↓
Python処理を分析
↓
pandas / 並列処理
↓
再度リソース確認
↓
改修・テスト
↓
約2週間
※リソース集中時
運用と並行する場合
約2か月
最初から「Linux監視をやろう」と 計画していたわけではありません。
遅い。
なぜ?
CPUは?
メモリは?
I/Oは?
Pythonは?
GIS側は?
そうやって 一つずつ見ていった結果、 アプリケーションだけではなく インフラ側まで含めて 性能を見るようになりました。
「コードを書く」だけではなく、 「コードが動いている環境を見る」。
これが、 このGISデータ移行案件で Linuxの性能監視から得た 一番大きな経験でした。