門外不出のOracle現場ワザ

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

日本オラクル株式会社 コンサルティング統括本部テクノロジーコンサルティング本部
小田 圭二(おだ けいじ)

目次

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

Javaにおけるコネクションプーリング

DriverManagerクラスとデータソース

Javaでは、JDBCによってデータベースへアクセスします。DB接続を表わすオブジェクトを「コネクション」と言い、Connectionインターフェイスで表現されます。コネクションは、データソース(DataSourceインターフェイス)か、DriverManagerクラスのどちらかで獲得します。
データソースはJDBC 2.0から導入されたオブジェクトで、JNDI(Java Naming and Directory Interface)に登録されて使われることを想定しており、コネクションプーリングも考慮した作りになっています。一方のDriverManagerクラスは、JDBC 1.0からある最も古く単純な実装で、単にコネクションを払い出すだけの機能しか持ちませんが、JNDI内でデータソースの定義を記述する際に物理接続の生成元として記述する場合があり、まったく使用しないわけではありません。
データソースを用いたコネクションの取得には、いろいろな方法があります。実は、JDBC 2.0で用意されたクラス群だけでは、コネクションプーリングの枠組みとして解釈がいくつも存在し、ベンダごとに独自の仕組みを持つ実装が提供されました。そのために混乱した時期もありましたが、現在では、データソースが暗黙的にコネクションプーリングの機能を持つという実装でほぼ統一されたようです。
図1は、現在の代表的な取得方法を示しています。

図1 Connectionの取得
図1 Connectionの取得

アプリケーション層ではJNDIにおけるデータソースのリソース位置を指定し、JNDIではファクトリ層とデータソース層でデータソースの実体クラスと実体化方法を定義します。データソース層までで物理接続の実体が定義されていない場合には、ドライバ層でDriverManagerクラス、もしくはデータソースの実体クラスを指定します。

データソースを用いた例

LIST1は、JNDIを使ってjava:/comp/env/MyDsという位置からデータソースを検索し、そのデータソースからコネクションを獲得するコードです。

LIST1 JNDI経由のConnectionクラス獲得
LIST1 JNDI経由のConnectionクラス獲得

この部分だけでは、コネクションプーリングが使用できるかどうかも含めて、データソースの実体クラスが何であるかは分かりません。獲得したコネクションが論理接続なのか、物理接続なのかも分かりません。
データソースの検索にJNDIを使う方法では、データソースの実際のクラスやパラメータなどはJNDIの定義部分に追いやられており、アプリケーション側のコーディングで論理接続のライフサイクルやORA-3113などのOracleエラーハンドリング以外の部分でコネクションプーリングを意識することはありません。ただし、どのようなコネクションプーリングが使用できるかについては、少なくとも開発リーダーやDBAが把握しておき、コーディング方法を指示する必要があるでしょう。

JNDI定義部分

データソースを議論する上で分かりづらいのが、JNDIの仕組みと位置付けです。JNDIを使うプログラミングを知らないとデータソースの入れ替えなどはできないと思いがちですが、すでに用意されたJNDI定義があれば比較的簡単にできます。ただし、その方法はアプリケーションサーバー(以下、APサーバー)やフレームワークごとに異なります。本パートでは、できるだけ簡単に入れ替える方法を紹介します。具体的な方法は後述しますが、共通の考え方を押さえておきましょう。
まず、利用しているAPサーバーやフレームワークのJNDI定義部分、もしくはデータソース定義部分を探します。商用のAPサーバーなどでは、データソース定義部分においてはDriverManagerクラスの定義しかできず、データソースの実体クラスを入れ替えられない場合も多いのですが(図2)、そのような場合でもJ2EEアプリケーションであればJNDI定義は設定できるはずですので、新しいデータソースの定義はこちらの方法を使います(一部設定が困難な実装も存在します)。

図2 設定ツールの制限例
図2 設定ツールの制限例

表1に各実装での設定箇所を示したので参考にしてください。

表1 主な実装のデータソース定義とJNDI定義
表1 主な実装のデータソース定義とJNDI定義

