2 データベース・アプリケーションの接続方法

データベース接続とは、クライアント・プロセスとデータベース・インスタンスとの間の物理的な通信経路のことです。データベース・セッションは、データベースに対する現在のユーザー・ログインの状況を示す、データベース・インスタンス・メモリー内の論理エンティティです。セッションは、ユーザーがデータベースから認証された時点から、ユーザーが接続を切断するか、データベース・アプリケーションを終了する時点まで続きます。1つの接続では、セッションが確立されないか、1つ以上のセッションが確立されます。

Oracle Real-World Performanceグループが調査するOLTPのパフォーマンス問題のほとんどは、アプリケーションの接続方法に関連しています。このため、健全な接続方法を設計することはアプリケーション開発において重要で、特に、規模を拡大して増加する要件を満たす必要のある企業環境では重要です。

トピック:

接続プールの設計ガイドライン

接続プールは、アプリケーションから使用できるOracleデータベースへの接続のキャッシュです。

実行時に、アプリケーションはプールに接続をリクエストします。リクエストを満たすことができる接続がプールにある場合、その接続がアプリケーションに戻されます。アプリケーションは、その接続を使用してデータベースで処理を実行した後、接続をプールに返します。リリースされた接続は次の接続リクエストに使用できます。

静的接続プールでは、プールに含まれている接続の数は固定のため、要件にあわせて増やすことはできません。そのため、プールに新しいアプリケーション・リクエストを満たすアイドルな接続がみつからない場合、リクエストはキューに格納されるか、エラーが返されます。ただし、動的接続プールでは、プールが新しい接続を作成してから、それをアプリケーションに戻します。理論的には、動的接続プールではプール内の接続数を増加および減少させることができ、そのため、不要な接続の維持に浪費される場合のあるシステム・リソースの節約に役立ちます。ただし、実際には動的接続プールの方法では潜在的接続ストームを許容するため、サブスクリプションが超過する問題が発生します。

接続ストーム

接続ストームは、アプリケーション・サーバーがさらに多くの接続リクエストを起動するが、データベース・サーバーCPUがすぐにスケジュールすることができないという競合状態で、これによりアプリケーション・サーバーはさらに多くの接続を作成します。

接続ストームの間、データベース接続の数は1分未満の間に数百から数千に急騰します。

動的接続プールは接続ストームを起こしがちです。接続リクエストの数が増えると、データベース・サーバーはCPUコアの数に対して過剰サブスクライブになります。指定の時間では、1つのCPUコアでは1つのプロセスしか実行できません。そのため、サーバー上に32個のコアがある場合、一度に32プロセスしか実行できません。アプリケーション・サーバーが数百または数千の接続を作成した場合、CPUはその数のプロセスについていこうとシステム上の時間を取り合うためにビジーになります。

データベース内では、アクティブ・セッションの数が増加すると待機するアクティビティが増加します。このアクティビティはASHレポートおよびAWRレポートで待機イベントを参照することで確認できます。典型的な待機イベントにはエンキューへのラッチ、行キャッシュ・オブジェクト、ラッチ・フリー、enq : TX-index contentionおよびバッファ・ビジー待機が含まれます。待機イベントが増加すると、セッションは作業を実行できないため、トランザクション・スループットが低下します。サーバーのコンピュータは過剰サブスクライブされているため、監視ツール・プロセスはCPU上の時間を勝ち取る必要があります。最も極端なケースでは、キーボードが使用できなくなり、デバッグが困難になります。

接続ストームを回避するためのガイドライン: 静的プールの使用

Oracle Real-World Performanceグループでは、動的接続プールではなく、静的接続プールの使用をお薦めします。

何年にも渡る接続ストームの診断によって、Oracle Real-World Performanceグループは、動的接続プールが必要なワークロードに対して過剰なプロセスを使用することを発見しました。広く行き渡っている通説では、動的接続プールは必要に応じて接続を作成し、必要がなくなると接続を減らすとされています。実際には、接続プールが使い果たされると、アプリケーション・サーバーはデータベース接続のプールのサイズを急速に増加します。セッションの数はシステムへの小さな負荷でも増え、これによりすべてのセッションがアクティブになる際にパフォーマンスの問題を引き起こします。

動的接続プールはシステムをすぐに不安定にしてしまうため、Oracle Real-World Performanceグループでは、動的接続プールよりも静的接続プールをお薦めしています。

接続の数を減らすと、CPUのストレスが減り、これによりレスポンス時間が速くなりスループットが向上します。この結果は矛盾しているように感じるかもしれません。パフォーマンスは次の理由で向上します。

  • セッションが減るということは、データベース内の競合に関連する待機イベントが減ることを意味します。接続を減らすと、それまでラッチのサイクルを消費し、競合を仲裁していたCPUはデータベース・トランザクションの処理に多くの時間を割くことができるようになります。

  • 接続の数が減少すると、接続はCPU上に長くスケジュールされていられるようになります。結果として、これらのプロセスに関連するすべてのメモリー・ページはCPUキャッシュに存在し続けます。スケジューリングがさらに効率的になり、メモリーを消費しなくなります

