該当する結果がありません

一致する検索結果がありませんでした。

お探しのものを見つけるために、以下の項目を試してみてください。

  • キーワード検索のスペルを確認してください。
  • 入力したキーワードの同義語を使用してください。たとえば、「ソフトウェア」の代わりに「アプリケーション」を試してみてください。
  • 下記に示すよく使用される検索語句のいずれかを試してみてください。
  • 新しい検索を開始してください。
急上昇中の質問

門外不出のOracle現場ワザ

第5章 DBアクセスの空白地帯 コネクションプーリングを極める

日本オラクル株式会社 コンサルティング統括本部テクノロジーコンサルティング本部

小田 圭二(おだ けいじ)

目次

Part1 DB接続のパフォーマンスと管理性を最大化するコネクションプーリングの仕組み

コネクションとは?

コネクションプーリングについて解説する前に、まず「コネクシ

ョンとは何か?」を説明しましょう。

アプリケーションがOracleを用いてSQLを実行するためには、OracleにSQLを渡すための手段が必要です。Oracleではミドルウェアや「SQL*Plus」などのツールを使用してSQLをOracleへ渡します。

また、アプリケーションとOracleとを結ぶSQL実行のための通信路も必要になります。この通信路がコネクションです。

専用サーバー接続

SQL*PlusからOracleへSQLを渡す際のコネクションを生成する動作を見てみましょう。図1は、リスナーが接続要求を受け取るときの様子を簡略化したものです。

図1 コネクションを生成する際の動作

図1 コネクションを生成する際の動作

SQL*Plusは、DBサーバーのリスナーに対して、ユーザー名とパスワードと共に接続要求を行ないます。リスナーはOS上で新たなサーバープロセスを作成し、SQL*Plusからの接続要求をリダイレクトします。SQL*Plusはその後、新たなサーバープロセスとだけ通信を行ないます。

このように、接続要求によりリスナーが専用のサーバープロセスを用意してくれる接続体系を「専用サーバー接続」と呼びます。

サーバープロセス生成のコスト

新たなサーバープロセスを作成するには、さまざまな処理が必要です。まず、OSに新しいプロセス(Windowsではスレッド)を割り当ててもらい、プロセス空間をOracle用に初期化し、SGAにもきちんとアクセスできるように各種の設定を行ないます。その後、Oracleを正しく使用できるようにパラメータを読み込んだり初期化のためのSQLも発行したりします(図2)。

図2 サーバープロセス生成時の処理

図2 サーバープロセス生成時の処理

一般的なOLTP(On-Line TransactionProcessing:オンライントランザクション処理)においては、アプリケーションから発行されるほとんどのSQLは簡潔で、これらの接続処理に比べると非常に短い時間で処理が済むことが多いです。筆者のLinuxマシン(CPU:Pentium4 1GHz)で試したところ、1つのコネクションの生成に約0.05秒ほどかかっていました。Oracleは1秒間で少なくとも数百~数万SQLを処理できることを考えると、コネクション生成は大変重い処理であることが分かると思います。

サーバープロセス保持のコスト

コネクションの生成が重たいからといって、単純に考えて事前にたくさん作っておけば良いというわけではありません。アイドル状態のコネクションは、ただメモリリソースを消費しているだけです(図3)。

図3 メモリが無駄になっている例

図3 メモリが無駄になっている例

数千セッションを保持しているにもかかわらず、ある瞬間に実際に処理を行なっているセッションは数個しかなく、数GBものメモリが無駄になっているという状態は無視できないでしょう。

しかし、このような状態は決して珍しいものではなく、例えばWebアプリケーションにおいても、単純に1ユーザー1コネクションにすると、データベースに対して実際に処理を行なっているユーザー数は、アクティブなユーザー数と比べて極めて少ない割合でしかないのが一般的です。

コネクションのマイナス要素

ここまでをまとめると、コネクションは次の2つのマイナス要素を持っていることになります。

  • 接続要求処理は、CPU使用量や応答時間におけるコストが高い
  • アイドル状態のコネクションは、メモリリソースを無駄に消費する