ただし、データソースのすべてがJNDIの標準のプロパティ設定方法をサポートしていない点には注意が必要です。例えば、Oracle用のデータソースであるOracleDataSourceのコネクションキャッシュは、設定を変更する際に別途プロパティを操作する必要がありますし、商用APサーバーの多くは、JNDI上でのプロパティ設定方法を公開していません(専用のツールなどで設定します)。
また、標準のjavax.sql.DataSourceインターフェイスには必要最低限のプロパティしかないため、データソースの実体クラスごとにプロパティの仕様が大きく異なる点にも注意が必要です。

監視部分

パート1でも述べましたが、コネクションプーリングを使用する上で、監視をきちんと行なうことは原因不明のトラブルを招かないためにも非常に重要です。商用のAPサーバーにはコネクションプールの状態を監視するツールが付属しているはずですので、監視のためのコーディングは基本的に不要ですが、ツールに表2の項目を監視する機能が含まれていることをチェックしてください。

表2 コネクションプーリングに関する監視/集計項目
表2 コネクションプーリングに関する監視/集計項目

含まれていなければ、自作するか、ほかの監視ツールを入手することをお勧めします。監視部分を自作する場合には、表2の項目を監視できるように作成してください。時系列のログを出力できるツールが少ないように思われます。

コネクションプーリングの選択基準

デフォルトのコネクションプーリング

Javaによる開発では、具体的にどのような点に着目してコネクションプーリングを選択すべきなのでしょうか。そもそも、コネクションプーリングには選択の余地があるのでしょうか。
図3のように、Javaのアプリケーションはさまざまな層で構成されます。

図3 Javaアプリケーションの階層構造とコネクションプーリング
図3 Javaアプリケーションの階層構造とコネクションプーリング

アプリケーションを実装する際には、通常、最も上位の層が提供(もしくは推奨)する機能を使いますので、コネクションプーリング機能についても、最上位の層が提供するものを使用することになります。
しかし、下位の層が持つコネクションプーリング機能のほうが、アプリケーションにとって適切な場合もあります。図3のアプリケーションAでは、JDBCドライバやAPサーバーの提供するコネクションプーリング機能も選択できます。
パート1では、コネクションプーリングにはさまざまな要素があることを紹介しました。アプリケーションの要件によっては、使用するコネクションプーリング機能をより下位のものに変更するか、外部のコネクションプーリング機能を選択するほうが良い場合があります。コネクションプーリングには選択の余地があるのです。

接続時の応答時間

パート1で述べたように、接続時の応答時間は接続時の挙動が「先回り型」である場合に最小化されます。「その場型」の挙動の場合、どうしても初期の接続、もしくは接続がメンテナンスされた後の接続で応答に時間がかかる場合があります。応答時間のぶれが極力少ないことを求められるアプリケーションでは、先回り型の挙動をするコネクションプーリングを選択すると良いでしょう。

アイドル状態のコネクション

APサーバーを1台しか使わない小規模システムでは、アイドル状態のコネクションが多少存在しても大きな問題とはなりません。しかし、APサーバーを数十台も使うような大規模なシステムでは、アイドル状態のコネクションが持つリソースは軽視できません。また、24時間稼動のシステムでは、アイドル状態のコネクションをメンテナンスしなければ、偶然大きく増加したコネクションが永久にそのままということもあります。
筆者としては、次に挙げる条件に当てはまるシステムでは、アイドル状態の物理接続および論理接続をメンテナンスする機能を持つコネクションプーリングの使用をお勧めします。

  • 1つのデータベースに対して、コネクションプーリングが一度に2セット以上接続するシステム
  • 24時間稼動、またはそれに近い長時間稼動を行なうシステム

文キャッシュ

文キャッシュはほとんどのコネクションプーリングが実装していますが、実装していないものもあります。アプリケーションの種類を問わず、デメリットがほとんどなく、パフォーマンスの向上が見込める文キャッシュを使用できるコネクションプーリングを使用すべきです。

監視