経験から、Oracle Real-World Performanceグループでは、%userと%systemのCPU使用率の比率を90/10にすることと、データベース・サーバーのCPUコアごとに、割り当てるプロセスを平均10以内することをお薦めしています。接続の数は、CPUコア・スレッドではなく、CPUコアの数に基づくようにしてください。たとえば、サーバーに2つのCPUがあり、それぞれのCPUに18のコアがあるとします。各CPUコアには2つのスレッドがあります。Oracle Real-Wold Performanceグループのガイドラインに基づくと、アプリケーションではデータベース・インスタンスに対して36から360の接続を持つことができます。

ログイン方法の接続ガイドライン

すべてのデータベース開発者が直面する問題は、アプリケーションがいつどのようにデータベースにログインしてトランザクションを起動するかです。

最適に次ぐ設計では、データベース・アプリケーションは、それぞれのSQLリクエストに対して次のステップを実行します。

  1. データベースにログインします。

  2. INSERT文またはUPDATE文などのSQLリクエストを発行します。

  3. データベースからログアウトします。

ログイン/ログアウトの方法を使用するアプリケーションは機能要件を満たすことができます。また、1秒当たりのトランザクションの数が少ないときには優れたパフォーマンスを示します。ただし、データベースでのログインおよびログアウトは非常にリソース消費量の多い操作です。Oracle Real-World Performanceグループは、そのようなアルゴリズムを使用するアプリケーションは、うまくスケーリングできず、特に動的接続プールを使用している場合に重大なパフォーマンスの問題を引き起こす可能性があることを発見しました。ログイン/ログアウトの方法では、通常、接続プールは使用しません。

アプリケーションがログイン/ログアウトの設計を使用し、DBAおよび開発者が問題の原因に気がつかないと、最初に起こりうる症状はデータベース・スループットの低下と応答時間の不規則で極端な増大です。データベースの診断調査では、リソース競合が少ない間はアクティブなセッションがかなり少ないことを示すことがあります。

最適でないパフォーマンスに対するヒントとしては、1秒当たりのログイン数は1秒当たりのトランザクション数に近くなります。トランザクションごとのログイン/ログアウトの方法が使用されると、データベース・インスタンスおよびオペレーティング・システムは、内部的に多くの作業を実行して新しいプロセス、データベース接続および関連するメモリー領域を作成します。こうしたステップの多くはシリアライズされ、CPU使用を低下させ、それによりトランザクション・スループットを低下させます。

前述の理由から、Oracle Real-World Performanceグループでは、多数のトランザクションをサポートするようにスケーリングする必要のあるアプリケーションの場合、ログイン/ログアウト設計を使用しないことを強くお薦めしています。

プログラム・セッション・リークを回避する設計ガイドライン

プログラムが接続を失うと、セッション・リークが起こりますが、データベース・インスタンス内ではセッションはアクティブなままです。リークされたセッションはプログラム的にアプリケーションからみつからなくなります。

最適に設計されたアプリケーションでは、セッション・リークが起こらないようにされています。通常、セッション・リークはアプリケーションによって例外が見つかったために発生します。アプリケーションが例外を適切に処理しない場合、接続はコミットやロールバックを実行することなく停止し、セッションがリークされます。

セッション・リークは、データベース・パフォーマンスおよびデータ整合性の重大な問題を引き起こす可能性があります。一般的に、問題は次の形になります。

  • 失われた接続プール

  • ロック・リーク

  • 論理的な破損

失われた接続プール

設計の不備によって接続プールが失われる場合があります。

たとえば、アプリケーション設計の不備によってセッションが常にリークするとします。リーク率が低かったとしても、動的な接続プールではかつてないほど多くのセッションがプログラム的に使用できなくなります。

結果として使用できる接続プールが減り、残りの接続ではワークロードが維持できなくなります。使用できないセッションは増え続け、プール内に使用できる接続がなくなります。

セッション・リークの確認

セッション・リークはアプリケーションやアプリケーション・サーバーの問題が原因で発生します。これは、データベース単独で修正することはできません。この問題には、アプリケーションやアプリケーション・サーバーで対応する必要があります。セッション・リークを確認する簡単な方法は、データベースへの接続を1つ使用するように接続プールを変更し、アプリケーションをテストすることです。1つの接続を使用してテストを行うと、アプリケーションの問題の根本的な原因を簡単に見つけることができます。

ロック・リーク