コネクションプーリングはこれら2つの要素を解決する良い方法ですが、コネクションプーリング全盛の現在でも、接続処理によるパフォーマンストラブルはゼロではありません。「主要なアプリケーションではコネクションプーリングを使用しているから」と安心してしまい、ほかの細かいアプリケーションからの接続によりトラブルが発生するというケースも少なくありません。

DBAはどこからどのように接続が行なわれるのか、設計者/開発者はデータベースに優しい接続方法をとっているかをきちんと考えて、コネクションプールの実装を選択する必要があります(図4)。

図4 コネクションについて注意する

図4 コネクションについて注意する

これらのことを考慮しながら、以降ではまずアプリケーションの接続形態について詳しく見ていきます。

接続するタイミング

いつコネクションを生成すれば良いのか?

では、どのタイミングでコネクションを生成するのがベストなのでしょうか。一般的に見られるコネクション生成のタイミングは、次のように分類できます。

  1. SQLを1つ発行するごと
  2. トランザクションを1つ開始するごと
  3. ログインなど、大きな処理単位ごと
  4. 半永久的に接続したまま
  1. SQLを1つ発行するごと

    SQLを1つ発行するたびにコネクションを生成する場合がありますが、バッチ処理やOLTPではこのような実装をしてはいけません。コネクションが正常に切断された時点で自動的にコミットが発行されますので、複数のDML(Data Manipulation Language:データ操作言語(更新系SQL))で構成されたトランザクションは実行できません。

    「そんな実装はしない!」と言う方がいらっしゃるかもしれませんが、このようなコネクション生成は気軽な気持ちで作成した単純なツール系などで結構見かけます。

    例えば、アプリケーションのログ表やV$ビューなどの情報を取得するため、定期的にSQL*Plusがシェルから起動されるような場合です(図5)。

    図5 SQL*Plusから定期実行される監視ツールの例

    図5 SQL*Plusから定期実行される監視ツールの例

    Javaや.NETで簡単なツールを作成して、コネクションプーリングを使用していない場合もあります。

    「塵も積もれば……」というように、気が付くとCPUの10%以上をサーバープロセスの生成処理で消費しているということになりかねません。サーバープロセス生成時のCPU使用状況は、UNIX系OSであればvmstatのSYSTEM部分 注1に表示されます。定期的に不自然にSYSTEMの数値が高くなる場合がありますが、「テストではこのようなことはなかったし、ネットワークも問題ないし、心当たりがない」という場合に調べてみると何か手がかりが見つかるかもしれません。

    注1:メモリやCPUなどの稼動状況、負荷状況に関する情報を取得するためのコマンド。SYSTEM部分にはシステム全体の割り込み回数やコンテキストの切り替え回数が表示される。

  2. トランザクションを1つ開始するごと

    OLTPで最も直感的な実装として考えられるのが、トランザクションごとにコネクションを生成する実装です。少なくとも1つのトランザクションは1つのコネクションの中で行なう必要がありますので、必要最小限の単位でコネクションを保持することになり、アイドルコネクションによる無駄なリソース消費はありません(図6)。

    図6 アクティブトランザクションとコネクション生存期間

    図6 アクティブトランザクションとコネクション生存期間

    ただし、もちろんCPUの使用量やコネクション生成時の応答時間オーバーヘッドを考えると、リソースの使用効率が悪いために3以降の考え方へ移行せざるを得ないのですが、コネクションプールの登場により、この考え方が逆に重要になることを覚えておいてください。

    ログインなど、大きな処理単位ごと

    この考え方は現在でも主流の1つです。「ログインからログアウトまで」「処理単位開始から終了まで」といった複数のトランザクションを含む大きな処理単位で1つのコネクションを保持します。バッチ処理では、ほぼ例外なくこの形をとりますし、使用ユーザーが少数に特定されている場合や一度ログインすると1日中接続を保持したままのアプリケーションなどはこの形式を好みます。

    バッチ処理の多くがこの形式で問題ないのは、処理単位が大きいために接続回数が少なく、また処理中は絶えず接続にSQLが供給されて無駄がないためです(図7)。

    図7 長時間コネクションを保持させるアプリケーション例

    図7 長時間コネクションを保持させるアプリケーション例

    使用ユーザーが少数で特定される場合は、ログインしたままアイドル状態のセッションを保持しても、無駄になっているリソースは許容範囲内のため大きな問題になることはありません。

  3. 半永久的に接続したまま

    この形式が、まさにコネクションプーリングです。1~3に不適合なアプリケーション形式、つまり、不特定多数のユーザーが短いトランザクションを発行するために必要なアーキテクチャです。Webアプリケーションにはこの形式が求められるわけです。

    1~3までは、実装はすぐに想像できるほど簡単なものでしたが、コネクションプーリングには色々と考えるべきことがたくさんあります。基本的には「プールしてあるコネクションを再利用していく仕組み」なのですが……(図8)。

    図8 コネクションプールの構造

    図8 コネクションプールの構造

    詳細については、以降でじっくりと見ていきましょう。