コネクションプーリングの動作を監視できる機能は、システムが巨大化/複雑化するにつれ、必須になってきます。何か問題が発生した場合の原因切り分けの速さが違います。多くの商用APサーバーにはWebブラウザ上から監視できる機能がありますし、そうでなくとも、コネクションプーリング関連クラスのメソッドから各種情報を取得できることがほとんどです。コネクションの数が予想しにくいWebアプリケーションの場合は特に、監視する手段を持つコネクションプーリングが有効です。
また、アラート機能を備えるコネクションプーリングもあり、こちらは運用監視システムとの連携など、きめ細かいリアルタイムの監視を行なう場合にお勧めします。

机上の検証

コネクションプーリングの選択に実機検証などの時間をかけられない場合でも、デフォルトで使用するコネクションプーリング機能に問題ないかどうかを、机上で結構ですので、次節で紹介する表と照らし合わせて検証してみてください。問題のある場合には、JDBCドライバのコネクションプーリングに切り替えて使用するなどの対応策があることを覚えておきましょう。

コネクションプーリングの実装の紹介

ここでは、JavaアプリケーションからOracleデータベースに接続するためのコネクションプーリングの実装を紹介します。前節までの動作詳細とともに、適切なコネクションプーリング機能を持つコンポーネントを選択する参考にしてください。

  • Oracle Connection Cache
    Oracle JDBC Driverに備わっているコネクションプーリング機能で、「暗黙コネクションキャッシュ」と呼ばれます。OracleDataSourceクラスで表現されるデータソースに実装されており、connectionCachingEnabledプロパティをtrueにすることで起動します。なお、OC4J9iで提供していたJDBCドライバは使用方法や機能が異なりますので、最新版であるOC4J10gのJDBCドライバを使用してください。
    パート1で説明した機能との対比は、ほかのコネクションプーリングも含めて表3にまとめてありますので、そちらをご覧ください。
    表3 Oracle Connection CacheおよびDBCPが備えるコネクションプーリング機能
    表3 Oracle Connection CacheおよびDBCPが備えるコネクションプーリング機能
    暗黙コネクションキャッシュでは、高速接続フェイルオーバーの機能を使用できます。これはOC4J 10gから追加された機能で、Real Application Clusters環境において、データベースに障害が発生したかどうかをほぼ100%の正確さで判断できます(図4)。
    図4 高速接続フェイルオーバー
    図4 高速接続フェイルオーバー
    この機能はONS(Oracle Notification Service)によって実現されており、今まではSQL文を発行し、その結果から類推するしかなかったデータベースサーバー(以下、DBサーバー)の障害を、DBサーバーから直接メッセージとして受け取ることができます。イベントドリブンなので、誤検知を排除し、検知も最も高速に行なえます。また、障害から復旧したことも通知として受け取り、コネクションプールを復旧ノードへ再分散できます。
    Oracle Connection Cacheは、ほかにも大規模なシステムに対応するための機能を備えており(コラム「Oracle Connection Cacheの柔軟なコネクション管理機能」を参照)、障害時に際しても、Oracleデータベースを使用したシステムでは現時点で最高の機能を備えます。ただし、監視に関してはそのままでは簡単には閲覧などを行なえないため、機能を自作する必要があります。監視に必要な情報に関しては、すべてメソッドを通じて取り出せます。
    COLUMN:Oracle Connection Cacheの柔軟なコネクション管理機能

    Oracle Connection Cacheには、異なるユーザーの接続を1つのキャッシュでまとめて管理する機能も備わっています。適切なユーザーの接続をキャッシュから選択する作業は、暗黙コネクションキャッシュが行なってくれます。
    ほかにも、最大物理接続数を超えた時点でのロギングなど、論理接続の獲得/返却時に実行したい動作を埋め込むために、OracleConnectionCacheCallbackというコールバックインターフェイスも用意されています。ユーザーはこのインターフェイスを継承するクラスを作成してデータソース経由で登録することにより、獲得/返却時にトリガーのように処理をフック(差し込み)できます。

  • DBCP
    Jakartaプロジェクトによって作成されたJava Commons APIの1つです。最近では、TomcatやStrutsなどのコネクションプーリング機能として使用されています。
    DBCPには、BasicDataSourceクラスという基本的な実装のデータソースが用意されており、こちらをそのまま利用することでも十分なコネクションプーリング機能が使用できます。機能の概要は表3をご覧ください。
    しかし、BasicDataSourceクラスだけではDBCPをほとんど使いこなしていません。DBCPは奥が深いAPIで、その基礎となっているのはオブジェクトキャッシュのためのAPI「Java Commons Pool」です。DBCPは全面的にこのJava Commons Poolを使用する形で提供されています。
    DBCPを利用してカスタムのコネクションプーリング機能を実装するのは簡単ではありませんが、最も難しいキャッシュ管理部分やXA部分、文キャッシュなど、かなり細かな機能ごとにコネクションプーリング管理メソッドおよびプロパティが用意されているため、非常に高機能な実装の割にはシンプルな構成が可能です。DBCPの全体像概要は図5をご覧ください。
    図5 DBCPカスタムの全体像概要
    図5 DBCPカスタムの全体像概要
    DBCPをカスタムで書くと、BasicDataSourceクラスでは実現不可能なことも実現できます。ほかの実装では満足できない厳しい仕様が求められる際には、カスタムでの利用をお勧めします。
  • 商用APサーバー
    商用APサーバーのコネクションプーリング機能も、細かな設定が可能となっています。複数の実装から選択できることはありませんが、商用利用に十分耐え得るエンジンとなっているはずです。OC4J(Oracle Application Server Containers for J2EE)、WebLogic、WebSphere、Borland Enterprise Server、Sun ONEのコネクションプーリングについては、誌面の関係もあり、表4、表5に機能の比較一覧を示すに留めます。
    表4 主要なAPサーバーのコネクションプーリング機能(1)
    表4 主要なAPサーバーのコネクションプーリング機能(1)
    表5 主要な商用APサーバーのコネクションプーリング機能(2)
    表5 主要な商用APサーバーのコネクションプーリング機能(2)
    詳しくは、各APサーバーのマニュアルなどをご覧ください。文キャッシュが使用できなかったり、監視機能が不十分なものもありますし、ここに挙げたものは先回り型の接続を行なえません。「商用=高機能」ではないことに注意してください。

