2017年1月19日木曜日

ORACLEデータベース並列処理の際に気を付けること

バッチ処理などのパフォーマンスを上げるために、処理の並列化を行うことがあります。
今回のコラムでは、ORACLEの知識だけで高速化を試みた結果、痛い目を見た話です。
■要件
営業所ごとに1年の売り上げを集計する夜間バッチがありました。
そのバッチは、年追うごとに扱うデータが増えていき、終了時間も徐々に日中のオンライン開始時間に近づいていました。
そこで、今後のことも考えて、このバッチのパフォーマンスチューニングをすることになりました。
■目標設定
パフォーマンスチューニングは、「早くなればいい」という漠然とした目標ではいけません。
何時間何分で完了するといった、具体的な指標が無ければ、終わりのない旅になってしまいます。
今年の実績は、夜中1時から明け方7時まで6時間掛かっていました。
業務と話し合い、来年は、夜中1時から明け方4時までの3時間という半分の時間で終わらせる目標を設定しました。
■現状調査
今のバッチは、営業所単位で存在するデータを、A営業所目からF営業所目まで順(シリアル)に処理します。
バッチの中身を解析すると、テーブルには営業所コード列があり、営業所コード列単位にデータを取得して処理していました。
serial.jpg
■対策
そこで、テーブルとバッチを営業所単位に分割し、バッチ処理を並列に行うことを検討しました。AからFまで同時に行うのです。
そして、バッチが並列に動作しても、ディスクアクセスの競合が発生しないように、テーブルは営業所コードをキーとしたパーティションテーブルにしました。
para1.jpg
■テスト
開発環境でのテストを行います。
開発と本番サーバのCPU、メモリは同等の性能です。
ディスクは、本番の1/3の容量しかないので、データ量は約1/3でテストします。
まずは、現状のバッチ、テーブル構成で性能測定を行いました。
データを戻した後は、並列化したバッチとパーティションテーブル構成での性能測定です。
順調に動いているように見えましたが、データベースサーバのCPU使用率が右肩上がりなのが気になります。
とうとう、100%でピタリと、はり付いたまま動かなくなりました。
13.jpg
と、同時にデータベースサーバがダウンしました。
一度に起動するプロセスが多く、処理量も6倍になったためCPUが限界に達したのです。
そこで、並列度を以下の通り見直して再測定を行いました。
para2.jpg
1度に並列処理する営業所の数を6つから3つに減らしました。A、C、Eを並列処理し、次にB、D、Fを並列処理します。
今度は、CPU使用率も安定しており、無事バッチ処理が完了しましたが、現状よりも遅いという結果が出ました。
開発環境なので仕方ないのですが、変更後のバッチを動作している裏で、業務の動作テストが行われていたようです。
AWRを確認すると、変更後のバッチが動作している時間帯には、バッチ以外のSQLによる負荷が確認できました。
それで、速いはずの変更後バッチが遅かったのです。
ちなみに、変更前のバッチが実行された時間帯のAWRには、余計な処理は流れていなかったです。
これでは測定にならないので、テストしてる人達には離席していただき、変更後のバッチを再度測定しました。
予想通りの結果が出ました。開発環境で変更前後のバッチの完了時間を比較しました。変更前は2時間、変更後は40分でした。
並列化したことで完了時間が1/3位に短縮されています。
開発なのでデータ量は1/3です。単純計算で、データ量が本番と同じなら、変更後のバッチは2時間で完了するはずです。
なので、3時間以内という目標は達成できるはず。
■運用
修正後のバッチが動作する前日までに、テーブルをパーティション化し、最新のバッチを配置しました。
修正後のバッチが初めて動く日、夜間立ち合いを行いました。
開始数分で、ログにエラーを出力してバッチはダウンしました。
14.jpg
調査すると、同時に3営業所分のデータ処理を行ったことで、undo表領域の単位時間当たりの使用量が3倍になり、現状の
undo表領域の容量では足りなくなったのが原因でした。
開発環境の検証では、データ量が本番の1/3だったため、こういった現象が発生しなかったのだと考えられます。
ちなみに、変更前は1営業所ずつ処理してたので、単位時間当たりのundo消費量は、現状のundo表領域のサイズで間に合って
いたのでしょう。
バッチがダウンしたため、データベースは途中までの処理をrollbackしている状態です。
お客様はかんかんです。
暫定対策として、undo表領域を増やしてリトライすることになりました。
■振り返り
紆余曲折を経て、バッチに掛かる時間は目標時間内に収まるようになりました。
並列化するうえで注意すべき点としては、単位時間当たりのリソース消費量でしょう。
例えば、今まで1時間掛かっていた処理を、3パラレルにして20分で終わらせるためには、ディスク、CPU、メモリなどのリソースに
ついて考慮が必要です。
単位時間当たりの処理量を増やし、1時間の1/3、20分で処理を終わらせるのですから単純計算で、3倍のリソースが必要です。
現状のサーバリソースで持ちこたえられない場合、ディスク、CPU、メモリが枯渇して処理自体が失敗することだってあり得ます。
このあたりの考慮がすっぽり抜けていたため、起きた失敗でした。
高速化と物理的なリソースは切っても切れない縁なのです。

0 件のコメント:

コメントを投稿