COLUMN:定期的にSQLを発行するシェルを作成するには?

定期的にSQL*Plusを立ち上げ、そのたびに接続してSQLを発行するのではなく、SQL*Plusを起動したままコネクションも1 回だけ生成して、定期的にSQLだけを送ってあげるようにしましょう。次のようにするとできます。


#!/bin/sh
(
echo 'conn system/' #コネクション生成
echo 'set time on timing on'  #時間情報を付ける
while [ 1 ]                   #永久ループ(for文にすれば有限ループ)
do
echo 'select count(*) from v$session;' #SQLの本体
sleep 5                                #5秒間スリープ
done
) | sqlplus /nolog                     #SQL*Plusにパイプで渡す
	

コネクションプーリングの構成要素

アプリケーションから見たコネクションの「抽象化」

コネクションプーリングを使用する際は、アプリケーションから見たコネクションを「抽象化」する場合が多いことに注意してください。つまり、アプリケーションから見たコネクションの生成/切断は、単にコネクションプールからのコネクションの獲得/返却になります。アプリケーション側では、直接コネクションの生成や切断は行ないません。実際の生成や切断は、コネクションプールを管理している別のモジュール(アプリケーション管理モジュール)が行ないます(図9)。

図9 コネクションプーリングによるコネクションの抽象化

図9 コネクションプーリングによるコネクションの抽象化

コネクションプールからの獲得と返却を別個のメソッド、関数として定義することもありますが、それだと既存のアプリケーションとの移植性が著しく低下するため、コネクションプールに対する(もしくはそれも意識させずに)通常の接続の生成や切断として記述します。

一般的に「アプリケーションからコネクションプールへのコネクション」を「論理接続」、「コネクションプールからデータベースへのコネクション」を「物理接続」と呼びますので、本稿でもそのように呼びます。

コネクションプール管理モジュールは、自分で作成することもできますし、ベンダやドライバ、フレームワークで用意されているものも利用できます。ほとんどの場合はこの中から1つを選ぶことになります。

物理接続数のコントロール

物理接続数を適切にコントロールすることは、コネクションプール管理モジュールの重要な使命です。理想的には、論理接続がどのようなパターンで要求されてもコネクションの生成と切断が最小限で済み、無駄なリソースはいつも限定的であり、論理接続の要求を必要以上に待たせない実装であることが求められます。しかし、現在のところ理論的に究極の実装は存在せず、ベンダによってさまざまな実装が見られ、パラメータの設定項目もたくさんあります。DBAや開発者は、それらの特徴をしっかり掴んだ上で、適切なものを選択するための選択眼が求められると言って良いでしょう。

物理接続数は、主に最小物理接続数、最大物理接続数の間で推移する、もしくは単調増加する動きが基本となります(図10)。

図10 物理接続数のコントロール

図10 物理接続数のコントロール

さらに、アイドル状態となっている物理接続を再利用のために奪取/切断する動作が加わって、本格的なコネクションプーリングと言えます。

最小物理接続数までの接続

最低限保持しておく物理接続数を、本稿では「最小物理接続数」と呼びます。コネクションプーリングが動作を開始したとき、論理接続の要求があるなしにかかわらず、最小物理接続数まで物理接続を生成します。

例えば、早朝はほとんどアクセスがないが、社員が出社する午前9:00に突然論理接続が100程度必要となるシステムの場合には、最小物理接続数を100程度に設定しておけば、負荷の軽い時点で必要なだけコストの高い物理接続を生成しておくことができます。物理接続の生成には、次の2つのパターンがあります(図11)。

