「Pythonが遅い」と決めつける前に

GISの大量データ移行案件で、 もともと1件単位の処理を前提としていた 移行ツールを引き継ぎました。

大量データを実際に投入してみると、 移行完了までに 約2年半 かかる見込み。

仕様書も十分に残っておらず、 詳しい知見者もいない。

当然、 最初から 「ここがボトルネックです」 と教えてくれる人もいません。

だから、とりあえず実際に動かしてみる。

そして、 処理中のサーバーが どんな状態になっているのかを 見ることにしました。

まず使ったのがtopだった

Linuxのプロセス状況を見るときに まず確認したのが topです。

top

実行すると、 CPU使用率やメモリ使用量、 実行中のプロセスなどを リアルタイムで確認できます。

大量データ移行処理を実行しながら topを見ることで、

CPU どの程度使われているか
Memory メモリ使用量が増えていないか
Process 移行処理がどう動いているか

といったことを 実際の処理と合わせて 確認していきました。

CPUが余っていることに気づいた

ここで重要だったのが、 「処理が遅い」という結果だけを見るのではなく、 CPU使用率を見ることでした。

もしCPUが常に100%近く使われているなら、 CPU側がボトルネックになっている可能性があります。

逆に、 CPUにかなり余裕があるのに 処理が遅いのであれば、

「CPUを使い切れていない理由は何だ?」

という疑問が出てきます。

そこから、 Python側の処理構造を調べ、 並列化できる部分がないかを 検討しました。

結果として、 ProcessPoolExecutor を使った並列処理へつながっていきます。

vmstatでサーバー全体を見る

topだけではなく、 システム全体の状態を見るために vmstatも使いました。

vmstat 1

1を指定すると、 1秒間隔で状態を確認できます。

CPUだけではなく、 メモリやI/Oなども含めて システム全体の状態を見ることができます。

性能テスト中に見るポイント

CPU → 処理能力を使えているか

Memory → メモリが圧迫されていないか

I/O → ディスクなどの処理が詰まっていないか

Process → 処理がどのように動いているか

こうして、 「Pythonの中」だけではなく 「Pythonが動いている環境」まで 見るようになりました。

1秒ごとの状態をログとして残したくなった

vmstat 1を 画面で眺めるだけでも 状態は分かります。

ただ、 性能テストを何度も繰り返していると、

「この時点ではどうだった?」
「さっきのテストと比較すると?」

といったことを 後から確認したくなります。

そこで使っていたのが、 awkと組み合わせた方法です。

vmstat 1 | awk '{print strftime("%y/%m/%d %H:%M:%S"), $0}'

|vmstatの出力を awkへ渡します。

awk側では strftime()を使って 現在時刻を付けます。

処理の流れ

vmstat

1秒ごとのシステム状態

パイプ

awk

タイムスタンプを追加

「その瞬間のリソース状況」を 時刻付きで追えるようにする。

性能テストでは、 こうした小さな工夫が 後から効いてきます。

topとvmstatは役割が違う

どちらも性能確認に使えますが、 見ているものは少し違います。

top プロセス単位で見る
vmstat システム全体を見る
awk 出力を加工・記録する

例えば、 Pythonの移行処理だけが CPUを大量に使っているのか。

それとも、 システム全体として I/Oなど別の部分が ボトルネックになっているのか。

それぞれの情報を 組み合わせて判断します。

CPU使用率だけで判断しない

性能改善を始めたころは、 どうしても CPU使用率が気になります。

「CPUが余っている」

「もっと使おう」

という考え方です。

ただ、 実際に並列処理を入れていくと、 CPU以外の問題も見えてきます。

CPU 計算処理
Memory データ保持
I/O データ読み書き
Network 外部サービスとの通信

CPUを使えるようになった結果、 次はI/Oがボトルネックになる。

そんなこともあります。

性能改善は、 一つの数字だけを見る作業ではありません。

Pythonの改修とLinuxの監視をセットで考える

この案件で重要だったのは、 PythonとLinuxを 別々のものとして考えなかったことです。

性能改善のループ

Pythonを改修

移行処理を実行

top / vmstatで確認

CPU・メモリ・I/Oを確認

処理時間を比較

ボトルネックを判断

またPythonを改修

つまり、 Linuxのコマンドは 「インフラ担当者だけが使うもの」 というより、

アプリケーションの性能を調べるための 観測手段

として使っていました。

性能テストは「速くなったか」を確認するだけではない

改修前と改修後で 処理時間を比較する。

これはもちろん重要です。

ただ、 それだけでは 「なぜ速くなったのか」 が分かりません。

そこで、

処理時間 何秒・何分かかったか
CPU どれくらい使ったか
Memory どれくらい消費したか
I/O 待ちが発生していないか

複数の指標を合わせて、 改修の効果を確認しました。

「速くなった」ではなく、 「なぜ速くなったのか」まで見る。

実際には、最初から監視方法が決まっていたわけではない

この案件を説明すると、

Linuxのリソース監視を実施し、 CPU・メモリ・I/Oを分析。
ボトルネックを特定して Pythonプログラムを最適化した。

と書けば、 きれいな話になります。

でも、 実際はもっと泥臭い。

「なんか遅い」

とりあえず topを見る。

CPUが余っている。

「じゃあ、 もっと使えるんじゃないか?」

Pythonを調べる。

並列処理を試す。

今度はメモリやI/Oを見る。

またテストする。

そんな繰り返しでした。

仕様書も、 「このコマンドを使って監視する」 という計画書もありません。

問題が出てきたから調べる。
調べたら試す。
試したら測る。

その繰り返しの中で、 少しずつ性能改善の方法が 固まっていきました。

最終的に「インフラを見る目」が必要だった

この案件では、 Pythonのコードを書くだけでは 解決できませんでした。

かといって、 インフラだけを見ても 解決できません。

必要だったのは、

Python

Linux

GIS

性能テスト

を一緒に見ることでした。

「アプリケーションが遅い」 という問題を、 アプリケーションだけで解決しない。

これは、 この案件を通してかなり実感したことです。

Linux監視から学んだこと

GISの大量データ移行を 高速化していく中で、 Linuxのコマンドは 単なる運用知識ではありませんでした。

top プロセス・CPU・メモリを確認
vmstat システム全体の状態を確認
awk 出力を加工して時刻情報を付加
Python 処理そのものを改修
性能テスト 改修効果を計測

そして、 これらを組み合わせながら 少しずつボトルネックを潰していきました。

最終的なイメージ

既存ツール

大量データ投入

約2年半かかることが判明

Linuxでリソース確認

Python処理を分析

pandas / 並列処理

再度リソース確認

改修・テスト

約2週間 ※リソース集中時

運用と並行する場合
約2か月

最初から「Linux監視をやろう」と 計画していたわけではありません。

遅い。
なぜ?
CPUは?
メモリは?
I/Oは?
Pythonは?
GIS側は?

そうやって 一つずつ見ていった結果、 アプリケーションだけではなく インフラ側まで含めて 性能を見るようになりました。

「コードを書く」だけではなく、 「コードが動いている環境を見る」。

これが、 このGISデータ移行案件で Linuxの性能監視から得た 一番大きな経験でした。