コネクションプーリングの切り替え

ここからは、APサーバーやフレームワークにデフォルトで使われているデータソースをほかの実装に変えて、コネクションプーリング機能を切り替える具体的な方法を説明します。対象データベースをOracleとして、いずれもOracleDataSourceへの切り替えを行なっていますが、手順はほかのデータソースへの切り替えも基本的な部分では同様です。

Tomcatの場合

Tomcat 5.0では、$CATALINA_HOME/conf/<ホスト名 >/<コンテキスト名>.xmlというXMLファイルでデータソースを定義しています。このファイルを直接書き換えても良いですし、Webブラウザを使った管理ツール経由でも設定できます。ここでは、DBCPで動作していたデータソースをOracleDataSourceの暗黙コネクションキャッシュに切り替えます。

  1. 定義を確認する
    データソース定義が記述してあるXMLファイルを見つけるか、設定ツールからエントリを見つけます。ここでは、$CATALINA_HOME/conf/localhost/sample.xmlだったとします。中身をLIST2に示します。
    LIST2 書き換える前のsample.xml
    LIST2 書き換える前のsample.xml
    データソースはResource要素のtype属性として定義されており、ResourceParams要素で実体を定義しています。
  2. 定義を書き換える
    データソースをOracleDataSourceに置き換えるために、次のようにLIST2を書き換えます。LIST3がその結果です。
    LIST3 書き換え後のsample.xml
    LIST3 書き換え後のsample.xml
    ファクトリ BasicDataSourceFactoryをOracleDataSourceFactoryに変更します。必須です
    driverClass 削除します。必須です
    暗黙コネクションキャッシュ connectionCachingEnabledをtrueにして暗黙コネクションキャッシュを有効にします。必須です
    暗黙文キャッシュ BasicDataSourceでも使用できましたが、改めて追加します。implicitCachingEnabledをtrueにします
    validationQuery以下のプロパティ LIST2中のBasicDataSource固有のプロパティ設定は、OracleDataSourceの設定ファイルには書けませんので削除します
  3. コネクションキャッシュのプロパティを設定する
    コネクションキャッシュのプロパティは、アプリケーションのコーディング中で設定する必要があります。データソースの実体に対して一度だけプロパティを設定する処理が必要です。LIST4にプロパティ設定メソッドを示します。
    LIST4 プロパティ設定メソッド
    LIST4 プロパティ設定メソッド
    ここではプロパティの各設定値を直に書いていますが、プロパティらしく外部ファイルに定義して読み込む実装のほうがスマートです。
  4. autoCommitに注意する
    OracleDataSourceを使用すると、BasicDataSourceで設定できたdefaultAutoCommit 注1の設定が無効になります。そのため、コネクションの取得後に自動コミット(autoCommit)を無効にしているかどうかを、アプリケーションから確認する必要があります。余談ですが、defaultAutoCommitのような「かゆいところに手が届く」機能は、便利な反面、得てして移植性を落とす原因となります。
