前回のおさらい&今回の概要
前回では、ユーザから受け取ったSQLに対して、DBMSがどのような手順を踏んでデータを取り出す(または更新する)か、という一連の流れを解説しました。今回は、そこから一歩進んで、実際にシステムに性能問題が発生したとき、どのように対処するか、という実践的なところに踏み込んで解説したいと思います。
前回の内容を前提とするものではありませんが、オプティマイザを中心とするクエリ評価エンジンの機能については、知っていたほうが理解しやすいでしょう。忘れてしまったという方は、第4回(1)で簡単におさらいしてください。
パフォーマンスチューニングは医療に近い
筆者は、仕事でパフォーマンスチューニングを引き受けることがよくあります。性能試験の一環として遅延が発生した処理のチューニングを行うこともあれば、すでにカットオーバーされて運用に入っているシステムが遅延を起こして、お祭りの会場になっているところにのこのこやっていくこともあります。
その経験に照らして、筆者は、パフォーマンスチューニングというのは医者の仕事に近い、と思っています。
もちろん、筆者は医者をやったことがあるわけではないので、医師の仕事のやり方については漠然とした理解しかありませんし、障害対応を広く「システムとして異常な状態から正常な状態への復旧」と位置付ければ、チューニングに限らず広くデバッグ全般をそうたとえることも可能でしょう。
しかしそれでも、パフォーマンスチューニングのプロセスはやはり、医師が行う「治療」のプロセスに非常に似通っていると思うのです。また、その類似性を意識することで、チューニングの手順を整理、理解しやすくなるメリットがあると思います。
そのようなわけで、本稿を読んだあと、みなさんが性能問題を抱えたシステムを見たら「ああ、病気のかわいそうな子だ。治してあげないと」と思うようになって、さらにその治し方のフローを具体的に頭に描けるようになれば、本稿の目的は達成されたことになります。それでは、本連載最後の1回も、どうぞお付き合いよろしくお願いします。
- 対象読者
- (DBに限らず)システムの遅延が発生して困った経験のある人
- 性能試験を担当することになった人
- 性能問題への対処方法について勉強したい人
- 対象環境
治療としてのチューニング
いきなり治療する?
ある日皆さんは、ユーザ、あるいはプロジェクトマネージャなどからこういう言葉をかけられました。
- 「システムのパフォーマンスが悪いんだけど見てもらえないかな?」
こんなとき、みなさんならどういう手順でチューニングを進めていこうとするでしょうか。いきなりデータベースのパラメータを変えるとか、バッファキャッシュのメモリ割り当てを変えてみる、というような唐突な行動は、よもや取らないでしょう。そういう場当たり的で闇雲な対処をしている現場もないではありませんが、真似してはいけません。
ここで冒頭筆者が言った言葉を思い出していただきたいのですが、パフォーマンスチューニングとは一種の治療行為です。とすれば、パフォーマンスの悪いシステムは患者に該当します。体調不良を訴えて病院にやってきた患者に、医者はまず何をするでしょう。どんなヤブ医者でも、いきなり投薬や手術に飛びついたりはしませんよね。
そう、まず行うべきは診察・検査です。なぜかといえば、病気や怪我の部位が特定できなければ、どんな治療をしてよいかもわからないからです。胃潰瘍に風邪薬は効きませんし、動脈から出血しているのに静脈を止血しても意味がありません。
チューニングの一般的なフロー
チューニングの一般的なフローを図示すると、図1のようになります。
まず、チューニング(=治療)の前にやるべきことは検査です。つまり、「どこで」「なぜ」遅延しているのかを突き止めることです。チューニングプランを立てるのはそのあとです。これは一見まどろっこしい、迂遠(うえん))な方法に見えるかもしれません。しかし、何の証拠もつかまないまま場当たり的な対処(治療)を行うことは、まぐれ当たり以外でうまくいくことはありませんし、状況をより悪化させることもあるのです。
さらに言うと、パフォーマンスチューニングという仕事は、遅延原因の特定までできれば半分終わったも同然なのです。その理由は、ちょうど医療の世界で多くの傷病(しょうびょう)に対してすでに治療方法が確立されているのと同じように、遅延原因に対するチューニング方法も半ば自動的に決まってくるからです。
データベースの鉄則
検査をせずに治療するようなヤブ医者にはなるな
それでは、検査・診察について、個々のステップを詳しく見ていきましょう。
① 遅延個所の調査
話をわかりやすくするために、3層構造の一般的なWebアプリケーションのシステムを考えましょう。物理的なサーバとしては、Webサーバ、アプリケーションサーバ(APサーバ)、データベースサーバ(DBサーバ)の3つです。DBサーバはストレージも含むものとします。フラットファイルやPDFなど、何らかのファイル作成の機能を持つシステムであれば、これにプラスして帳票サーバがあったり、他システムと連携する場合には外部接続用のサーバがあったりするでしょうが、基本的には同じことです。
すると、このシステムの処理の流れは、図2で表すことができます。点線の矢印は、クライアントから処理要求が出されて、それをサーバが処理してクライアントに結果を返す処理シーケンスを表しています。また、①~⑫は、機能ごとの処理の開始/終了時間を示しています。すると、ユーザが「遅い」とか「速い」と体感する時間というのは、「⑫-①」です(厳密にはこの言い方は正しくないのですが、長くなるので詳細はコラム「滞留個所 番外編」で説明します)。これをレスポンスタイムと呼びます。
今最も知りたいことは、レスポンスタイム内における各処理(サーバと1対1に対応すると想定)の占める時間、つまり、各サーバ内における滞留時間の内訳です。それが最も長い個所、すなわちボトルネックが、最初のチューニングターゲットになります。
明らかに遅い処理が最初から判明しているケースであれば、このステップを飛ばすことも可能です。しかし、確固たる証拠がないまま予断を持つことは危険です。「DBサーバが遅いに違いない」と思い込んでいたら、実はAPサーバのJavaアプリケーションが遅かった、なんてことはざらにあります。確実な証拠を掴む前に犯人逮捕を焦れば、誤認逮捕の危険が増すだけです。
データベースの鉄則
いかなる場合も、検査の前に予断を持ってはいけない
滞留時間はどうやって調べる
では、その滞留時間はどうやったらわかるでしょうか。方法としては、大きく2つあります。1つは、システムの稼働中に、滞留時間がわかる情報をアプリケーションのログに出力すること。もう1つは、処理の一部分を切り出して、単独の処理時間を実測する方法です。
滞留時間がわかる情報をアプリケーションのログに出力
ApacheのようなWebサーバや、WebLogicのようなAPサーバは、アクセスログに処理時間、すなわち滞留時間をダイレクトに出力する機能があります。この機能を使うことで、Webサーバならば「⑪-②」、APサーバならば「⑨-④」の時間を知ることができるわけです。本稿では個別のソフトウェアの実装にまでは深く踏み込みませんが、たとえばApacheであれば、httpd.confのLogFormatを指定する個所で%Dのフォーマットを指定することで、マイクロ秒単位の処理時間を出力できます[1]。
一方、DBサーバの場合も話は同じで、各DBMSはSQLの滞留時間を把握するための機能を持っています(表1)。使い方や出力される情報のレベルは実装ごとに異なるため、詳細はお使いのDBMSのマニュアルを参照してください。
処理の一部分を切り出して、単独の処理時間を実測
一方、すでに遅延が疑わしい処理に「当たり」がついていれば、その処理だけ切り出して実行する、というのも手軽な検証手段です。DBであれば、SQLを単独でコマンドラインから実行すればよいわけです。
ただ、この方法が採用できるのは、処理をきれいに切り分けられる場合だけです。実際には、アプリケーション内部でSQLが生成されたり、パラメータが設定されたりして、どんなSQLが実行されているかブラックボックスでわからないことも多いでしょう。また、単体実行したときは速くて、高負荷時にだけ遅くなる、ということもあります。そういうケースでは、結局上述のDBMSのログから確認するしかありません。
上記の方法でボトルネック個所が特定できたならば、次のステップへ進むことになります。