図11 一気型と余裕型

図11 一気型と段階型

  • 一気型:最小物理接続数まで可能な限り高速で物理接続を生成する
  • 段階型:最小物理接続数まで段階的に物理接続を生成する
  • 一気型

    ほとんどのコネクションプーリングは一気型で動作します。もし、アプリケーションサーバー(以降、APサーバー)のCPU数を考えてマルチスレッドで動作するコネクションプーリングがあれば、最も早く物理接続の生成が完了することでしょう。

    ただし、一時的とはいえ、サーバープロセス生成に関する高い負荷をDBサーバーに与えます。

  • 段階型

    コネクションプーリングを使用するアプリケーションが複数あるシステムなどでは、一気型では問題が生じる場合があります。24時間365日運用しているDBサーバー、もしくは一部のAPサーバーが障害を起こした後の復旧時など、ほかのアプリケーションが稼動中にコネクションプーリングを用いるアプリケーションを起動しなければならない場合があります。このとき、一気型で最小物理接続数まで一気に物理接続を生成すると、一時的とはいえ、ほかのオンラインアプリケーションのレスポンスタイムに影響が出るほどの負荷上昇が発生する可能性があります(図12)。

    図12 一気型がほかのアプリケーションに影響を与える例

    図12 一気型がほかのアプリケーションに影響を与える例

    レスポンスへの影響を抑えるには、最小物理接続数を0に近くするという方法もありますが、段階的に物理接続を生成することで解決できます。一度に生成する物理接続数とスリープ時間まで設定できると、さらに細かな制御を行なえます。

最小物理接続数→最大物理接続数

コネクションプーリングは、データベースの資源を枯渇させないために「最大物理接続数」というパラメータを持ちます。最小物理接続数を超えて最大物理接続数に達するまでは、基本的に論理接続の要求に応じて物理接続数を増加させていきます。
ただし、増加のさせ方には次の2通りが存在します。

  • その場型:要求されたときに物理接続を生成する
  • 先回り型:常に、論理接続数よりも多い物理接続をあらかじめ用意する
  • その場型

    論理接続要求が来たときに、物理接続の空きがなければその時点で物理接続を生成して要求に応えます(図13)。

    図13 その場型

    図13 その場型

    コネクションプール管理モジュールの実装としては簡単に済みますが、論理接続数が物理接続数を超えた場合には、論理接続の獲得が遅くなるため、安定したパフォーマンスを望む方にはお勧めできません。

    物理接続を増加させる単位は、10個など複数の値を設定できる場合があります。その場合、ほぼ先回り型と似た効果を得ることができますが、増加単位をむやみに大きく設定していると、物理接続の切断機能によって多くの物理接続が切断される事象が頻発する場合がありますので注意が必要です(後述)。

  • 先回り型

    いつも物理接続数を論理接続数よりも多い状態に保とうとする動作をします。最近では、IAサーバーも含めてほとんどのAPサーバーやDBサーバーでCPUを複数搭載していますので、実処理のバックグラウンドで物理接続数を増加させておいてもほかの処理には影響を与えにくくなっています。先回りしておくことで、論理接続をいつも一定の時間で獲得ができるため安定した動作をしますので、選択可能な場合はこちらの実装をお勧めします(図14)。

    図14 先回り型

    図14 先回り型

    コネクションプール管理モジュールの動作は少々複雑です。まず、必要なパラメータとして論理接続数と物理接続数の差をどの程度にするかを、数や比率で表現しなければなりません。調整を行なうタイミングも、論理接続の獲得時に行なう場合と一定時間間隔で行なう場合とがあります。

最大物理接続数を超える要求

論理接続の要求時に、すでにすべての物理接続が払い出されていて、その数が最大物理接続数に達している場合、主に次の3つの動きが存在します。

  • 積極型:とりあえずコネクションを生成し、返却後は切断する
  • 我慢型:ほかの論理接続が返却されるまで待ち行列に入れる
  • 厳格型:エラーを返す

すべてにメリット/デメリットがあります。また、高負荷の場合にアプリケーション/コネクションプール管理モジュール/DBサーバーのどの部分に滞留(もしくはエラー発生)するかが異なります(表)。