注1:本来はConnectionsオブジェクトが持つプロパティ。デフォルトはtrueで、SQLの実行ごとにコミットが発行されてしまう。ほとんどのアプリケーションでは前もってfalseにしておかないと、トランザクション処理を記述できない。

Strutsの場合

Strutsでは、WEB-INF/struts-config.xmlというXMLファイルでデータソースを定義しています。外部ツールを使用しない限り、基本的にはこのファイルを直接書き換えます。ここでは先のTomcatと同じく、DBCPで動作していたデータソースをOracleDataSourceの暗黙コネクションキャッシュに切り替える例を示します。

  1. 定義を確認する
    Strutsでは、Tomcatとは異なりデータソースのためのdata-sourcesディレクティブが存在します。struts-config.xmlの中身はLIST5のとおりです。
    LIST5 書き換え前のstruts-config.xml
    LIST5 書き換え前のstruts-config.xml
  2. 定義を書き換える
    OracleDataSourceに置き換えるために、struts-config.xmlを書き換えます。方法はTomcatの場合とまったく同一ですので、ここは省略します。書き換え後のstruts-config.xmlをLIST6に示します。
    LIST6 書き換え後のstruts-config.xml
    LIST6 書き換え後のstruts-config.xml
  3. コネクションキャッシュのプロパティを設定する
    Tomcatの場合と同じく、コネクションキャッシュのプロパティは、アプリケーションのコーディング中で設定する必要があります。Strutsでは、Actionクラス 注2の子クラスからgetDataSourceメソッド 注3を使ってデータソースを獲得します。LIST7のようにデータソースを取得するのが一般的ですが、これではすべてのActionクラスの子クラスにコネクションキャッシュのプロパティを設定するコードを書くことになり、非常に非効率です。
    LIST7 Strutsにおける一般的なデータソースの取得
    LIST7 Strutsにおける一般的なデータソースの取得
    注2:Strutsで定義されるMVCモデルで言うModel部分の雛形クラス。Actionクラスを継承したクラスにアプリケーションロジックを記述する。
    注3:Actionクラスに定義されている独自メソッドで、JNDIを隠蔽した形でデータソースを取得できる。
    それを解決する方法の1つがLIST8で、Actionクラスを継承してプロパティを設定するための抽象クラス(LIST8ではExtendActionクラス)を作成し、アプリケーションロジックはその抽象クラスを継承したクラスに記述します。
    LIST8 コネクションキャッシュのプロパティ設定に対応
    LIST8 コネクションキャッシュのプロパティ設定に対応
  4. autoCommitに注意する
    Tomcatと同様、OracleDataSourceを使用すると、BasicDataSourceで設定できたdefaultAutoCommitの設定が無効になります。Connectionオブジェクトの取得後にautoCommitを無効にしているかどうかを確認する必要があります。

OC4Jの場合

OC4Jでは、<AS_HOME>/j2ee/home/config/data-sources.xmlファイルでデータソースが管理されています。Strutsと同様、このXMLファイルを直接書き換えて設定を変更します。ここでは、OC4J管理下のデータソースから、OracleDataSourceの暗黙コネクションキャッシュへ変更する例を紹介します。
なお、ここで使用するのは最新バージョンのOC4J 10gとします。

  1. 変更を確認する
    OC4Jで使用するデータソースには、Managed Data SourceとNative Data Sourceの2種類があります。Managed Data SourceはOC4Jが提供するデータソースで、Native Data Sourceは外部で用意したデータソースです。LIST9のdata-sources.xmlでは、Managed Data Sourceの定義をしています。
    LIST9 変更前のdata-sources.xml
    LIST9 変更前のdata-sources.xml
    Managed Data Sourceでは、コネクションプーリング機能をOC4Jのモジュールが提供しますので、当然、細かなプロパティもすべてこのファイルの中に記述できます。
  2. 定義を書き換える
    OC4Jでは、Native Data Sourceを用いることで、任意の外部データソースのコネクションプーリング機能を利用できます。書き換え後のdata-sources.xmlはLIST10のようになります。
    LIST10 変更後のdata-sources.xml
    LIST10 変更後のdata-sources.xml
    connection-poolディレクティブは削除されています。
  3. コネクションキャッシュのプロパティを設定する
    Tomcatの場合と同様、別途定義したメソッドなどを使ってコネクションキャッシュのプロパティを設定します。LIST4を参考にしてください。

Sun ONEの場合

Sun ONEでは、server.xmlファイルを直接編集するか、または開発ツールであるSun ONE Studioから設定することで、コネクションプーリングを行なうデータソースを変更できます。ここではSun ONE Studioからの設定例を紹介します。

  1. コネクションプーリングを行なうデータソースの登録
    「RunTime」ペインから、「Server Registry」→「Installed Servers」→「Sun ONEApplication Server 7」→「UnregisteredJDBC Connection Pools」を選択することで、コネクションプーリングを行なうデータソースを選択できます。ここに、OracleDataSourceを登録します。
    プロパティには、TomcatやStrutsなどと同じ項目を設定できます。connectionCachingEnabledを忘れずにtrueにしておきましょう。
  2. JNDIリソース位置を登録
    1. の「Unregistered JDBC ConnectionPools」と同じ階層にある「UnregisteredJDBC Data Source」を選択し、1. で登録したデータソースを登録してJNDI名を登録します。
  3. コネクションキャッシュのプロパティを設定する
    Tomcatなどの場合と同様、別途定義したメソッドなどを用いてコネクションキャッシュのプロパティを設定します。LIST4を参考にしてください。

WebLogic/WebSphere/Borland Enterprise Serverの場合

これらのAPサーバーでは、コネクションプーリングを行なうデータソースを変更するインターフェイスを用意していません。開発者自身でJNDIツリーを作成し、データソースを登録する必要があります。その作業は本特集の説明範囲を越えますので、手順の概要だけを説明します。ここまでと同じく、OracleDataSourceの暗黙コネクションキャッシュを使用する方法を取り上げます。
WebLogic Serverや Borland Enterprise Serverでは、前出の表1のように、JNDIツリーを変更するインターフェイスが用意されています。このJNDIツリーに、DataSourceインターフェイスを持ち、実体がOracleDataSourceであるリソースを作成します。設定できるプロパティについては、ここで設定しておきます。その後、アプリケーション側から参照できるようにバインドも忘れずにしておきます。あとは、Tomcatなどと同様の手順で登録したデータソースを利用できます。
WebSphere Application Serverでは、JNDIツリーを自由に変更できるインターフェイスが用意されていないので、自分でJNDIツリーを構築する必要があるものと思われます。ファイルベースでのJNDIツリーを一から構築するのは、まさに本格的なJNDIプログラミングとなります。手間を考えると、Strutsなどのフレームワークを使うか、そのまま用意されているコネクションプーリング機能を使用することをお勧めします。

.NETのコネクションプーリング

コネクションプーリングは、.NETアプリケーションでも当然、利用される技術です。そこで次に、.NETアプリケーションにコネクションプーリング機能を提供するミドルウェア「ODP.NET」を解説します。

ODBC.NETとOLE DB.NET

.NETの標準的なDBアクセスコンポーネントであるODBC.NETやOLE DB.NETは、基本的にコネクションプーリング機能が実装されていません。そのため、DBを使用する処理が始まるたびにDBサーバーへのコネクションの生成が発生します。当然、WebアプリケーションなどではOracleに対してパート1で説明したような過負荷の問題が発生してしまいますので、コネクションプーリングやそれに似た仕組みを自作するなど、アプリケーション側での解決が必要となります(図6)。

図6 .NETのコネクションに関する問題
図6 .NETのコネクションに関する問題

大規模なWebアプリケーションとIIS

なぜ、Javaでは乱立状態に近いコネクションプーリング技術が、.NET環境では普及していないのでしょうか。これには理由があります。まず、.NET系でコネクションプーリングが必須となるような大規模なWebアプリケーションの開発実績が、IIS(Internet InformationServices)に集中している点です。
確かに、IIS(ASP.NET)ではODBC 3.0のコネクションプーリング機能を使用してパフォーマンスを向上させることができます(図7)。

図7 IISでのコネクションプーリング
図7 IISでのコネクションプーリング

しかし、マイクロソフトのナレッジベースKB:164221に「INFO:How to EnableConnection Pooling in an ODBC Application(ODBCアプリケーションでコネクションプーリングを可能にする方法)」という情報はありますが、例えば、C#.NETでコーディングなしにコネクションプーリング機能を使用する方法などの解説が見あたりません。
ただ、.NETでもIIS以外のAPサーバーが独自のコネクションプーリングを実装すれば、Javaと似たような状況になるかもしれません。

COLUMN:Fillメソッドの魔力

例えば、ADO.NETではデータセットに対してFillメソッドを実行するだけで、テーブル単位でデータを取得できます。JavaのようにResultSetオブジェクトにnextメソッドを使って1行ずつ読み出す(フェッチする)といったコードを書かなくても、同様の処理を行なう方法が多く提供されています。
とても便利に見えますが、Fillメソッドのようなデータベースアクセス隠蔽技術を多くのユーザーが利用するアプリケーションで使うのは、以下に挙げる点でとても危険に思えます。
まず、明らかに不要なデータまでフェッチしていないかどうか。100万件のデータのうち、最初の10件だけを画面に表示する場合に、100万件にフェッチするのは大変もったいない動作です。
次に、不要なデータをロックしていないか。ほかのユーザーもロックするかもしれないのに、とりあえず表全体をロックしておくという処理が、意図しない間に行なわれてしまう場合があります。
さらに、すでに変更されているかもしれない古いデータをもとに処理を行なっていないか。ほかのユーザーによって変更される可能性のあるデータに対し、最低限の範囲でロックをかけてから参照するという処理は、データベースアクセス隠蔽技術を使ったプログラミングでは記述できない場合があります。
便利なオブジェクトの動作がはっきりしない場合、OracleではSQLトレースを観察するなどして、無駄なアクセスがないかどうかを確認するようにしましょう。

ODP.NET

ODP.NET(Oracle Data Provider .NET)は、オラクルが提供する.NETアプリケーションからOracleデータベースに接続するためのアクセスコンポーネントです(図8)。

図8 ODP.NET
図8 ODP.NET

ODP.NETが登場して、ようやくOracleを利用するすべての.NETアプリケーションが簡単にコネクションプーリングの恩恵を与ることができるようになったと言っても過言ではないかもしれません。
ODP.NETはOracle Clientライブラリをネイティブで用いるため、コネクションプーリング以外の処理も高速です。Oracleを利用するアプリケーションを作成する場合は、クライアント側/サーバー側を問わず、利用することをお勧めします。

ODP.NETのインストール

ODP.NETのデメリットと言えば、インストールに手間がかかることです。ほかの.NETモジュールのようにWindows Updateで配信されるわけではなく、クライアント1台1台にData Accessモジュール 注4をインストールしていかなければなりません。
インストールされるモジュールは、OracleClientのOCIクライアント部分とODBC.NET、OLE DB.NETのOracleモジュール、およびODP.NETです。