ロック・リークは、一般的にセッション・リークの副作用です。

たとえば、バッチ更新の途中のリークされたセッションは表内の複数行に対してトランザクション・ロックを保有している可能性があります。リークされたセッションがロックを保有している場合、ロックを取得したいセッションはリークされたセッションの後にキューを作成します。

ロックを保有しているプログラムはロックを解除するためにクライアントからの対話を待ちますが、プログラム的には接続が失われているため、メッセージは送信されません。そのため、データベースはセッション内でアクティブなどのセッションに対してもコミットまたはロールバックできません。

論理的な破損

リークされたセッションでは、データベースに対するコミットされていない変更が含まれている場合があります。データベース接続が予期せず解除された際にトランザクションが作業の途中だったなどです。

この状況では、次の問題を引き起こす可能性があります。

  • アプリケーションはUIにエラーをレポートします。この場合、お客様はビジネス・オーダーやフライト・スケジュールなどの作業を失ったと苦情を言う可能性があります。

  • UIは、コミットまたはロールバックが発生していなくても、コミット・メッセージを受け取ります。これは、後続のトランザクションがそのトランザクション自体の作業とリークされたセッションの途中までのトランザクションの両方をコミットする可能性があるため、最悪のケースです。このケースでは、データベースは論理的に破損しています。

ランタイム接続ロード・バランシングの使用方法

トピック:

ランタイム接続ロード・バランシングの概要

Oracle Real Application Clusters (Oracle RAC)は、単一データベースを複数ノードにある複数インスタンスで管理するデータベース・オプションです。Oracle RACの共有ディスク方式でデータベースをクラスタ化すると、スケーラビリティが向上します。現在の必要性に応じてノードを簡単に追加または解放でき、いずれかのノードで障害が発生しても別のノードがワークロードを引き継ぐので、可用性が向上します。すべてのインスタンスがデータベース全体にアクセスできるため、Oracle RACではデータベースに高可用性機能とフェイルオーバー機能が追加されます。

作業リクエストのバランシングは、接続時(Oracle Net Servicesで提供される接続時ロード・バランシング)と実行時(ランタイム接続ロード・バランシング)の両方で発生します。Oracle RAC環境の場合、アプリケーションのセッション要求を均等に分散させるために、セッション・プールは、高速アプリケーション通知(FAN)イベントを介してOracle RACロード・バランシング・アドバイザから受信されるサービス・メトリックを使用します。セッション・プールに入ってくる作業要求は、現在のサービス・パフォーマンスを使用して、サービスを提供しているOracle RACのインスタンス全体で分散できます。

接続時ロード・バランシングは、アプリケーションがセッションを作成するときに発生します。プールされたセッションは、各インスタンスでセッションが作業を実行できるようにするため、セッションの作成時にOracle RACインスタンス間で適切に分散される必要があります。

ランタイム接続ロード・バランシングは、アプリケーションが既存のセッション・プールからセッションを選択する際に発生します(したがって頻度の高いアクティビティです)。ランタイム接続ロード・バランシングは、セッション・プール内で作業の処理に最も適切なセッションに作業リクエストをルーティングします。単一インスタンスでのみサービスをサポートするセッション・プールの場合は、プール内で使用可能な最初のセッションで十分です。プールが複数インスタンスにまたがるサービスをサポートしている場合は、適切なサービスを提供できる、または容量の大きいインスタンスが多数のリクエストを取得するように、作業をインスタンス間で分散する必要があります。

OCI、OCCI、JDBC、ODP.NETのクライアント・アプリケーションはすべて、ランタイム接続ロード・バランシングをサポートしています。

ランタイム接続ロード・バランシングの有効化と無効化

クライアントでのランタイム接続ロード・バランシングの有効化と無効化は、クライアント環境によって異なります。

トピック:

OCI

OCIクライアント・アプリケーションの場合、ランタイム接続ロード・バランシングは、アプリケーションがサービス時間に基づいてサービス・メトリックを受信するように、次の操作の実行時にOracle Database 11gリリース1 (11.1)以上のクライアントとOracle Database 10gリリース2 (10.2)以上のサーバーとの通信においてデフォルトで有効になります。

  • アプリケーションをスレッド・ライブラリにリンクしている。

  • OCI環境をOCI_EVENTSおよびOCI_THREADEDモードで作成している。

  • セッション・プールで使用されるサービスに対して、ロード・バランシング・アドバイザの目標と接続ロード・バランシングの目標を構成している。

OCIクライアントのランタイム接続ロード・バランシングを無効にするには、OCISessionPoolCreate()をコールする際にmodeパラメータをOCI_SPC_NO_RLBに設定します。

OCI用のFAN HA (FCF)では、サービスがTRUEになるにはAQ_HA_NOTIFICATIONSが必要です。

関連項目:

OCISessionPoolCreate()の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください

OCCI

OCCIクライアント・アプリケーションの場合、ランタイム接続ロード・バランシングは、次の操作の実行時にOracle Database 11gリリース1 (11.1)以上のクライアントとOracle Database 10gリリース2 (10.2)以上のサーバーとの通信においてデフォルトで有効になります。

  • アプリケーションをスレッド・ライブラリにリンクしている。

  • OCCI環境をEVENTSおよびTHREADED_MUTEXEDモードで作成している。

  • セッション・プールで使用されるサービスに対して、ロード・バランシング・アドバイザの目標と接続ロード・バランシングの目標を構成している。

OCCIクライアントのランタイム接続ロード・バランシングを無効にするには、NO_RLBオプションをStatelessConnectionPool ClassPoolType属性に対して使用します。

OCCI用のFAN HA (FCF)では、サービスがTRUEになるにはAQ_HA_NOTIFICATIONSが必要です。

関連項目:

OCCIインタフェースを使用するランタイム・ロード・バランシングの詳細は、『Oracle C++ Call Interfaceプログラマーズ・ガイド』を参照してください

JDBC

JDBC環境で、ランタイム接続ロード・バランシングは、高速接続フェイルオーバー(FCF)の有効時にOracle Database 11gリリース1 (11.1)以上のクライアントとOracle Database 10gリリース2 (10.2)以上のサーバーとの通信においてデフォルトで有効になります。

JDBC環境で、ランタイム接続ロード・バランシングは、FCF処理で使用するのと同じバンド外ONSイベント・メカニズムを使用する、Oracle Notification Service(ONS)インフラストラクチャに依存します。ランタイム接続ロード・バランシングが機能するためにONSの追加設定や構成は必要ありません。

JDBC環境でランタイム接続ロード・バランシングを無効にするには、値をfalseに設定してsetFastConnectionFailoverEnabled()をコールします。

関連項目:

JDBCインタフェースを使用するランタイム・ロード・バランシングの詳細は、『Oracle Database JDBC開発者ガイド』を参照してください

ODP.NET

ODP.NETクライアント・アプリケーションの場合は、ランタイム接続ロード・バランシングがデフォルトで無効です。ランタイム接続ロード・バランシングを有効にするには、接続文字列に"Load Balancing=true"を含めて、"Pooling=true" (デフォルト)を確認します。

ODP.NET用のFAN HA (FCF)では、サービスがTRUEになるにはAQ_HA_NOTIFICATIONSが必要です。

関連項目:

ランタイム・ロード・バランシングの詳細は、『Oracle Data Provider for .NET開発者ガイドfor Microsoft Windows』を参照してください

ロード・バランシング・アドバイザFANイベントの受信

アプリケーションでは、次の要件がすべて満たされている場合のみロード・バランシング・アドバイザFANイベントを受信できます。

  • Oracleクラスタウェアを伴うOracle RAC環境が設定され、有効化されていること。

  • サーバーが、イベント通知を発行するように構成されていること。

  • アプリケーションがスレッド・ライブラリとリンクされていること。

  • OCI環境がOCI_EVENTSおよびOCI_THREADEDモードで作成されていること。

  • OCCI環境がTHREADED_MUTEXEDおよびEVENTSモードで作成されていること。

  • DBMS_SERVICEパッケージを使用してOracle RAC環境を構成または変更していること。

    サービスの目的および接続ロード・バランシングの目的を設定するため、サービスを次のように変更する必要があります。

    EXEC DBMS_SERVICE.MODIFY_SERVICE("myService",
         DBMS_SERVICE.GOAL_SERVICE_TIME,
         clb_goal => DBMS_SERVICE.CLB_GOAL_SHORT);
    

    定数GOAL_SERVICE_TIMEは、ロード・バランシング・アドバイザがサービスでの処理の実行に要する時間およびサービスで使用可能な帯域幅に基づくことを指定します。

    定数CLB_GOAL_SHORTは、接続ロード・バランシングでロード・バランシング・アドバイザを使用し、ロード・バランシング・アドバイザが有効であることを指定します。接続バランシングの目標はCLB_GOAL_LONGに設定します。ただし、CLB_GOAL_LONGはクローズされたワークロードに対して(つまり、完了した作業の割合と新しく始める作業の割合が等しいときに)最も有効です。

関連項目:

  • OCIクライアントでFANイベントの受信を有効にする手順は、『Oracle Real Application Clusters管理およびデプロイメント・ガイド』を参照してください

  • DBMS_SERVICEの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください

  • OCISessionPoolCreate()の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください

  • JDBCインタフェースを使用するランタイム・ロード・バランシングの詳細は、『Oracle Database JDBC開発者ガイド』を参照してください