11 OCIでのセッション・プーリングおよび接続プーリング

この章では、OCIのセッション・プールおよび接続プーリングの機能について説明します。

この章には次のトピックが含まれます:

11.1 OCIでのセッション・プーリング

セッション・プーリングとは、アプリケーションがデータベースに対するステートレス・セッションのグループを作成してメンテナンスすることを意味します。

これらのセッションは、要求に応じてThinクライアントに提供されます。使用可能なセッションがない場合は、新しいセッションが作成されます。セッションでのクライアントの処理が完了すると、クライアントはプールに対してセッションを解放します。したがって、プール内のセッション数は動的に増加する場合があります。

プール内の一部のセッションに、特定のプロパティを使用してタグを付けることができます。たとえば、ユーザーは、デフォルト・セッションを要求して特定の属性を設定し、そのセッションにラベルまたはタグを付けて、プールに戻すことができます。そのユーザーまたは他のユーザーは、同じ属性を持つセッションを要求できるため、同じタグが付いたセッションを要求できます。プール内に、同じタグが付いた複数のセッションが存在する場合があります。セッションのタグは、変更またはリセットできます。

OCIでのセッション・プーリングを使用して、プロキシ・セッションを作成してメンテナンスすることもできます。

使用可能なセッションがなく、プールの最大サイズに達した場合のアプリケーションの動作は、指定した属性によって決まります。新しいセッションが作成されるか、エラーが戻されるか、またはスレッドがブロックしてセッションが使用可能になるまで待機する場合があります。

セッション・プーリングの主な利点は、パフォーマンスです。データベースへの接続(特にデータベースがリモートの場合)は、時間がかかるアクティビティです。したがって、クライアントでは、時間をかけてサーバーに接続し、資格証明を認証して有効なセッションを受け取るかわりに、プールからセッションを取り出すことができます。

11.1.1 OCIセッション・プーリングの機能

セッション・プーリングが実行できるタスクについて説明します。

セッション・プーリングにより次のタスクを実行できます。

  • ステートレス・セッションのプールを透過的に作成、メンテナンスおよび管理します。

  • アプリケーションでプールを作成し、プール内のセッションの最小数、増分数および最大数を指定するインタフェースを提供します。

  • ユーザーがデフォルト・セッションまたはタグ付けされたセッションをプールとの間で取得および解放するためのインタフェースを提供します。タグ付けされたセッションとは、クライアント定義の特定のプロパティが指定されたセッションです。

  • アプリケーションで、セッションの最小数と最大数を動的に変更できます。

  • 長時間アイドル状態のセッションをクローズし、必要なときにセッションを作成することによって、常に最適な数のセッションがオープンしているようにメンテナンスするメカニズムを提供します。

  • セッション・プーリングで認証を行うことができます。

11.1.2 同種セッション・プールおよび異種セッション・プール

セッション・プールは、同種または異種のいずれかになります。

同種セッション・プーリングとは、プール内のセッションの認証情報が同じ(同じユーザー名、パスワードおよび権限)であることを意味します。異種セッション・プーリングとは、セキュリティ属性と権限がセッションごとに異なる場合があるため、認証情報を指定する必要があることを意味します。

11.1.3 セッション・プーリングでのタグの使用について

ユーザーは、タグを使用して、プール内のセッションをカスタマイズできます。

クライアントは、デフォルト・セッションまたはタグが付いていないセッションをプールから取得して、特定の属性(NLS設定など)をセッションに設定し、OCISessionRelease()コールでセッションに適切なタグを付けて、プールに戻すことができます。

元のユーザーまたは他のユーザーは、同じ属性を持つセッションを使用するために、同じタグが付いたセッションを要求でき、これはOCISessionGet()コールで同じタグを指定することで行います。

この項には次のトピックが含まれます: 複数プロパティ・タグ

11.1.3.1 複数プロパティ・タグ

12cリリース2 (12.2)以上では、タグに複数のプロパティを含めることができます。これは、複数プロパティ・タグと呼ばれます。

複数プロパティ・タグは、セミコロンで区切られた<property-name>=<property-value>の1つ以上のペアで構成されます(<property-name>=<property-value>は両方とも文字列です)。

OCISessionGet()コールの実行中に、taginfoパラメータで最初に出現するプロパティ名は、一致を検索するための最も高い優先順位を付与され、最後に出現するプロパティ名は、最も低い優先順位を付与されます。したがって、文字列内のプロパティの順序は、プール内の一致するセッションを決定する際に重要です。制限のリストの次に続く例は、この注意点を示しています。

この機能は、DRCPでも動作します。

複数プロパティ・タグで渡すことのできるプロパティ名およびプロパティ値には、次の制限が適用されます。
  • プロパティ名とプロパティ値は、どちらも大/小文字が区別されます。

  • プロパティ名は、タグ内で1回のみ使用できます。同じプロパティ名が2回以上指定されると、エラーがスローされます。

  • プロパティ名と値には、どちらも空以外の文字列を指定する必要があります。

  • プロパティ名の前後にある先頭および末尾の空白と、プロパティ値の前後にある先頭および末尾の空白は、切り捨てられます。たとえば、"PDB = PDB1"は"PDB=PDB1"として処理されます。

  • プロパティ名とプロパティ値に空白を挿入することはできません。たとえば、NLS <空白> LANGUAGE=Frenchは、NLSとLANGUAGEの間に空白があるため、エラーとなります。

複数のプロパティの概念を説明するため、CDB環境にデプロイされたアプリケーションで、セッション取得要求を可能なかぎり同じプラガブル・データベース(pdb1など)からのセッションで満足させる必要があるとします。さらに、セッションは同じ言語(FRENCHなど)に属している必要がありますが、セッションに対するより高い優先順位をpdb1に付与します。アプリケーションでは、次のように複数プロパティ・タグを指定できます。

char *props  = “PDB=pdb1;LANGUAGE=FRENCH”

ここで、次のようなプロパティを持つ2つのセッションがプール内にあるとします。

Session 1 = >  “PDB=pdb1;LANGUAGE=CHINESE”
Session 2 = >  “PDB=pdb2;LANGUAGE=FRENCH” 

この場合、PDBプロパティはLANGUAGEプロパティより前に配置されることで、暗黙的により高い優先順位となるため、セッション取得要求(OCISessionGet())は、セッション1を戻します。