注4:このモジュールは、Oracle Technology Network JapanのWebサイトから無償でダウンロードできます( http://www.oracle.com/technology/global/jp/software/tech/windows/odpnet/index.html)。

ODP.NETのコネクションプーリングの仕組み

ODP.NETのコネクションプーリングは、独特の仕組みで暗黙的に動作します。OracleConnectionクラスでDBサーバーへのコネクションを生成する際、ConnectionStringフィールドにコネクションプーリング関連のパラメータ文字列を埋め込むことによって、コネクションプーリングが機能し始めます(LIST11)。

LIST11 コネクションプーリングの使用
LIST11 コネクションプーリングの使用

コーディング上、コネクション生成の仕組み自体には、まったく変化はありません。
表6にコネクションプーリング関連のパラメータを示します。

表6 コネクションプーリング関連のパラメータ
表6 コネクションプーリング関連のパラメータ

プールされるコネクションは、コネクションプーリングに関するパラメータも含めたConnectionStringプロパティの値で識別されます。ConnectionStringの値がコネクションプール名の代わりとなるわけです(図9)。

図9 コネクションプールの識別子
図9 コネクションプールの識別子

ODP.NETにもメンテナンススレッドは存在し、「レギュレータスレッド」と呼ばれます。アイドル物理接続の切断など、行なうことはJavaでのメンテナンススレッドと同等です。

上手に使うには

パート1からここまで述べてきたように、コネクションプーリングにはさまざまな機能が必要です。ODP.NETにはまだ足りない機能があることを把握した上で利用してください。

  1. 文キャッシュ
    文キャッシュの機能は持ちませんので、SQL文の解析処理によるDBサーバーの過負荷には気を付けてください。アプリケーション側ではできるだけカーソルを開かないなど、コーディングに配慮が必要となります。
  2. 障害時の挙動
    動作は楽観的で、レギュレータスレッドが自動的にコネクションプールを再構成することがありません。アプリケーション側で再獲得までを責任を持って実装する必要があります。
  3. 監視
    コネクションプーリングに関するパラメータは取得できませんので、例えば、待ち行列の長さなどは自作ツールでも監視できません。アプリケーション側でコネクション獲得のアクティビティをロギングしておくなどの回避策を採ることをお勧めします。
  4. アラート
    アラートを上げる仕組みを持ちませんので、3. 監視とともに、きちんとアプリケーション側でケアしましょう。
COLUMN:コネクション生存期間と.NET

.NET環境でアプリケーションを作成する場合、Javaと異なりコネクション生存期間が分かりづらいことがあります。Javaではコネクションの獲得を明示的に行なうスタイルが一般的なため、トランザクションの生存期間とコネクション生存期間を一致させることは容易ですし、実例も多く紹介されています。
しかし.NETでは、例えばデータアダプタやデータセットなどを用いるなど、コーディングを行なうことなくデータベースとの接続部分を実装する方法が数多くあります。気づかないうちにコネクションプーリング機能を使用していながら、意図せずに長時間コネクションを獲得したままになることがないよう、ツールが自動的に生成したコードをチェックすることをお勧めします。

おわりに

コネクションプーリングは、疎な関係のオブジェクトを正しくキャッシュするための技術として発展してきました。特にWebアプリケーションでは常識的なものとなっています。
本特集では、コネクションプーリングの仕組みや実装の切り替え、.NETでのコネクションプーリング事情などをある程度掘り下げられたと思います。さまざまなコネクションプーリングを取捨選択する文化が生まれれば幸いです。Javaでは究極のコネクションプーリングが生まれる日も近い気がします。.NETにも、DBCPやコネクションキャッシュのような実装が期待されるところです。
少しでもコネクションプーリングで解決できるパフォーマンストラブルが減り、設計の困難さが和らげばと願っています。

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

Copyright © 2009, Oracle Corporation Japan. All rights reserved.
無断転載を禁ず

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

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

小田 圭二 小田 圭二(おだ けいじ)
1996年日本オラクル入社。人事教育本部にて、新卒や中途採用社員に対し、データベースやOS、ネットワークの講師を5年ほど経験した後、2000年にテクノロジーコンサルティング本部に異動。 テクノロジーのコンサルタントとして、主に大規模ミッションクリティカルシステムを担当。
ポリシーは、「OracleもOS上で動くアプリケーションにすぎない。だから、OS、ストレージ、ネットワークを学ぶべき」。 スキル面の興味は、アーキテクチャ、DBA、インフラ技術、教育、コンサル手法など。