表 各形式と滞留(エラー処理)する箇所

表 各形式と滞留(エラー処理)する箇所

システムの性格や運用体制などで選択すると良いでしょう。

  • 積極型

    最大物理接続数に達していても、とりあえず物理接続を生成して論理接続を獲得させます(図15)。

    図15 積極型

    図15 積極型

    メリットは、持てるリソースのすべてを利用しようとするため、最も早く処理を返せるかもしれない点です。一時的にデータベースに対して多くのリソースを要求しますが、「一時的であれば耐えてくれるだろう」という考え方だと言えるでしょう。

    また、「コネクションプーリングを使用するアプリケーションが多数存在し、予備のリソースを共有化する」といった考え方の場合も後回し型を使用することになるでしょう。

    多くの場合、最終的な物理接続の上限値も決定できます。その上限値に達した場合の挙動は、我慢型、厳格型のどちらかの動きとなります。

    使用後のコネクションが返却されると、別途設定された短いタイムアウトを待って、再利用がなければ物理接続を切断します(タイムアウトが0の場合もあります)。後回し型の実装は、DBサーバー側の過度な競合によって、逆に処理遅延が発生する場合があります。

    また、最大物理接続数を超える要求が頻繁にあり、物理接続の生成/切断が頻繁に発生してしまった場合には、コネクションプーリングのメリットを十分に生かせず、結局CPUの負荷や応答時間に影響を与えてしまうことがあります。後回し型を採る場合には、過負荷の場合を想定して十分に検討する必要があるでしょう。

  • 我慢型

    最大物理接続数に達していた場合、論理接続要求はコネクションプール管理モジュールの待ち行列に入れて待機させます(図16)。

    図16 我慢型

    図16 我慢型

    p> メリットは、DBサーバーのリソースを計画的に無理なく使用できる点です。適切な最大物理接続数に設定してあれば、DBサーバーは過度な負荷を受けることなく健全に動き続けることが期待されます。

    過度な論理接続要求があった場合には、窓口が1つの待ち行列理論に従って待機時間が長くなっていき、獲得までに長時間を要することになります。待ち行列が慢性的に長い状態になると、論理接続要求がシステムのボトルネックとなって、DBサーバーの負荷は軽いのに、アプリケーションから見るとコネクション生成の処理が遅いという状態になります。そうなると、コネクションプールに関する統計値から待ち行列の長さなどをきちんと観察していかなければ、なかなか原因がつかめないことがあります。

    我慢型の実装を使用する場合には、コネクションプールに関する統計値を観察できる実装を使用し、かつテストを行なってDBサーバーが過負荷にならない範囲でできる限り高い最大物理接続数を導いておくべきでしょう。

  • 厳格型

    最大物理接続数を超えた論理接続要求に対してエラーを返します(図17)。

    図17 厳格型

    図17 厳格型

    何度か決められた回数をリトライして獲得できなければエラーを返す場合もあります。メリットは、論理接続が増え過ぎた時点でアプリケーション側でのエラー処理が可能なことです。すでに接続されているアクティブユーザーを過負荷から守るため、最大物理接続数を超えた時点で接続を要求してきたユーザーについてはサービスの提供を行なわず、エラー画面を表示するなどの対応が可能となります。ちょうど、過負荷の場合に505エラーを返すWebサーバーと似ています。

    しかし、アクティブなユーザーが実在するユーザーのごく一部であるWebアプリケーションなどでは、論理接続が一時的に想定した最大物理接続数を超えることは確率的に十分あり得ることです。そのため、一時的な論理接続要求の集中ですぐにエラー画面を返されてしまうことはアプリケーションとしては不都合です。そのため、何度かリトライした後にエラーを返すコネクションプーリングを選ぶか、アプリケーション側でリトライさせることが不可欠となります。

    ただし、多くのシステムでは、コネクションプーリングではなくさらに上流の箇所で負荷を絞ることが多いでしょう。あまり好んで採用される方式ではありません。

アイドル接続の奪取と切断

コネクションプーリングには、長時間アイドル状態の論理接続を奪取したり、長時間使用されていない物理接続を切断するための機構が必要です。これらの処理は、アプリケーションの処理とは無関係に処理しなければならないので、アプリケーションのスレッド(プロセスの場合もありますが、ここではスレッドで統一)とは別のスレッドで検知する必要があります。この検知を行ない、必要な手当てを行なうスレッドを本稿では「メンテナンススレッド」と呼ぶことにします(図18)。

図18 メンテナンススレッド

図18 メンテナンススレッド

メンテナンススレッドは、指定した、もしくは決められた一定時間ごと(5秒や1分など)に起動されます。

アイドル論理接続の奪取と切断

コネクションプーリングにとって、アプリケーションにより放置されたアイドル状態の論理接続を強制的に奪取/切断する機能は必須です。

例えば、一般的なWebアプリケーションでは、トランザクションの途中に最後まで画面遷移せずにブラウザを閉じてしまった場合、強制奪取機能がなければアプリケーションが半永久的に接続を持ち続けることになってしまいます(図19下)。

図19 論理接続の返却が行なわれない例

図19 論理接続の返却が行なわれない例

メンテナンススレッドは、獲得してから一定時間経過した論理接続を強制的に奪取し、ロールバックおよび切断処理を施します。本来であれば、最後にSQLを発行してから一定時間経過した論理接続を奪取する実装が理想なのですが、メンテナンススレッドからは、通常最後にいつSQLを発行したかは分からないため、獲得してからの期間で設定することがほとんどです。

また、切断ではなく、返却のみを行なうこともアプリケーションからの物理接続への参照までは書き換えることができないため、実装は困難です。

アプリケーションが奪取された論理接続を使用してSQLを発行した場合には、参照先の物理接続がすでに存在しないため、ORA-3113など、接続が存在しない旨のORAエラーが返されます。奪取を行なうまでの期間については、ユーザーに影響を与えない十分に長い期間を設定し、ユーザーにも画面上などで通知しておく必要があるでしょう。

そもそも、半永久的に返却が行なわれないようなロジックを存在させないようにすることが重要です。Webアプリケーションの場合、1画面遷移の間で論理接続の獲得と返却が必ず実行されるようにすることで、遷移ロジック中の例外的なエラー時以外では論理接続が必ず返却されるようになります。図19上では、ワークテーブルを一時表に保存したかったので同一セッションを保持しているというストーリーなのですが、一時表のメリット(REDOを生成しない、DELETEの必要がない)を捨ててワークテーブルを永続表にすることで、1画面遷移の中での返却が可能になっています。

アイドル物理接続の切断

最小物理接続数を超えて物理接続が生成されているときにオフピーク時間が訪れ、論理接続数が最小物理接続数をも下回っている状態が長く続く場合、アイドル状態の物理接続はリソースの無駄遣いと言えます。そのアプリケーションがオフピークでも、バッチ処理やほかのアプリケーションはピークかもしれませんので、無駄なリソースはできるだけ速やかに解放する必要があります。

メンテナンススレッドは、一定期間使用されていない物理接続を切断します(図20)。

図20 アイドル物理接続の切断

図20 アイドル物理接続の切断

しかし、あまり短い時間に設定していると、頻繁に物理接続の増減が発生してしまうことがありますので、1時間などある程度長い時間が良いでしょう。

障害時の挙動

ほとんどのコネクションプーリングは、DBサーバーの障害を検知するためのSQL文を設定できます。障害を検知するSQL文が発行されるタイミングは次の3つのうちのどれか、または全部です。

  • 論理接続獲得時
  • 論理接続返却時
  • アイドル時に一定間隔

障害を検知するSQL文の発行が失敗すると、まずリトライします。決められた回数のリトライもすべて失敗すると、コネクションプール管理モジュールはデータベース接続に関するエラーが起きたと判断します。この判断には次の2種類が存在します。

  • 悲観型:コネクションプール中の全コネクションが問題と判断
  • 楽観型:エラーが起きた物理接続だけが問題と判断
  • 悲観型

    全コネクションを強制的に奪取してロールバック/切断を行ないます(図21)。


    図21 悲観型

    図21 悲観型

    インスタンスの自動/半自動的な再起動で問題が解決していたり、Real Application ClustersやHigh Availability構成を取っている場合には、すぐに再接続しても成功が期待できるので、設定したスリープ時間の後、メンテナンススレッドによって最小物理接続数までの再接続を試みます。

    DBサーバー障害の際は、先回りして物理接続を構成できるため迅速に対処できると言えますが、誤検知もあり得ることを理解しておく必要があります。

  • 楽観型

    メンテナンススレッドは、アイドル状態の物理接続で障害を検知した場合にのみ物理接続を再構成し、論理接続獲得時や論理接続返却時に障害を検知した場合にも当該の物理接続でのみ再生成を試みます(図22)。

    図22 楽観型

    図22 楽観型

    ほかの論理接続には何も行ないません。ORA-3113などのエラーは、プロセス障害である可能性もありますので、楽観型のほうが不用意なサービスエラーを防ぐことができると言えます。

アプリケーション側の対処

論理接続獲得時にエラーを返された場合、ユーザーにエラーを返す前に再獲得を試みるべきです(図23)。

図23 論理接続の再獲得

図23 論理接続の再獲得

メンテナンススレッドが再獲得時の処理によって再確立された物理接続を用いて獲得が成功する可能性が高いからです。

論理接続返却時には、アプリケーション側にエラーが返されても、別途必要なコミットに成功しているのであれば、特に対処は必要ないでしょう。返却時の自動的なコミットを期待している実装の場合には、ロールバックされてしまっている可能性が高いので、確認処理が必要となります。確認処理の実装は困難が予想されるので、返却時とは別にコミットを行なうべきでしょう。

COLUMN:障害を検知するSQL文として最も適切なのは?


実行計画
----------------------------------------------------------
0    SELECT STATEMENT Optimizer=ALL_ROWS (Cost=2 Card=1)
1  0   FAST DUAL (Cost=2 Card=1)……FAST DUALとなっている(10g以降)

統計
----------------------------------------------------------
(省略)
0  consistent gets…… ブロック参照がまったく行なわれていない
(省略)
SQL>select * from dual;……DUAL表の値を読む検索

実行計画
----------------------------------------------------------
0    SELECT STATEMENT Optimizer=ALL_ROWS (Cost=2 Card=1 Bytes=2)
1  0 TABLE ACCESS (FULL) OF 'DUAL' (TABLE) (Cost=2 Card=1 Bytes=2)

  …… 通常のDUAL表への検索となっている

統計
----------------------------------------------------------
(省略)
3  consistent gets…… ブロック参照が行なわれる
(省略)	
	

コネクションプーリングに付随する技術

ここでは、コネクションプーリングそのものではないですが、深く関連する周辺技術について説明します。

文キャッシュ

データベースでは、問い合わせやDMLを発行するときにカーソルを作成してオープンする必要があります。カーソルはコネクションと紐付けられており、一度オープンしておけば、同じSQL文はパラメータを変えるだけでいつでも何度でも実行できます。
カーソル内でWHERE句の条件などをバインド変数によりパラメータ化することを「カーソルの共有化」と言い、共有化されたカーソルのことを「共有カーソル」「バインド変数化されたカーソル」などと言います(LIST)。

LIST 共有カーソルの例

LIST 共有カーソルの例

この共有カーソルの特性とコネクションプーリングの仕組みを利用して、異なる論理接続間でのカーソルの共有化が可能です。この機能のことを「文キャッシュ」と言います。文キャッシュを使用すると、アプリケーション側でクローズしたカーソルをクローズせずにオープンしたまま残し、別の機会にそのまま再利用できるようになります(図24)。

図24 コネクションプーリングと文キャッシュ

図24 コネクションプーリングと文キャッシュ

文キャッシュは、パフォーマンス上非常に有効です。通常、文キャッシュはコネクションプール管理モジュールで自動的に実施され、アプリケーションのコーディングで文キャッシュを意識することはありません。

COLUMN:空コミットはしないほうが良いですよね?

Oracleは、いわゆる空コミットやSELECTFOR UPDATE以外の問い合わせのみ実行していた場合には、読み取り専用トランザクションの扱いとなり、REDOログファイルに対して書き込みを待機する実際のコミット処理は行ないません。そのため、空コミットが増えることはデータベース全体に対する懸念材料にはなりません。user commits統計値にも反映されません。

アイドル中の物理接続は、単にバックグラウンドで再接続が試行されるだけですので、アプリケーション側に影響はありません。また、アプリケーションが使用中の論理接続に関しては、メンテナンススレッドにより知らない間に接続が無効になっている場合があるため、アプリケーションでのエラーハンドリングが必要です。検知するのはSQL文の実行時で、ORA-3113やORA-3114エラーを受け取ることになります。SQL文の実行時エラーには、制約違反やNot Foundなど、コネクションに関係ないものも多いので、ほかの想定ケースも洗い出し、きちんとエラーハンドリングを行ないましょう。

共有サーバー構成

Oracleの共有サーバー構成は、DBサーバー側で実施するコネクションプーリングの一形態ととらえることができます。共有サーバー構成は、ディスパッチャが共有サーバーとの通信を中継し、SQL単位で共有サーバーへ処理を振り分けます(図25)。

図25 共有サーバー構成

図25 共有サーバー構成

コネクションプール管理モジュールに当たるのがディスパッチャです。

ディスパッチャは、接続形態が専用サーバー構成とは異なり複雑になります。同一のセッションでも異なる共有サーバーをまたがって処理が実施されるため、SQLトレースなどを取得して分析を行なうなどの作業も困難となります。そのため、現在ではアプリケーション側のコネクションプーリングがあるため、ほとんど使用されません。まれに、大量のアイドル接続が存在するときや、物理接続の生成/切断が頻繁に行なわれるコネクションプーリングを使用せざるを得ないときなどに併用する場合があります。

また、コネクションプーリングが使用できないアプリケーションで大規模なWebアプリケーションを構築する場合などでは、アプリケーションを潤滑に動かす手段として使用するのも1つの手でしょう。

OCIコネクションプーリング

OracleのOCIコネクションプーリングは、JDBC OCIドライバ上のコネクションキャッシュや、Pro*Cのデフォルトでのコネクションプーリングとして用意されています。意識せずに使用したことがある方も多いかもしれません。その実装は、共有サーバー構成のディスパッチャ部分をOCIクライアント側のコネクションプール管理モジュールが担い、論理接続の単位に関係なくSQL単位でOracleの専用サーバーへ振り分けています。つまり、専用サーバーをあたかも共有サーバー構成のように利用するため、振る舞いは共有サーバーと似たものになります(図26)。

図26 OCIコネクションプーリング

図26 OCIコネクションプーリング

DBサーバーから見た複雑さは共有サーバー構成と同等になりますので、できればアプリケーション側のコネクションプーリングの使用(Javaの場合はJDBC Thinドライバ上のコネクションキャッシュ)をお勧めします。

Pro*Cなどでは、アプリケーション側でのコネクションプーリングがない場合が多く、ほとんどの場合自作する必要があります。できれば自作、もしくは既存製品の利用をお勧めしますが、自作する余裕はないがコネクションプーリングは必要といった場合に使用すると良いでしょう。

Part2 Java &.NETで使えるコネクションプーリング究極の選択 >>

"門外不出のOracle現場ワザ" インデックスに戻る

Copyright © 2009, Oracle Corporation Japan. All rights reserved.

無断転載を禁ず

この文書はあくまでも参考資料であり、掲載されている情報は予告なしに変更されることがあります。日本オラクル社は本書の内容に関していかなる保証もいたしません。また、本書の内容に関連したいかなる損害についても責任を負いかねます。

Oracleは米国Oracle Corporationの登録商標です。文中に参照されている各製品名及びサービス名は米国Oracle Corporationの商標または登録商標です。その他の製品名及びサービス名はそれぞれの所有者の商標または登録商標の可能性があります。

小田 圭二

小田 圭二(おだ けいじ)

1996年日本オラクル入社。人事教育本部にて、新卒や中途採用社員に対し、データベースやOS、ネットワークの講師を5年ほど経験した後、2000年にテクノロジーコンサルティング本部に異動。 テクノロジーのコンサルタントとして、主に大規模ミッションクリティカルシステムを担当。

ポリシーは、「OracleもOS上で動くアプリケーションにすぎない。だから、OS、ストレージ、ネットワークを学ぶべき」。 スキル面の興味は、アーキテクチャ、DBA、インフラ技術、教育、コンサル手法など。