関連項目:

セッションのタグ付けの詳細は、「OCISessionGet()」を参照してください

この項には次のトピックが含まれます: セッション状態の修正のためのPL/SQLコールバック

11.1.3.1.1 セッション状態の修正のためのPL/SQLコールバック

複数プロパティ・タグを使用する場合、セッション状態のPL/SQLベースの修正コールバックをサーバーで提供できます。

このアプリケーションで提供されたコールバックは、複数プロパティ・タグで指定されたとおりに、プールからチェックアウトされたセッションをアプリケーションで要求された必要な状態に変換します。このコールバックは、データベース常駐接続プーリング(DRCP)があってもなくても動作します。

このコールバックを使用すると、修正ロジックがサーバー上のセッション状態に対して実行されるため、アプリケーションのパフォーマンスを改善できます。したがって、修正ロジックのために、この機能によりデータベースへのアプリケーションのラウンドトリップがなくなります。コールバックは、OCISessionGet()を使用して接続しているユーザーによって提供されます。コールバックは、OCISessionPoolを使用しないアプリケーションまたはカスタム・プールを使用するアプリケーションのOCISessionGet()に渡される認証ハンドルの属性OCI_ATTR_FIXUP_CALLBACKとして指定する必要があります。OCISessionPoolを使用するアプリケーションでは、この属性は、認証ハンドルで設定し、次にそれを属性OCI_ATTR_SPOOL_AUTHとしてセッション・プール・ハンドルで設定する必要があります。

例11-1 PL/SQLの修正コールバックの例

次のPL/SQL修正コールバックのサンプル・コード・スニペットは、TIME_ZONE=UTC;NLS_DATE_FORMAT=DD-MM-YYYYなどのALTER SESSION文で、key=valueプロパティを直接使用できるタグを処理します。

CREATE OR REPLACE PACKAGE myPackage AS
  TYPE property_t IS TABLE OF VARCHAR2(64) INDEX BY VARCHAR2(64);
  PROCEDURE buildTab(
    tag          IN  VARCHAR2,
    propertyTab  OUT property_t
  );
  PROCEDURE myPlsqlCallback (
    requestedTag IN  VARCHAR2,
    actualTag    IN  VARCHAR2
  );
END;
/

CREATE OR REPLACE PACKAGE BODY myPackage AS

  -- Parse the "property=value" pairs in the tag
  PROCEDURE buildTab(tag IN VARCHAR2, propertyTab OUT property_t) IS
    property  VARCHAR2(64);
    propertyName  VARCHAR2(64);
    propertyValue VARCHAR2(64);
    propertyEndPos NUMBER := 1;
    propertyStartPos NUMBER := 1;
    propertyNameEndPos NUMBER := 1;
  begin
    WHILE (LENGTH(tag) > propertyEndPos)
    LOOP
      propertyEndPos := INSTR(tag, ';', propertyStartPos);
      IF (propertyEndPos = 0) THEN
        propertyEndPos := LENGTH(tag) + 1;
      END IF;
      propertyNameEndPos := INSTR(tag, '=', propertyStartPos);
      propertyName := SUBSTR(tag, propertyStartPos,
                   propertyNameEndPos - propertyStartPos);
      propertyValue := SUBSTR(tag, propertyNameEndPos + 1,
                    propertyEndPos - propertyNameEndPos - 1);
      propertyTab(propertyName) := propertyValue;
      propertyStartPos := propertyEndPos + 1;
    END LOOP;
  END;

  PROCEDURE myPlsqlCallback (
    requestedTag IN VARCHAR2,
    actualTag IN VARCHAR2
  ) IS
    reqPropTab property_t;
    actPropTab property_t;
    propertyName VARCHAR2(64);
  BEGIN
    buildTab(requestedTag, reqPropTab);
    buildTab(actualTag, actPropTab);

    -- Iterate over requested properties to set state when it's not
    -- currently set, or not set to the desired value
    propertyName := reqPropTab.FIRST;
    WHILE (propertyName IS NOT NULL)
    LOOP
      IF ((NOT actPropTab.exists(propertyName)) OR
         (actPropTab(propertyName) != reqPropTab(propertyName))) THEN
        EXECUTE IMMEDIATE 'ALTER SESSION SET ' || propertyName || '=''' || reqPropTab(propertyName) || '''';
      END IF;
      propertyName := reqPropTab.NEXT(propertyName);
    END LOOP;
    -- Could iterate over other actual props to reset any extra props to a default state
  END;
END myPackage;
/

関連項目:

11.1.4 セッション・プーリング用のOCIハンドル

セッション・プーリング用のハンドル・タイプについて説明します。

セッション・プーリング用のハンドル・タイプは次のとおりです。
11.1.4.1 OCISPool

セッション・プール・ハンドルです。

これは、OCIHandleAlloc()を使用して割り当てます。OCISessionPoolCreate()およびOCISessionPoolDestroy()に渡す必要があります。属性の型はOCI_HTYPE_SPOOLです。

OCIHandleAlloc()コールの例を次に示します。

OCISPool *spoolhp;
OCIHandleAlloc((void *) envhp, (void **) &spoolhp, OCI_HTYPE_SPOOL, 
                        (size_t) 0, (void **) 0));

環境ハンドルに対して、複数のセッション・プールを作成できます。

11.1.4.2 OCIAuthInfo

認証情報ハンドルです。

これは、OCIHandleAlloc()を使用して割り当てます。これは、OCISessionGet()に渡されます。このハンドルでは、ユーザー・セッション・ハンドルでサポートされるすべての属性をサポートします。認証情報ハンドルの属性の型はOCI_HTYPE_AUTHINFOです(表4-1を参照)。

OCIHandleAlloc()コールの例を次に示します。

OCIAuthInfo *authp;
OCIHandleAlloc((void *) envhp, (void **) &authp, OCI_HTYPE_AUTHINFO, 
                      (size_t) 0, (void **) 0));

関連項目:

11.1.5 OCIセッション・プーリングの使用

ユーザー名とパスワードを使用する単純なセッション・プーリング・アプリケーションの作成ステップを示します。

ユーザー名とパスワードを使用する単純なセッション・プーリング・アプリケーションの作成ステップは、次のとおりです。

  1. OCISPoolハンドルに対してOCIHandleAlloc()を使用して、セッション・プール・ハンドルを割り当てます。環境ハンドルに対して複数のセッション・プールを作成できます。

  2. modeOCI_DEFAULT (新規セッション・プールの場合)に設定したOCISessionPoolCreate()を使用して、セッション・プールを作成します。その他のモードについては、関数の説明を参照してください。

  3. スレッドごとにループを行います。次の処理を実行する関数を使用してスレッドを作成します。

    1. OCIHandleAlloc()を使用して、OCIAuthInfo型の認証情報ハンドルを割り当てます。

    2. OCIAttrSet()を使用して、認証情報ハンドルにユーザー名とパスワードを設定します。

    3. modeOCI_SESSGET_SPOOLに設定したOCISessionGet()を使用して、プールされたセッションを取得します。

    4. トランザクションを実行します。

    5. ハンドルを割り当てます。

    6. 文を準備します。

      ノート:

      OCIセッション・プールから取得したサービス・コンテキストを使用する場合、OCISessionGet() (またはOCILogon2())によって戻されたサービス・コンテキストを使用する必要があり、これらのコールの外で他のサービス・コンテキストを作成する必要はありません。

      サービス・コンテキストを指定したOCIStmtPrepare2()を使用して取得した文ハンドルは、後で同じサービス・コンテキストとの組合せでのみ使用でき、異なるサービス・コンテキストとは使用できません。

    7. 文を実行します。

    8. トランザクションをコミットまたはロールバックします。

    9. OCISessionRelease()を使用して、セッションを解放(ログオフ)します。

    10. OCIHandleFree()を使用して、認証情報ハンドルを解放します。

    11. 各スレッドのループを終了します。

  4. OCISessionPoolDestroy()を使用して、セッション・プールを破棄します。

11.1.6 セッション・プーリングのOCIコール

セッション・プーリングのOCIコールの使用方法について説明します。

OCIには、次のタスクを実行するためにセッション・プーリングのコールが用意されています。

11.1.6.1 プール・ハンドルの割当て

セッション・プーリングでは、OCIHandleAlloc()をコールしてプール・ハンドルOCI_HTYPE_SPOOLを割り当てる必要があります。

指定された環境ハンドルに対して複数のプールを作成できます。単一のセッション・プーリングの割当て例を次に示します。

OCISPool *poolhp; 
OCIHandleAlloc((void *) envhp, (void **) &poolhp, OCI_HTYPE_SPOOL, (size_t) 0,
               (void **) 0));

関連項目:

OCIHandleAlloc()

11.1.6.2 プール・セッションの作成

OCISessionPoolCreate()関数を使用して、セッション・プールを作成できます。

このコールの使用例を次に示します。

OCISessionPoolCreate(envhp, errhp, poolhp, (OraText **)&poolName, 
              (ub4 *)&poolNameLen, database, 
              (ub4)strlen((const signed char *)database),
              sessMin, sessMax, sessIncr,
              (OraText *)appusername,
              (ub4)strlen((const signed char *)appusername),
              (OraText *)apppassword,
              (ub4)strlen((const signed char *)apppassword),
              OCI_DEFAULT);

関連項目:

OCISessionPoolCreate()

11.1.6.3 データベースへのログイン

次のコールを使用して、セッション・プーリング・モードでデータベースにログインできます。

  • OCILogon2()

    最も単純なコールです。ただし、ユーザーは、セッションのタグ付けを行うことができません。セッション・プーリング・モードでOCILogon2()を使用してデータベースにログインするコード例を、次に示します。

    for (i = 0; i < MAXTHREADS; ++i) 
    { 
      OCILogon2(envhp, errhp, &svchp[i], "hr", 2, "hr", 2, poolName,
                poolNameLen, OCI_LOGON2_SPOOL));
    }
    
  • OCISessionGet()

    これは、使用するのが推奨されるコールです。これにより、ユーザーは、プール内のセッションにラベル付け(タグ付け)ができるため、特定のセッションを容易に取得できます。次に、OCISessionGet()の使用例を示します。これは、demoディレクトリのcdemosp.cから取り出しました。

    OCISessionGet(envhp, errhp, &svchp, authInfop,
                 (OraText *)database,strlen(database), tag,
                 strlen(tag), &retTag, &retTagLen, &found, 
                 OCI_SESSGET_SPOOL);
    

    OCIセッション・プールから取得したサービス・コンテキストを使用する場合、OCISessionGet() (またはOCILogon2())によって戻されたサービス・コンテキストを使用する必要があり、これらのコールの外で他のサービス・コンテキストを作成する必要はありません。

    サービス・コンテキストを指定したOCIStmtPrepare2()を使用して取得した文ハンドルは、後で同じサービス・コンテキストとの組合せでのみ使用でき、異なるサービス・コンテキストとは使用できません。

11.1.6.4 データベースからのログオフ

ログオン・コールに応じてセッション・プーリング・モードのデータベースからログオフする2つ方法を示します。

次のコールから、ログイン・コールに対応するものを選択し、それを使用してセッション・プーリング・モードでデータベースからログオフします。

  • OCILogoff()

    OCILogon2()を使用して接続を行った場合は、OCILogoff()をコールしてログオフする必要があります。

  • OCISessionRelease()

    OCISessionGet()を使用して接続を行った場合は、OCISessionRelease()をコールしてログオフする必要があります。保留状態のトランザクションは自動的にコミットされます。

11.1.6.5 セッション・プールの破棄

OCISessionPoolDestroy()をコールして、セッション・プールを破棄します。

これを次の例に示します。

OCISessionPoolDestroy(poolhp, errhp, OCI_DEFAULT);

関連項目:

OCISessionPoolDestroy()

11.1.6.6 プール・ハンドルの解放

セッション・プール・ハンドルを解放するには、OCIHandleFree()をコールします。

これを次の例に示します。

OCIHandleFree((void *)poolhp, OCI_HTYPE_SPOOL);

ノート:

開発者: 接続をプールに解放する前に、オープン・トランザクションをコミットまたはロールバックしてください。そうしない場合、接続が解放されるときに、Oracle Databaseでは自動的にオープン・トランザクションがコミットされます。

セッション・プールの使用中にインスタンス障害が検出されると、OCIではそのインスタンスへのセッションのクリーン・アップを試みます。

関連項目:

OCIHandleFree()

11.1.7 OCIセッション・プーリングの例

テスト済の完全なプログラムのセッション・プーリングの例の記載場所を示します。

テスト済の完成プログラムでのセッション・プーリングの例は、demoディレクトリのcdemosp.cを参照してください。

11.2 データベース常駐接続プーリング

データベース常駐接続プーリング(DRCP)は、アプリケーションがデータベース接続を取得し、この接続で比較的短い時間動作してから接続を解放する一般的なWebアプリケーションの使用シナリオに対し、データベース・サーバーの接続プールを提供します。

DRCPではサーバー・プロセスをプーリングされ、そのそれぞれは、専用のサーバー・プロセスとデータベース・セッションの組合せと同等のものです。(これからは、これら「専用」サーバー・プロセスをプール・サーバーと呼びます。)

DRCPは、中間層プロセス内のスレッド間で接続を共有する中間層接続プールを補完します。また、DRCPを使用すると、同じ中間層ホスト上の中間層プロセス間、および異なる中間層ホスト上の中間層プロセス間でもデータベース接続を共有できます。この結果、大量のクライアント接続をサポートするために必要となる基本データベース・リソースが大幅に減少するため、データベース層のメモリー・フットプリントが縮小し、中間層とデータベース層の両方のスケーラビリティが向上します。すぐに使用可能なサーバーのプールが提供されていると、クライアント接続の作成および分割にかかるコストを削減できるというメリットがあります。

DRCPは、中間層接続プーリングを実行できないマルチプロセス・シングル・スレッド・アプリケーション・サーバー(PHP/Apacheなど)を含むアーキテクチャに特に適しています。DRCPを使用すると、データベースは同時接続数を数万にまで増やすことができます。

関連項目:

DRCPの詳細は、『Oracle Database開発ガイド』を参照してください

11.3 Traffic DirectorモードでのOracle Connection Managerの使用について

Traffic DirectorモードのOracle Connection Managerは、サポートされているデータベース・クライアントとデータベース・インスタンスの間に配置されているプロキシです。

Oracle Database 11gリリース2 (11.2)以上からサポートされているクライアントは、Traffic DirectorモードでOracle Connection Managerに接続できます。Traffic DirectorモードのOracle Connection Managerにより、計画済および計画外のデータベース・サーバー停止の高可用性(HA)、接続の多重化のサポート、およびロード・バランシングが向上します。Traffic DirectorモードでのOracle Connection Managerのサポートは、次の各項で詳しく説明されています。

操作モード

Traffic DirectorモードのOracle Connection Managerは、次に示す操作モードをサポートしています。

  • プール接続モードでは、Traffic DirectorモードのOracle Connection Managerは、次のデータベース・クライアント・リリースを使用するアプリケーションをサポートしています。
    • OCI、OCCIおよびオープン・ソースのドライバ(Oracle Database11gリリース2( 11.2.0.4)以上)

    • JDBC (Oracle Database 12cリリース1 (12.1)以上)

    • ODP.NET (Oracle Database 12cリリース2 (12.2)以上)

    さらに、アプリケーションではDRCPを使用する必要があります。つまり、アプリケーションは接続文字列(またはtnsnames.ora別名)でDRCPを有効にする必要があります。

  • 非プール接続(つまり専用)モードでは、Traffic DirectorモードのOracle Connection Managerで、データベース・クライアント・リリースのOracle Database11gリリース2 (11.2.0.4)以上を使用するアプリケーションをサポートしています。このモードでは、接続の多重化などの一部の機能は使用できません。

主な機能

Traffic DirectorモードのOracle Connection Managerでは、次の機能に対するサポートが提供されます。
  • 透過的パフォーマンス拡張機能と接続の多重化。次の機能があります。
    • 文キャッシュ、行のプリフェッチ、および結果セット・キャッシュは、すべての操作モードに対して自動有効化されます。

    • プロキシ常駐接続プール(PRCP)を使用したデータベース・セッションの多重化(プール・モードのみ)。ここで、PRCPは、データベース常駐接続プーリング(DRCP)のプロキシ・モードです。アプリケーションで、Traffic DirectorモードのOracle Connection Managerとデータベースの間の透過的接続時ロード・バランシングおよび実行時ロード・バランシングが得られます。

    • Traffic DirectorモードのOracle Connection Managerの複数インスタンスの場合、クライアント側の接続時ロード・バランシングを通じて、またはロード・バランサ(BIG-IP、NGINXなど)を使用して、アプリケーションの拡張性が向上します。

  • アプリケーションの停止時間なし
    • 計画済データベース・メンテナンスまたはプラガブル・データベース(PDB)の再配置
      • プール・モード

        Traffic DirectorモードのOracle Connection Managerは、計画済停止のOracle Notification Service(ONS)イベントに応答し、作業をリダイレクトします。要求が完了した時、Traffic DirectorモードのOracle Connection Managerでプールから接続が排出されます。サービスの再配置は、Oracle Database 11gリリース2 (11.2.0.4)以上でサポートされています。

        PDBの再配置の場合、Traffic DirectorモードのOracle Connection Managerは、PDBが再配置される際にインバンド通知に応答します。これは、ONSが構成されていない(Oracle Databaseリリース18c、バージョン18.1以上のサーバーに対してのみ)場合でも同様です。

      • 非プール・モード、つまり専用モード

        クライアントからのリクエスト境界情報がない場合、Traffic DirectorモードのOracle Connection Managerは、(リクエスト/トランザクションの境界にまたがって保持される必要がある状態が単純なセッション状態およびカーソル状態のみであれば)多くのアプリケーションの計画済停止をサポートします。次の機能がサポートされます。
        • トランザクション境界でサービス/PDBを停止するか、Oracle Databaseリリース18cの継続的なアプリケーション可用性を利用してリクエスト境界でサービスを停止します。

        • Traffic DirectorモードのOracle Connection Managerでは、透過的アプリケーション・フェイルオーバー(TAF)フェイルオーバー・リストアを利用して、単純な状態を再接続してリストアします。

    • 読取りがほとんどのワークロード向けの計画外データベース停止

  • シングル・ポイント障害を回避する、Traffic DirectorモードのOracle Connection Managerの高可用性。これは次によってサポートされます。
    • 接続文字列でロード・バランサまたはクライアント側のロード・バランシング/フェイルオーバーを使用した、Traffic DirectorモードのOracle Connection Managerの複数インスタンス。

    • Traffic DirectorモードのOracle Connection Managerインスタンスのローリング・アップグレード。

    • 計画済停止の場合のクライアントからTraffic DirectorモードのOracle Connection Managerへの既存の接続の正常終了。

    • Oracle Databaseリリース18c以上のクライアントへのインバンド通知。

    • 古いクライアントの場合、通知が現在のリクエストの応答とともに送信されます。

  • セキュリティと分離を実現するために、Traffic DirectorモードのOracle Connection Managerは次の機能を提供します。
    • Transmission Control Protocol/Transmission Control Protocol Secure(TCP/TCPS)およびプロトコル変換をサポートするデータベース・プロキシ

    • IPアドレス、サービス名およびSecure Socket Layer/Transport Layer Security(SSL/TLS)ウォレットに基づくファイアウォール

    • マルチテナント環境でのテナントの分離

    • DoS攻撃とファジング攻撃からの保護

    • Oracle DatabaseオンプレミスとOracle Cloudの間でのデータベース・トラフィックのセキュアなトンネリング

関連項目:

11.4 OCIでの接続プーリング

接続プーリングとは、ロードを均衡化するために、再使用可能な物理接続のグループ(プール)を複数のセッションで使用することです。

プールは、アプリケーションではなく、OCIにより管理されます。Webアプリケーション・サーバーおよび電子メール・サーバーの中間層アプリケーションでも接続プーリングを使用できます。

この機能は、バックエンドのOracle Databaseに接続しているWebアプリケーション・サーバーで使用する方法があります。Webアプリケーション・サーバーで、データベース・サーバーから同時に複数のデータ要求を受けたとします。アプリケーションでは、アプリケーションの初期化を行うとき、各環境にプール(またはプール・セット)を作成できます。

11.4.1 OCI接続プーリングの概念

Oracle Databaseは、データベース・セッションと接続のファイングレイン管理など、いくつかのトランザクション・モニター機能を備えています。データベース・セッションのファイングレイン管理は、接続(サーバー・ハンドル)からデータベース・セッション(ユーザー・ハンドル)の概念を切り離すことで実行されます。セッション切替えやセッション移行でOCIコールを使用すると、アプリケーション・サーバーまたはトランザクション・モニターでは、少数の物理接続で複数のセッションを多重化でき、したがって、接続およびバックエンドのOracleサーバー・プロセスをプールすることで、高度な拡張性が実現します。

接続プール自体は通常、物理接続の共有プールで構成され、同じ数の専用サーバー・プロセスを含むバックエンド・サーバー・プールに変換されます。

物理接続の数は、アプリケーションで使用するデータベース・セッションの数より少なくなります。物理接続とバックエンド・サーバー・プロセスの数も、接続プーリングを使用することで少なくなります。これによって、多重化できるデータベース・セッションの数が多くなります。

11.4.1.1 共有サーバーとの類似点と相違点

中間層での接続プーリングは、共有サーバーがバックエンドで提供する機能に似ています。

セッション多重化ロジックを中間層で管理することで、接続プーリングは、専用サーバー・インスタンスを共有サーバー・インスタンスと同じように動作させます。

中間層の接続プールによって、専用サーバー・プロセスへの着信接続を含む専用サーバー・プロセスのプーリングが制御されます。接続プーリングと共有サーバーの主な相違点は、共有サーバーの場合、クライアントからの接続は、通常データベース・インスタンスのディスパッチャへの接続である点です。ディスパッチャには、クライアント要求を適切な共有サーバーに送信します。ただし、接続プールからの物理接続は、中間層からバックエンドのサーバー・プールにある専用サーバー・プロセスに直接接続されます。

接続プーリングは、中間層自体がマルチスレッドである場合にのみ有効です。各スレッドでは、データベースに対するセッションをメンテナンスできます。データベースへの実際の接続は接続プールでメンテナンスされ、その接続(専用データベース・サーバー・プロセスのプールを含む)は中間層のすべてのスレッドの間で共有されます。

11.4.1.2 ステートレス・セッションとステートフル・セッション

ステートレス・セッションは、中間層スレッド間で逐次再利用可能です。

ある3層ユーザーのためにスレッドでデータベース要求を処理した後で、異なる3層ユーザーの異なる要求のために同じデータベース・セッションを再利用できます。

ただし、データベースに対するステートフル・セッションは、特定の3層ユーザーに関連する特定の状態になっている場合があるため、中間層スレッド間で逐次再利用はできません。このような状態の例としては、オープン・トランザクション、文からのフェッチ状態、PL/SQLパッケージ状態などがあります。その状態が存在するかぎり、そのセッションは異なる要求には再利用できせん。

ノート:

ステートレス・セッションも、オープン・トランザクション、オープン文のフェッチ状態などになる可能性があります。ただし、このような状態が継続するのは比較的短期間(中間層スレッドによって特定の3層要求を処理する期間のみ)であるため、(これらの状態がクリーン・アップされると)そのセッションを異なる三層ユーザーのために逐次再利用できます。

ステートレス・セッションは通常、文キャッシュとともに使用されます。

接続プーリングによって、ステートレス接続とステートフル・セッションが提供されます。

関連項目:

ステートレス・セッションを操作する必要がある場合は、「OCIでのセッション・プーリング」を参照してください。

11.4.1.3 複数の接続プール

複数の接続プールの拡張概念を、様々なデータベース接続に使用できます。

複数の接続プールは、異なる優先度がユーザーに割り当てられている場合にも使用できます。接続プーリングを使用すると、異なるレベルのサービス保証を実装できます。

図11-1は、OCI接続プーリングを示しています。

図11-1 OCI接続プーリング

図11-1の説明が続きます
「図11-1 OCI接続プーリング」の説明
11.4.1.4 透過的アプリケーション・フェイルオーバー

接続プーリングでは、透過的アプリケーション・フェイルオーバー(TAF)が使用可能になっています。

BACKUPおよびPRECONNECT句が接続文字列では使用できず接続プーリングとTAFでは機能しない点を除いて、TAFの概念は、接続プール内の各接続に等しく適用されます。

接続プールの接続がフェイルオーバーする場合、主接続文字列自体を使用して接続します。セッションは、そのインスタンスに障害が発生した後に、プールを使用してデータベースとのラウンドトリップを行うときにフェイルオーバーします。リスナーは、サービスベースの接続文字列でよく行われるように、存在する正常なインスタンスに接続をルーティングするよう構成されます。

関連項目:

『Oracle Database Net Services管理者ガイド』の透過的アプリケーション・フェイルオーバーの構成に関する章

11.4.2 接続プーリングのOCIコールの使用

アプリケーションで接続プーリングを使用する場合に実行する必要があるステップを示しています。

アプリケーションで接続プーリングを使用するには、次のことが必要です。

  1. プール・ハンドルの割当て
  2. 接続プールの作成
  3. データベースへのログイン
  4. 接続プーリングでのSGA制限の処理
  5. データベースからのログオフ
  6. 接続プールの破棄
  7. プール・ハンドルの解放
11.4.2.1 プール・ハンドルの割当て

接続プーリングでは、OCIHandleAlloc()によってプール・ハンドルOCI_HTYPE_CPOOLを割り当てる必要があります。

指定された環境ハンドルに対して複数のプールを作成できます。

単一の接続プーリングの割当て例を次に示します。

OCICPool *poolhp;
OCIHandleAlloc((void *) envhp, (void **) &poolhp, OCI_HTYPE_CPOOL, 
                      (size_t) 0, (void **) 0));

関連項目:

OCIHandleAlloc()

11.4.2.2 接続プールの作成

OCIConnectionPoolCreate()関数は、接続プール・ハンドルを初期化します。

次のINパラメータがあります。

  • connMin- プールの作成時にオープンする最小接続数です。

  • connIncr- すべての接続がビジーのときにコールで接続が必要な場合に、オープンする接続の増分数です。この増分は、オープンしている接続の合計数がそのプールでオープン可能な最大接続数より少ない場合にのみ使用します。

  • connMax- プールでオープンできる最大接続数です。プールで最大数の接続がオープンするとすべての接続がビジーになるため、コールに接続が必要な場合は、取得するまで待機することになります。ただし、プールにOCI_ATTR_CONN_NOWAIT属性が設定されている場合は、エラーが戻されます。

  • poolUsernameおよびpoolPassword- ユーザー・セッションがプールの接続間で透過的に移行できます。

  • さらに、OCI_ATTR_CONN_TIMEOUT属性によって、プールの接続のタイムアウトを設定できます。この時間を超えてアイドル状態の接続は定期的に終了し、オープン接続が最適な数に維持されます。この属性が設定されていない場合は、接続がタイムアウトになることはありません。

ノート:

プールの縮小は、ネットワーク・ラウンドトリップがある場合にのみ発生します。操作がない場合、接続は継続されます。

前述の属性はすべて動的に構成できるため、アプリケーションでは現在のロード(オープン接続数とビジー接続数)を読み取り、これらの属性を適切に調整できます。

プール属性(connMaxconnMinconnIncr)を動的に変更する場合は、modeパラメータにOCI_CPOOL_REINITIALIZEを設定したOCIConnectionPoolCreate()をコールする必要があります。

OUTパラメータpoolNamepoolNameLenには、データベース名とその長さの引数のかわりに、後続のOCIServerAttach()OCILogon2()コールで使用する値が格納されます。

アプリケーションで作成できるプールの数に制限はありません。中間層アプリケーションでは、複数のプールを作成して同一サーバーまたは異なるサーバーに接続し、アプリケーション固有のニーズに基づいてロードを均衡化できます。

このコールのコード例を次に示します。

OCIConnectionPoolCreate((OCIEnv *)envhp,
                   (OCIError *)errhp, (OCICPool *)poolhp,
                   &poolName, &poolNameLen,
                   (text *)database,strlen(database),
                   (ub4) connMin, (ub4) connMax, (ub4) connIncr,
                   (text *)poolUsername,strlen(poolUserLen),
                   (text *)poolPassword,strlen(poolPassLen),
                   OCI_DEFAULT));
11.4.2.3 データベースへのログイン

アプリケーションでは、複数のインタフェースのいずれかを使用できます。

アプリケーションでは、次のいずれかのインタフェースを使用して、スレッドごとにデータベースにログインする必要があります。

  • OCILogon2()

    最も単純なインタフェースです。このインタフェースは、単純な接続プール接続が必要で、セッション・ハンドルの属性を変更する必要がない場合に使用します。このインタフェースは、データベースへのプロキシ接続を行う場合にも使用できます。

    次に、OCILogon2()の使用例を示します。

    for (i = 0; i < MAXTHREADS; ++i) 
    { 
       OCILogon2(envhp, errhp, &svchp[i], "hr", 2, "hr", 2, poolName,
                 poolNameLen, OCI_LOGON2_CPOOL));
    
    }
    

    このインタフェースを使用してプロキシ接続を行うには、パスワード・パラメータをNULLに設定してください。

  • OCISessionGet()

    このインタフェースの使用をお薦めします。このインタフェースを使用すると、ユーザーは、証明書、識別名などの外部認証方式も使用できます。OCISessionGet()は、セッションを取得する場合の推奨する統一関数コールです。

    次に、OCISessionGet()の使用例を示します。

    for (i = 0; i < MAXTHREADS; ++i) 
    { 
            OCISessionGet(envhp, errhp, &svchp, authp,
                          (OraText *) poolName,
                          strlen(poolName), NULL, 0, NULL, NULL, NULL,
                          OCI_SESSGET_CPOOL)
     }
    
  • OCIServerAttach()およびOCISessionBegin()

    アプリケーションで、ユーザー・セッション・ハンドルおよびサーバー・ハンドルに特別な属性を設定する必要がある場合は、別のインタフェースを使用できます。このような要件に対して、アプリケーションでは、すべてのハンドル(接続プール・ハンドル、サーバー・ハンドル、セッション・ハンドルおよびサービス・コンテキスト・ハンドル)を割り当てる必要があります。次の順序に従います。

    1. 接続プールを作成します。

      接続プーリングでは、物理接続で仮想サーバー・ハンドルが透過的に多重化されるため、ユーザーがこの作業を行う必要はありません。ユーザーには、セッション用に専用(仮想)接続が確立されているように感じられます。多重化はユーザーに対して透過的に行われるため、仮想サーバー・ハンドル自体に対してセッションを多重化しないでください。ユーザー・レベルで明示的な多重化を必要とするセッション移行およびセッション切替えの概念は、接続プーリングに関しては廃止されたため、使用しないでください。

    2. モードをOCI_CPOOLに設定してOCIServerAttach()をコールします。

      OCIプログラムでは、ユーザーは、接続プールを使用して作成されるセッションごとに一意の仮想サーバー・ハンドルを作成(モードをOCI_CPOOLに設定してOCIServerAttach()をコール)する必要があります。仮想サーバー・ハンドルとセッションは、1対1対応である必要があります。

    3. モードをOCI_DEFAULTに設定してOCISessionBegin()をコールします。

      資格証明は、OCISessionBegin()を使用してOCI_CRED_RDBMSOCI_CRED_EXTまたはOCI_CRED_PROXYに設定できます。資格証明をOCI_CRED_EXTに設定すると、セッション・ハンドルの設定ではユーザー名もパスワードも必要ありません。資格証明をOCI_CRED_PROXYに設定すると、セッション・ハンドルの設定ではユーザー名のみ必要です (1次セッションを明示的に作成したり、OCI_ATTR_MIGSESSIONを設定する必要はありません)。

      仮想サーバー・ハンドルに接続プールを指定する(modeOCI_CPOOLに設定してOCIServerAttach()をコールする)場合は、OCISessionBegin()へのコールでOCI_MIGRATEフラグを設定しないでください。互換性上の理由でのみ、このOCI_MIGRATEフラグを渡すことをお薦めします。接続プールを使用するときに、ユーザーには、セッションに独自の専用(仮想)接続が確立されているように感じられますが、この接続は実際の接続に対して透過的に多重化されているだけのため、OCI_MIGRATEフラグは使用しないでください。

11.4.2.4 接続プーリングでのSGA制限の処理

OCI_CPOOLモード(接続プーリング)では、バックエンド・データベースのセッション・メモリー(UGA)はSGAから取得されます。

SGAで格納できるセッション・メモリー以上のメモリー量をアプリケーションで使用する場合は、バックエンド・データベースでSGAをチューニングしてSGAを拡張する必要性が生じる場合があります。バックエンド・データベースに対するメモリー・チューニングの要件は、インスタンスが専用モードである点を除けば、共有サーバーがバックエンドの場合にLARGE POOLを構成する動作に似ています。

さらにSGA制限が発生する場合は、次の点を考慮してください。

  • セッションごとにオープンする文を少なくして、セッション・メモリーの使用量を減らします。

  • 中間層にセッションをプールすることで、バックエンドのセッション数を減らします。

  • それ以外の場合は、接続プーリングをオフにします。

アプリケーションでは、バックエンドで専用データベース・リンクを接続プーリングとともに使用しないでください。

バックエンドが専用サーバーの場合、専用データベース・リンクを使用するセッションは物理接続に連結され、同じ接続が他のセッションでは使用できなくなるため、効率的な接続プーリングは実現しません。アプリケーションで専用データベース・リンクを使用し、セッション間でバックエンド処理を効率的に共有できない場合は、共有データベース・リンクの使用を検討してください。

関連項目:

11.4.2.5 データベースからのログオフ

適切なコールを選択して、接続プーリング・モードのデータベースからログオフします。

次のコールから、ログイン・コールに対応するものを選択し、それを使用して接続プーリング・モードでデータベースからログオフします。

  • OCILogoff():

    OCILogon2()を使用して接続を行った場合は、OCILogoff()を使用してログオフする必要があります。

  • OCISessionRelease()

    OCISessionGet()をコールして接続を行った場合は、OCISessionRelease()をコールしてログオフする必要があります。

  • OCISessionEnd()およびOCIServerDetach()

    OCIServerAttach()およびOCISessionBegin()をコールして接続を行いセッションを開始した場合は、OCISessionEnd()をコールしてセッションを終了し、OCIServerDetach()をコールして接続を解放する必要があります。

11.4.2.6 接続プールの破棄

OCIConnectionPoolDestroy()により接続プールを破棄します。

OCIConnectionPoolDestroy()を使用して、接続プールを破棄します。

11.4.2.7 プール・ハンドルの解放

プール・ハンドルは、OCIHandleFree()を使用して解放します。

次のコード・フラグメントは、前述した3つの処理を示しています。

 for (i = 0; i < MAXTHREADS; ++i)
  {
    checkerr(errhp, OCILogoff((void *) svchp[i], errhp));
  }
  checkerr(errhp, OCIConnectionPoolDestroy(poolhp, errhp, OCI_DEFAULT));
  checkerr(errhp, OCIHandleFree((void *)poolhp, OCI_HTYPE_CPOOL));

11.4.3 OCI接続プーリングの例

テスト済の完成プログラムでの接続プーリングの例の記載場所を示します。

テスト済の完成プログラムでの接続プーリングの例は、demoディレクトリのcdemocp.cおよびcdemocpproxy.cにあります。

11.5 接続プーリングまたはセッション・プーリングの使用/不使用の判断

これらを使用する場合と使用しない場合を示します。

データベース・セッションを中間層スレッドで再利用できず(つまり、ステートフルのとき)、バックエンドのサーバー・プロセスの数によってはデータベースでスケール上の問題が発生する可能性がある場合は、OCI接続プーリングを使用します。

データベース・セッションを中間層スレッドで再利用でき(つまり、ステートレスのとき)、バックエンドのサーバー・プロセスの数によってはデータベースでスケール上の問題が発生する可能性がある場合は、OCIセッション・プーリングを使用します。

データベース・セッションを中間層スレッドで再利用できず(つまり、ステートフルのとき)、バックエンドのサーバー・プロセスの数がデータベースでスケール上の問題が発生するほど大きくない場合は、プーリングのメカニズムを使用する必要はありません。

ノート:

プールされていないセッションまたは接続があると、すべての中間層ユーザー要求に対してデータベース・セッション/接続を分割し、再作成することになります。これにより、データベース側でスケール上の重大な問題が発生し、要求を履行するまでの待機時間が非常に長くなる可能性があります。そのため、データベース・セッションがステートフルであるかステートレスであるかに基づいて、プーリング手法の1つを中間層アプリケーションに採用することを強くお薦めします。

接続プーリングではプール要素は接続であり、セッション・プーリングではプール要素はセッションとなります。

プールと同様に、スレッドがデータベースでの作業を終了し、リソースが解放されるまでは、プーリングされたリソースはある一定期間、アプリケーション・スレッドによってロックされます。使用期間中は、リソースは他のスレッドでは使用できません。したがって、アプリケーション開発者は、どんな種類のプーリングでも、比較的短期のタスクを効率的に処理されるということを認識する必要があります。ただし、アプリケーションが長時間実行されるトランザクションを実行中の場合、プーリングされたリソースを他のアプリケーションと共有することを長期間拒絶するため、リソースが枯渇する可能性があります。したがって、プーリングは短期のタスクで使用し、プールのサイズは必要なトランザクションの並列性を維持できる大きさに保つ必要があります。

接続プーリングおよびセッション・プーリングに関する次の追加情報に注意してください。

  • OCI接続プーリング

    データベースへの接続はプーリングされます。ユーザーによって、セッションは作成および破棄されます。データベースに対する各コールにより、プールから使用できる適切な接続が取り出されます。

    アプリケーションは、データベースに対する少数の物理的接続で複数のセッションを多重化します。ユーザーは、プール構成をチューニングして必要な並列性を達成できます。

    アプリケーション・セッションの有効期間は、キャッシュされたプール接続の有効期間とは関係がありません。

  • OCIセッション・プーリング

    セッションおよび接続はOCIによってプーリングされます。このアプリケーションはプールからセッションを取得し、セッションをプールに戻して解放します。

11.5.1 セッション作成用の関数

セッションの作成には、様々な機能を使用した、いくつかの方法があります。

OCIでは、セッション作成用の次の関数を提供しています。

  • OCILogin

    OCILogon()は、OCIセッションを取得する最も簡単な方法です。この方法の利点は、OCIサービス・コンテキストを簡単に取得できる点です。欠点は、セッション移行、プロキシ認証、接続プールまたはセッション・プールの使用などの、拡張OCI操作を実行できない点です。

  • OCILogon2()

    OCILogon2()には、セッションを取得するOCILogon()の機能が含まれます。このセッションは、基礎となる新規の接続があるセッション、既存の接続プールから仮想接続によって開始されたセッション、または既存のセッション・プールからのセッションである場合があります。この関数がコールされるときのmodeパラメータ値によって、動作が決まります。

    ユーザーは、OCIによって戻されるサービス・コンテキストの属性(OCI_ATTR_STMTCACHESIZEを除く)を変更できません。

  • OCISessionBegin()

    OCISessionBegin()は、プロキシ認証、接続プールまたはセッション・プールからのセッションの取得、外部資格照明および移行可能セッションなどの、OCIセッションの様々なオプションをすべてサポートします。これは、最低レベルのコールで、すべてのハンドルを明示的に割り当て、すべての属性を設定する必要があります。OCIServerAttach()は、このコールの前にコールする必要があります。

  • OCISessionGet()

    OCISessionGet()は、セッションを取得する方法としてお薦めします。このセッションは、基礎となる新規の接続があるセッション、既存の接続プールから仮想接続によって開始されたセッション、または既存のセッション・プールからのセッションである場合があります。この関数がコールされるときのmodeパラメータ値によって、動作が決まります。この動作はOCILogon2()に似ていますが、これを使用して、プールから特定のセッションを取得するタグを指定することもできます。

11.5.2 様々なタイプのOCIセッションの選択について

使用するセッションのタイプを選択する方法について説明します。

OCIには、次の種類のセッションがあります。

  • 基本的なOCIセッション

    基本的なOCIセッションは、専用OCIサーバー・ハンドル上でユーザー名およびパスワードを使用することで機能します。これは、プール・メカニズムではありません。使用するタイミングの詳細は、「接続プーリングまたはセッション・プーリングの使用/不使用の判断」を参照してください。

    外部資格証明を使用して認証された場合、ユーザー名またはパスワードは必要ありません。

  • セッション・プール・セッション

    セッション・プール・セッションは、セッション・プール・キャッシュから取得します。一部のセッションはタグ付けされる場合があります。これは、ステートレス・セッションです。OCISessionGet()コールおよびOCISessionRelease()コールはそれぞれ、セッション・キャッシュからセッションを取得および解放します。これにより、セッションの作成および破棄からサーバーが保護されます。

    接続プール・セッション、セッション・プーリング・セッション、非プーリング・セッションの比較については、「接続プーリングまたはセッション・プーリングの使用/不使用の判断」を参照してください。

  • 接続プール・セッション

    接続プール・セッションは、OCI接続プールからのOCISessionGet()コールおよびOCISessionBegin()コールを使用して作成されます。これはステートフル・セッションであるため、セッション・キャッシュはありません。各コールによって新規セッションが作成され、ユーザーの責任でこれらのセッションを終了します。

    セッションは、接続プールのサーバー・ハンドル間で自動的に移行できます。各セッションにユーザー名およびパスワードを含めたり、各セッションをプロキシ・セッションにすることができます。接続プール・セッション、セッション・プーリング・セッション、非プーリング・セッションの比較については、「接続プーリングまたはセッション・プーリングの使用/不使用の判断」を参照してください。

  • サーバー・ハンドルを共有するセッション

    少数の物理接続で複数のOCIセッションを多重化できます。これらの複数のセッションに同じサーバー・ハンドルを持たせると、アプリケーションにより、手動で多重化できます。OCI接続プールのAPIを使用して、セッション多重化の詳細はOCIで行うことをお薦めします。

  • プロキシ・セッション

    プロキシ・セッションは、クライアントのパスワードを中間層から保護する必要がある場合に役立ちます。プロキシ・セッションはまた、OCI接続プールまたはOCIセッション・プールの一部に含めることができます。

  • 移行可能なセッション

移行可能なトランザクション・ハンドルを使用している場合、アプリケーションで移行可能なセッションを使用する必要はなく、かわりにOCI接続プーリングを使用します。

関連項目: