ノート:

Oracle Cloud Infrastructure Monitoringサービスを使用して、Oracle Autonomous Databaseからカスタム・メトリックを公開

イントロダクション

Oracle Autonomous Databaseは、世界初の自動稼働データベースを導入して、データを管理する方法に革命をもたらしています。Oracle Autonomous Databaseは、世界中の企業の重要なビジネス・アプリケーションを主要なデータ・ソースとして活かしています。

Oracle Autonomous Databaseは、Oracle Cloud Infrastructure (OCI) Monitoringサービスとの緊密な統合により、数多くの重要なデータベース関連のサービス・メトリックをデフォルトで提供しています。それは、多くの革新的な顧客は、彼らの可観測性を一歩進めたいと考えています。これらの顧客は、Oracle Autonomous Databaseに格納されているアプリケーション・データに関する独自のメトリックを収集、公開および分析する必要があります。これらのカスタム・メトリックと呼びますが、これは、アプリケーションがOCI SDKによって提供される単純なREST APIによってOCIモニタリング・サービスに収集および投稿できるメトリックです。

このチュートリアルでは、いくつかのPL/SQLスクリプトのみを使用し、Oracle Cloudコンソールで数回クリックするだけで、Oracle Autonomous Databaseからカスタム・メトリックを簡単に公開する方法を説明します。

このチュートリアルでは、eコマース・ショッピング・オーダー・データベース・スキーマを使用して、データのメトリックを計算および収集する方法を紹介します。eコマース・アプリケーションが受信した各オーダーについて、各オーダー・ステータス(履行済、受入済、拒否済など)の数を表すメトリックを定期的に計算する方法が表示されます。最後に、これらのカスタム・メトリックをOracle Cloud Monitoring Serviceに公開します。

前提条件

  1. Oracle Cloud無料の層または有料アカウントにアクセスします。
  2. 共有または専用のいずれかのタイプのOracle Autonomous Databaseインスタンス。

    ノート:このチュートリアルでは、共有インフラストラクチャ上で1 OCPUと1TBのストレージのみを使用するOracle Autonomous Transaction ProcessingインスタンスにOracle Autonomous Databaseを使用します。これは、Oracle Cloud無料の層アカウントを使用して作成できます。

  3. PL/SQLに関する基本的な知識。
  4. Oracle Cloudコンソールの精通。
  5. SQL DeveloperやSQL*Plusなどの任意のOracle Databaseクライアントを使用できます。Oracle Autonomous Transaction Processingを初めて使用する場合は、Autonomous Databaseへの接続を参照してください。Oracle Autonomous Transaction Processingについては、Oracle Autonomous Transaction ProcessingのOracle Cloudコンソール・ページから入手できるSQL Developer Webを参照してください。SQL Developer Webを使用する場合、Oracle Walletは不要です。
  6. Oracle Autonomous Transaction ProcessingインスタンスへのADMINユーザー・アクセス。
  7. OCIモニタリング・サービスカスタム・メトリックを公開するためのPostMetricData API動的グループおよびリソース原則などのOracle Cloudの概念をよく理解します。

ソリューション一覧

Oracle Autonomous Databaseインスタンスにデプロイされた単純なPL/SQLスクリプトがあります。これは、OCIモニタリング・サービスでカスタム・メトリックの計算、収集および転記を定期的に実行するようにスケジュールされています。

また、Oracle Autonomous Databaseインスタンスにプライベートまたはパブリック・エンドポイントを含めることもできます。Oracle Autonomous DatabaseとOCI Monitoringサービス間の通信は、超高速で高可用性を備えたOracle Cloudネットワークで行われます。サービス・ゲートウェイを設定する必要はありません。

このチュートリアルでは、Oracle Autonomous DatabaseからOCIモニタリング・サービスにカスタム・メトリックを取得するまで、知っておく必要があるすべてのことを説明します。

概要

  1. Oracle Autonomous Transaction Processingインスタンスの動的グループを作成し、ポリシーを使用してメトリックをOracle Cloud Infrastructure (OCI)モニタリング・サービスにポストすることを認可します。
  2. Oracle Autonomous Transaction Processingインスタンスで必要な権限を持つ新規データベース・ユーザーまたはスキーマを作成するか、必要な権限を持つ既存のデータベース・ユーザーまたはスキーマを更新します。
  3. サンプルのeコマース・アプリケーションのデータを格納するSHOPPING_ORDERという名前の表を作成します(この表に格納されている顧客オーダーのカスタム・メトリックを計算します)。
  4. 顧客オーダーのランダム・データをSHOPPING_ORDER表に移入するためのPL/SQLスクリプトを定義します。
  5. PL/SQLスクリプトを定義して、OCIモニタリング・サービスでカスタム・メトリックを計算、収集および転記します。
  6. ステップ4および5からスクリプトをスケジュールおよび実行します。
  7. Oracle Cloudコンソールで公開されているカスタム・メトリックを確認します。

本番のユース・ケースでは、実際のデータと更新を移入するための独自のアプリケーションがあります。したがって、この場合、ステップ3および4は必要ありません。

ステップ

  1. Oracle Autonomous Transaction Processingインスタンスの動的グループを作成し、ポリシーを使用してメトリックをOracle Cloud Infrastructure (OCI)モニタリング・サービスにポストすることを認可します。

    1. ルールを使用して、Oracle Autonomous Transaction Processingインスタンス(またはインスタンス)に対してadb_dgという名前の動的グループを作成します。

      ALL {resource.type = 'autonomousdatabase', resource.compartment.id = '<compartment OCID for your ADB instance>'}

      または、コンパートメント内のすべてのインスタンスではなく、単一のOracle Autonomous Transaction Processingインスタンスを選択することもできます:

      ALL {resource.type = 'autonomousdatabase', resource.id = '<OCID for your ATP instance>'}

      Oracle Autonomous Databaseの動的グループ

    2. Oracle Cloud Infrastructure Identity and Access Management (IAM)ポリシーを作成して、動的グループadb_dgを認可し、adb_dg_policyという名前のポリシーおよびポリシー・ルールAllow dynamic-group adb_dg to read metrics in compartment <Your Oracle Autonomous Transaction Processing compartment OCID>を使用してOCIモニタリング・サービスにメトリックを投稿します。

      これで、Oracle Autonomous Transaction Processingサービス(動的グループadb_dgの定義でカバーされる)は、同じコンパートメントにメトリックを投稿する権限になりました。

      OCIモニタリング・サービスにメトリックを公開する権限を持つOracle Autonomous Transaction Processingデータベース・ユーザーがいません。はい。Oracle Autonomous Transaction Processingで実行されているPL/SQLでは、メトリックをOCIモニタリング・サービスに投稿できません。手順3cで行います。

  2. Oracle Autonomous Transaction Processingインスタンスで必要な権限を持つ新規データベース・ユーザーまたはスキーマを作成するか、必要な権限を持つ既存のデータベース・ユーザーまたはスキーマを更新します。

    1. Oracle Autonomous Transaction Processingインスタンスに、ECOMMERCE_USERという名前のデータベース・ユーザーまたはスキーマを作成します。これは、すべてのOracle Autonomous Transaction ProcessingインスタンスのADMINユーザーとして作成できます。既存のユーザーを使用する場合は、このステップをスキップできます。

      CREATE USER ECOMMERCE_USER IDENTIFIED BY "Password of your choice for this User";
      

      ノート:ここで、ユーザー(またはスキーマ)をECOMMERCE_USERとして参照し、残りのステップは同じままです(既存のユーザーを使用するか、新しく作成したユーザーを使用するか)。

    2. 必要なOracle Database関連の権限をECOMMERCE_USERに付与します。

      GRANT  CREATE TABLE, ALTER ANY INDEX, CREATE PROCEDURE, CREATE JOB, 
             SELECT ANY TABLE, EXECUTE ANY PROCEDURE, 
             UPDATE ANY TABLE, CREATE SESSION,
             UNLIMITED TABLESPACE, CONNECT, RESOURCE TO ECOMMERCE_USER;
      GRANT  SELECT ON "SYS"."V_$PDBS" TO ECOMMERCE_USER;
      GRANT  EXECUTE ON "C##CLOUD$SERVICE"."DBMS_CLOUD" to ECOMMERCE_USER;
      GRANT  SELECT ON SYS.DBA_JOBS_RUNNING TO ECOMMERCE_USER;
      
    3. Oracle Cloudリソース・プリンシパルのOracle Database資格証明を有効にして、そのアクセスをdb-user ECOMMERCE_USERに付与します。これにより、ステップ1で作成した動的グループadb_dgがデータベース・ユーザーECOMMERCE_USERに接続され、ユーザーがメトリックをOCIモニタリング・サービスにポストする認可が付与されます。詳細は、リソース・プリンシパルを使用したOracle Cloud Infrastructureリソースへのアクセスを参照してください。

      EXEC DBMS_CLOUD_ADMIN.ENABLE_RESOURCE_PRINCIPAL(username => 'ECOMMERCE_USER');
      
    4. (オプション)前のステップで完了した操作を確認します。

      ノート: Oracle Cloudリソース・プリンシパルのOracle Database資格証明を有効にすると、常にOracle Autonomous DatabaseのADMINユーザーによって所有されます。確認方法:

      SELECT OWNER, CREDENTIAL_NAME FROM DBA_CREDENTIALS WHERE CREDENTIAL_NAME = 'OCI$RESOURCE_PRINCIPAL'  AND OWNER =  'ADMIN';
      
      -- To check if any other user, here ECOMMERCE_USER has access DB credential(hence to OCI Resource Principal), you have to check *DBA_TAB_PRIVS* view, as follows.
      SELECT * from DBA_TAB_PRIVS WHERE DBA_TAB_PRIVS.GRANTEE='ECOMMERCE_USER';
      
  3. データベース表のメトリックの計算を示すSHOPPING_ORDERというサンプル・データ表を作成します。

    表スキーマはわかりやすいですが、STATUS列に注意してください。

     DROP TABLE SHOPPING_ORDER;
     CREATE TABLE SHOPPING_ORDER (
         ID                NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY
         PRIMARY KEY,
         CREATED_DATE      TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP,
         DETAILS           VARCHAR2(1000) DEFAULT NULL,
         LAST_UPDATED_DATE TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP,
         STATUS            VARCHAR2(30 CHAR),
         TOTAL_CHARGES     FLOAT DEFAULT 0.0,
         CUSTOMER_ID       NUMBER(19)
     )
         PARTITION BY LIST ( STATUS ) 
         (   PARTITION ACCEPTED VALUES ( 'ACCEPTED' ),
             PARTITION PAYMENT_REJECTED VALUES ( 'PAYMENT_REJECTED' ),
             PARTITION SHIPPED VALUES ( 'SHIPPED' ),
             PARTITION ABORTED VALUES ( 'ABORTED' ),
             PARTITION OUT_FOR_DELIVERY VALUES ( 'OUT_FOR_DELIVERY' ),
             PARTITION ORDER_DROPPED_NO_INVENTORY VALUES ( 'ORDER_DROPPED_NO_INVENTORY' ),
             PARTITION PROCESSED VALUES ( 'PROCESSED' ),
             PARTITION NOT_FULLFILLED VALUES ( 'NOT_FULFILLED' )
         );
     /
    
     -- we move rows from one partition to another, hence we enable row movement for this partioned table
     ALTER TABLE SHOPPING_ORDER ENABLE ROW MOVEMENT;
    

    各ショッピング・オーダーは、その存続期間中に8つのステータス値のいずれかを持つことができます: [ACCEPTED, PAYMENT_REJECTED, SHIPPED, ABORTED, OUT_FOR_DELIVERY, ORDER_DROPPED_NO_INVENTORY, PROCESSED, NOT_FULFILLED]

  4. 次のPL/SQLスクリプトを読み、SHOPPING_ORDER表にデータを移入します。任意のOracle Databaseクライアントで実行します。

    このスクリプトは、最初にTOTAL_ROWS_IN_SHOPPING_ORDER行数をランダムに生成された順序データとともにSHOPPING_ORDER表に追加します。次に、各SHOPPING_ORDER行のSTATUS値をランダムに変更して、データを更新します。

    CREATE OR REPLACE PROCEDURE POPULATE_DATA_FEED IS
        ARR_STATUS_RANDOM_INDEX      INTEGER;
        CUSTOMER_ID_RANDOM           INTEGER;
        TYPE STATUS_ARRAY IS VARRAY(8) OF VARCHAR2(30);
        ARRAY STATUS_ARRAY := STATUS_ARRAY('ACCEPTED', 'PAYMENT_REJECTED',
                                        'SHIPPED', 'ABORTED', 'OUT_FOR_DELIVERY',
                                        'ORDER_DROPPED_NO_INVENTORY', 
                                        'PROCESSED', 'NOT_FULFILLED');
        TOTAL_ROWS_IN_SHOPPING_ORDER INTEGER := 15000;
        TYPE ROWID_NT IS TABLE OF ROWID;
        ROWIDS                       ROWID_NT;
    BEGIN     
        -- starting from scratch just be idempotent and have predictable execution time for this stored procedure
        -- deleting existing rows is optional 
        DELETE SHOPPING_ORDER;
    
        -- insert data
        FOR COUNTER IN 1..TOTAL_ROWS_IN_SHOPPING_ORDER LOOP
            ARR_STATUS_RANDOM_INDEX := TRUNC(DBMS_RANDOM.VALUE(LOW => 1, HIGH => 9));
            CUSTOMER_ID_RANDOM := TRUNC(DBMS_RANDOM.VALUE(LOW => 1, HIGH => 8000));
            INSERT INTO SHOPPING_ORDER (STATUS,CUSTOMER_ID) VALUES (ARRAY(ARR_STATUS_RANDOM_INDEX),CUSTOMER_ID_RANDOM);
            COMMIT;          
        END LOOP;
    
        DBMS_OUTPUT.PUT_LINE('DONE WITH INITIAL DATA LOAD');
    
        -- keep on updating the same data
        FOR COUNTER IN 1..8000 LOOP        
    
                --Get the rowids
            SELECT R BULK COLLECT INTO ROWIDS FROM (SELECT ROWID R FROM SHOPPING_ORDER SAMPLE ( 5 ) ORDER BY DBMS_RANDOM.VALUE) RNDM
            WHERE ROWNUM < TOTAL_ROWS_IN_SHOPPING_ORDER + 1;
    
                --update the table
            ARR_STATUS_RANDOM_INDEX := TRUNC(DBMS_RANDOM.VALUE(LOW => 1, HIGH => 9));
    
            FOR I IN 1..ROWIDS.COUNT LOOP
                UPDATE SHOPPING_ORDER SET STATUS = ARRAY(ARR_STATUS_RANDOM_INDEX) WHERE ROWID = ROWIDS(I);
                COMMIT;
            END LOOP;    
            --sleep in-between if you want to run script for longer duration
            --DBMS_SESSION.SLEEP(ROUND(dbms_random.value(low => 1, high => 2)));          
        END LOOP;
    
        DBMS_OUTPUT.PUT_LINE('DONE WITH POPULATE_DATA_FEED');
        EXECUTE IMMEDIATE 'ANALYZE TABLE SHOPPING_ORDER COMPUTE STATISTICS';
    END;
    /
    
  5. このチュートリアル(カスタム・メトリックを計算してOCIモニタリング・サービスにパブリッシュするスクリプト)の実際について説明します。任意のOracle Datbaseクライアントで実行します。スクリプトは、複数の実行で再生できることを確認するためにべき等です。次に、スクリプト部分を分析します。

    1. SHOPPING_ORDER_METRICS_TABLE表を作成し、これを使用して、計算されたメトリックを収集およびバッファします。

      メトリック計算を実行する問合せに対してデータ表が最適化されていることを確認します。これらの問合せは、データベースに負荷がかかりすぎないようにし、本番のユースケースを妨げます。

      DECLARE
          COUNT_VAR NUMBER := 0;
      BEGIN
          SELECT COUNT(*) INTO COUNT_VAR FROM ALL_TABLES WHERE TABLE_NAME = 'SHOPPING_ORDER_METRICS_TABLE';
      
          IF COUNT_VAR > 0 THEN
              DBMS_OUTPUT.PUT_LINE('TABLE EXISTS ALREADY!');
          ELSE
              -- table doesn't exist
              EXECUTE IMMEDIATE 'CREATE TABLE SHOPPING_ORDER_METRICS_TABLE(
                                  ID                 NUMBER         GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
                                  CREATED_DATE       TIMESTAMP(6)   DEFAULT CURRENT_TIMESTAMP,
                                  STATUS             VARCHAR2(30 CHAR),
                                  COUNT              NUMBER)';
          END IF;
      
      END;
      /
      
    2. メトリックを計算するストアド・プロシージャを作成します: ステータス値別のオーダー数のカウント、このメトリック・コレクションのインスタンス

      次に、ストアド・プロシージャは、前のステップで作成したバッファ表SHOPPING_ORDER_METRICS_TABLEの計算済メトリックをバッファします。OCIモニタリング・サービスへの公開時に一時的な中断が発生した場合は、今後メトリックの再投稿を試行できるバッファ。

      CREATE OR REPLACE PROCEDURE COMPUTE_AND_BUFFER_METRICS IS
      BEGIN    
          -- compute simple metric for getting count order by order-status 
          -- and store in buffer table SHOPPING_ORDER_METRICS_TABLE
          INSERT INTO SHOPPING_ORDER_METRICS_TABLE (STATUS, COUNT, CREATED_DATE) 
          SELECT STATUS, COUNT(*), SYSTIMESTAMP AT TIME ZONE 'UTC' FROM SHOPPING_ORDER SO GROUP BY SO.STATUS;
      
          -- we buffer at most 1000 metric points, please configure as per your needs
          DELETE FROM SHOPPING_ORDER_METRICS_TABLE SOMT WHERE SOMT.ID NOT IN
              (SELECT ID FROM SHOPPING_ORDER_METRICS_TABLE ORDER BY CREATED_DATE FETCH FIRST 1000 ROWS ONLY);
      
          COMMIT;    
          DBMS_OUTPUT.PUT_LINE('compute and buffering done @ ' || TO_CHAR(SYSTIMESTAMP));
      END;
      /
      

      バッファ・テーブルのサイズを制限するには、サイズが1,000行を超える場合はトリムします。

    3. バッファ・メトリックをSHOPPING_ORDER_METRICS_TABLEからPostMetricsData APIが要求で想定するJSONオブジェクトに変換するPL/SQLファンクションPREPARE_JSON_OBJECT_FROM_METRIC_ROWSを使用します。

      ノート:

      • この関数は、最新のメトリック・データ・ポイントのBATCH_SIZE_FOR_EACH_POST数をSHOPPING_ORDER_METRICS_TABLEからOCI_METADATA_JSON_OBJ JSON_OBJECT_Tに変換します。
      • OCI_METADATA_JSON_OBJは、PL/SQLの組込みJSONデータ型JSON_OBJECT_Tの変数です。PostMetricsData APIのリクエスト本文であるPostMetricDataDetailsと同じJSON構造を持つOCI_METADATA_JSON_OBJを構築しました。
       CREATE OR REPLACE FUNCTION GET_METRIC_DATA_DETAILS_JSON_OBJ (
           IN_ORDER_STATUS         IN VARCHAR2,
           IN_METRIC_CMPT_ID       IN VARCHAR2,
           IN_ADB_NAME             IN VARCHAR2,
           IN_METRIC_VALUE         IN NUMBER,
           IN_TS_METRIC_COLLECTION IN VARCHAR2
       ) RETURN JSON_OBJECT_T IS
           METRIC_DATA_DETAILS JSON_OBJECT_T;
           MDD_METADATA        JSON_OBJECT_T;
           MDD_DIMENSIONS      JSON_OBJECT_T;
           ARR_MDD_DATAPOINT   JSON_ARRAY_T;
           MDD_DATAPOINT       JSON_OBJECT_T;
       BEGIN
           MDD_METADATA := JSON_OBJECT_T();
           MDD_METADATA.PUT('unit', 'row_count'); -- metric unit is arbitrary, as per choice of developer
      
           MDD_DIMENSIONS := JSON_OBJECT_T();
           MDD_DIMENSIONS.PUT('dbname', IN_ADB_NAME);
           MDD_DIMENSIONS.PUT('schema_name', SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA'));
           MDD_DIMENSIONS.PUT('table_name', 'SHOPPING_ORDER');
           MDD_DIMENSIONS.PUT('status_enum', IN_ORDER_STATUS);
           MDD_DATAPOINT := JSON_OBJECT_T();
           MDD_DATAPOINT.PUT('timestamp', IN_TS_METRIC_COLLECTION); --timestamp value RFC3339 compliant
           MDD_DATAPOINT.PUT('value', IN_METRIC_VALUE);
           MDD_DATAPOINT.PUT('count', 1);
           ARR_MDD_DATAPOINT := JSON_ARRAY_T();
           ARR_MDD_DATAPOINT.APPEND(MDD_DATAPOINT);
           METRIC_DATA_DETAILS := JSON_OBJECT_T();
           METRIC_DATA_DETAILS.PUT('datapoints', ARR_MDD_DATAPOINT);
           METRIC_DATA_DETAILS.PUT('metadata', MDD_METADATA);
           METRIC_DATA_DETAILS.PUT('dimensions', MDD_DIMENSIONS);
      
           -- namespace, resourceGroup and name for the custom metric are arbitrary values, as per choice of developer
           METRIC_DATA_DETAILS.PUT('namespace', 'custom_metrics_from_adb');
           METRIC_DATA_DETAILS.PUT('resourceGroup', 'ecommerece_adb');
           METRIC_DATA_DETAILS.PUT('name', 'customer_orders_submitted');
      
           -- since compartment OCID is fetched using ADB metadata, our custom metrics will land up in same compartment as our ADB
           METRIC_DATA_DETAILS.PUT('compartmentId', IN_METRIC_CMPT_ID);
           RETURN METRIC_DATA_DETAILS;
       END;
       /
      
       CREATE OR REPLACE FUNCTION PREPARE_JSON_OBJECT_FROM_METRIC_ROWS (
           OCI_METADATA_JSON_OBJ JSON_OBJECT_T, BATCH_SIZE_FOR_EACH_POST NUMBER
       ) RETURN JSON_OBJECT_T IS
           OCI_POST_METRICS_BODY_JSON_OBJ JSON_OBJECT_T;
           ARR_METRIC_DATA                JSON_ARRAY_T;
           METRIC_DATA_DETAILS            JSON_OBJECT_T;
       BEGIN
           -- prepare JSON body for postmetrics api..
           -- for details please refer https://docs.oracle.com/en-us/iaas/api/#/en/monitoring/20180401/datatypes/PostMetricDataDetails
           ARR_METRIC_DATA := JSON_ARRAY_T();
      
           -- PostMetrics api has soft limit of 50 unique metric stream per call, hence we cap it at 50. 
           -- For Production usecase where every metric data point is important, we can use chunking
           FOR METRIC_ROW IN (SELECT * FROM SHOPPING_ORDER_METRICS_TABLE 
                               ORDER BY CREATED_DATE DESC FETCH FIRST BATCH_SIZE_FOR_EACH_POST ROWS ONLY) LOOP
      
               --DBMS_OUTPUT.PUT_LINE('inside for loop ' || METRIC_ROW.STATUS );
      
               METRIC_DATA_DETAILS := GET_METRIC_DATA_DETAILS_JSON_OBJ(
                                   METRIC_ROW.STATUS,
                                   OCI_METADATA_JSON_OBJ.GET_STRING('COMPARTMENT_OCID'), 
                                   OCI_METADATA_JSON_OBJ.GET_STRING('DATABASE_NAME'), 
                                   METRIC_ROW.COUNT, 
                                   TO_CHAR(METRIC_ROW.CREATED_DATE, 'yyyy-mm-dd"T"hh24:mi:ss.ff3"Z"'));
               --DBMS_OUTPUT.PUT_LINE('METRIC_DATA_DETAILS '|| METRIC_DATA_DETAILS.to_clob);
               ARR_METRIC_DATA.APPEND(METRIC_DATA_DETAILS);
      
           END LOOP;
           DBMS_OUTPUT.PUT_LINE('done with for loop ');
           OCI_POST_METRICS_BODY_JSON_OBJ := JSON_OBJECT_T();
           OCI_POST_METRICS_BODY_JSON_OBJ.PUT('metricData', ARR_METRIC_DATA);
      
           RETURN OCI_POST_METRICS_BODY_JSON_OBJ;
       END;
       /
      
    4. PL/SQLコードを使用して、PostMetricsData APIを使用してこれらの変換済メトリックをOCIモニタリング・サービスに公開します。

      ノート:これは、PL/SQLファンクションPOST_METRICS_DATA_TO_OCIおよびストアド・プロシージャPUBLISH_BUFFERED_METRICS_TO_OCIで実現します。

      
       CREATE OR REPLACE FUNCTION POST_METRICS_DATA_TO_OCI(OCI_POST_METRICS_BODY_JSON_OBJ JSON_OBJECT_T, ADB_REGION VARCHAR2) 
       RETURN NUMBER 
       IS
           RETRY_COUNT                    INTEGER := 0;
           MAX_RETRIES                    INTEGER := 3;
           RESP                           DBMS_CLOUD_TYPES.RESP;
           EXCEPTION_POSTING_METRICS      EXCEPTION;
           SLEEP_IN_SECONDS               INTEGER := 5;
       BEGIN
           FOR RETRY_COUNT in 1..MAX_RETRIES  LOOP
                   -- invoking REST endpoint for OCI Monitoring API
                   -- for details please refer https://docs.oracle.com/en-us/iaas/api/#/en/monitoring/20180401/MetricData/PostMetricData
               RESP := DBMS_CLOUD.SEND_REQUEST(CREDENTIAL_NAME => 'OCI$RESOURCE_PRINCIPAL', 
                                               URI => 'https://telemetry-ingestion.'|| ADB_REGION|| '.oraclecloud.com/20180401/metrics', 
                                               METHOD =>DBMS_CLOUD.METHOD_POST, 
                                               BODY => UTL_RAW.CAST_TO_RAW(OCI_POST_METRICS_BODY_JSON_OBJ.TO_STRING));
      
               IF DBMS_CLOUD.GET_RESPONSE_STATUS_CODE(RESP) = 200 THEN    -- when it is 200 from OCI Metrics API, all good
                   DBMS_OUTPUT.PUT_LINE('POSTED METRICS SUCCESSFULLY TO OCI MONIOTRING');
                   RETURN 200;
               ELSIF DBMS_CLOUD.GET_RESPONSE_STATUS_CODE(RESP) = 429 THEN -- 429 is caused by throttling
                   IF RETRY_COUNT < MAX_RETRIES THEN
                       -- increase sleep time for each retry, doing exponential backoff
                       DBMS_SESSION.SLEEP(POWER(SLEEP_IN_SECONDS, RETRY_COUNT+1));
                       DBMS_OUTPUT.PUT_LINE('RETRYING THE POSTMETRICS API CALL');
                   ELSE
                       DBMS_OUTPUT.PUT_LINE('ABANDONING POSTMETRICS CALLS, AFTER 3 RETRIES, CAUSED BY THROTTLING, WILL BERETRIED IN NEXT SCHEDULED RUN');
                       RETURN 429;
                   END IF;
               ELSE -- for any other http status code....1. log error, 2. raise exception and then quit posting metrics, as it is most probably a persistent error 
                       DBMS_OUTPUT.PUT_LINE('IRRECOVERABLE ERROR HAPPENED WHEN POSTING METRICS TO OCI MONITORING, PLEASE SEE CONSOLE FOR ERRORS');
                       -- Response Body in TEXT format
                       DBMS_OUTPUT.put_line('Body: ' || '------------' || CHR(10) || DBMS_CLOUD.get_response_text(resp) || CHR(10));
                       -- Response Headers in JSON format
                       DBMS_OUTPUT.put_line('Headers: ' || CHR(10) || '------------' || CHR(10) || DBMS_CLOUD.get_response_headers(resp).to_clob || CHR(10));
                       -- Response Status Code
                       DBMS_OUTPUT.put_line('Status Code: ' || CHR(10) || '------------' || CHR(10) || DBMS_CLOUD.get_response_status_code(resp));
                       RETURN 500;
               END IF;
      
           END LOOP;
       END;
       /
      
       CREATE OR REPLACE PROCEDURE PUBLISH_BUFFERED_METRICS_TO_OCI IS
           OCI_METADATA_JSON_RESULT       VARCHAR2(1000);
           OCI_METADATA_JSON_OBJ          JSON_OBJECT_T;
           ADB_REGION                     VARCHAR2(25);
           OCI_POST_METRICS_BODY_JSON_OBJ JSON_OBJECT_T;
           TYPE ID_ARRAY IS VARRAY(50) OF NUMBER;
           ARRAY                          ID_ARRAY;
           TOTAL_METRICS_STREAM_CNT       NUMBER;
           HTTP_CODE                      NUMBER;
           BATCH_SIZE_FOR_EACH_POST       NUMBER:=8; -- not more than 50! as per PostMetricsData API docs
       BEGIN
           -- get the meta-data for this ADB Instance like its OCI compartmentId, region and DBName etc; as JSON in oci_metadata_json_result
           SELECT CLOUD_IDENTITY INTO OCI_METADATA_JSON_RESULT FROM V$PDBS; 
           -- dbms_output.put_line(oci_metadata_json_result);
      
           -- convert the JSON string into PLSQL JSON native JSON datatype json_object_t variable named oci_metadata_json_result
           OCI_METADATA_JSON_OBJ := JSON_OBJECT_T.PARSE(OCI_METADATA_JSON_RESULT);
      
      
           WHILE(TRUE) LOOP
               SELECT COUNT(*) INTO TOTAL_METRICS_STREAM_CNT FROM SHOPPING_ORDER_METRICS_TABLE;
               IF(TOTAL_METRICS_STREAM_CNT < BATCH_SIZE_FOR_EACH_POST) THEN
                   DBMS_OUTPUT.PUT_LINE('Only ' || TOTAL_METRICS_STREAM_CNT || ' metrics datapoints buffered(less than batch size' || BATCH_SIZE_FOR_EACH_POST || '), hence waiting for buffer to fill up');
                   EXIT;
               END IF;   
      
               OCI_POST_METRICS_BODY_JSON_OBJ := PREPARE_JSON_OBJECT_FROM_METRIC_ROWS(OCI_METADATA_JSON_OBJ, BATCH_SIZE_FOR_EACH_POST);
               ADB_REGION := OCI_METADATA_JSON_OBJ.GET_STRING('REGION');
      
               HTTP_CODE := POST_METRICS_DATA_TO_OCI(OCI_POST_METRICS_BODY_JSON_OBJ, ADB_REGION);
      
               IF(HTTP_CODE = 200) THEN
                   DBMS_OUTPUT.PUT_LINE('Deleting the published metrics');
                   DELETE FROM SHOPPING_ORDER_METRICS_TABLE WHERE ID IN 
                                       (SELECT ID FROM SHOPPING_ORDER_METRICS_TABLE 
                                       ORDER BY CREATED_DATE DESC FETCH FIRST 50 ROWS ONLY);
               END IF;    
      
               COMMIT;    
      
               -- PostMetricData API has TPS rate limit of 50, just for safety  
               -- Hence sleep for atleast seconds => (1/50) to avoid throttling
               -- DBMS_SESSION.SLEEP(seconds => (1/50));                                  
           END LOOP;
       END;
       /
      

      関数POST_METRICS_DATA_TO_OCIは、PostMetricsData APIを起動します。すべてのOracle Cloud APIと同様に、呼び出すには、適切なOCI IAM認可が必要です。次のように、名前付きパラメータcredential_name => 'OCI$RESOURCE_PRINCIPAL'を使用して渡します。

      データベース資格証明OCI$RESOURCE_PRINCIPALは、ステップ2で作成した動的グループadb_dgにリンクされ、ステップ3のECOMMERCE_USERユーザーはすでにアクセスできます。

      そのため、信頼チェーンによって、ECOMMERCE_USERによって実行されるこのPL/SQLスクリプトには、カスタム・メトリックをOCIモニタリング・サービスにポストする認可があります。

      RESP := DBMS_CLOUD.SEND_REQUEST(CREDENTIAL_NAME => 'OCI$RESOURCE_PRINCIPAL', 
                                              URI => 'https://telemetry-ingestion.'|| ADB_REGION|| '.oraclecloud.com/20180401/metrics', 
                                              METHOD =>DBMS_CLOUD.METHOD_POST, 
                                              BODY => UTL_RAW.CAST_TO_RAW(OCI_POST_METRICS_BODY_JSON_OBJ.TO_STRING));
      

      dbms_cloud.send_requestは、すべてのOracle Autonomous Databaseとともに事前インストールされた任意のレスト・エンドポイントを起動する組込みのPL/SQLストアド・プロシージャです。ここでは、これを使用してOCIモニタリング・サービスのREST APIを起動します。

      ストアド・プロシージャPUBLISH_BUFFERED_METRICS_TO_OCIは、これまでに説明したすべての関数とプロシージャを使用して、すべてのバッファ・メトリックをOCIモニタリング・サービスにポストします。実行するには、PostMetricsData APIの起動ごとに、メトリック・データ・ポイントのサイズBATCH_SIZE_FOR_EACH_POSTのバッチを作成します。

  6. ステップ4および5からスクリプトをスケジュールおよび実行します。ステップ4および5では、ストアド・プロシージャおよびストアド・ファンクションをOracle Databaseに定義しましたが、まだ実行していません。

    1. ステップ4からスクリプトを実行して、SHOPPING_ORDER表にデータを移入します。このスクリプトは、1 OCPUおよび1TBのストレージでOracle Autonomouse Transaction Processingインスタンスで約15分間実行されます。

      -- we schedule the data feed to run immediately, asynchronously and only once!
      BEGIN
           DBMS_SCHEDULER.CREATE_JOB(
                                   JOB_NAME => 'POPULATE_DATA_FEED_JOB', 
                                   JOB_TYPE => 'STORED_PROCEDURE', 
                                   JOB_ACTION => 'POPULATE_DATA_FEED',
                                   ENABLED => TRUE, 
                                   AUTO_DROP => TRUE, -- drop job after 1 run.
                                   COMMENTS => 'ONE-TIME JOB');
       END;
       /
      
       -- just for our information
       SELECT STATUS,count(*) FROM SHOPPING_ORDER GROUP BY STATUS; 
      
    2. 残っているのは、ステップ5:計算および公開からOCIモニタリング・サービスへのPL/SQLスクリプトの定期的な実行のみです。

      次のように、PL/SQL組込みストアド・プロシージャDBMS_SCHEDULER.CREATE_JOBを使用して実行します。

      20分(1,200秒)の間続くOracle Database SCHEDULED_JOBが作成されます。カスタム・メトリックが計算され、毎分公開されます。

      本番ユース・ケースの場合は、必要に応じて構成します。

      BEGIN
          DBMS_SCHEDULER.CREATE_JOB(
                                  JOB_NAME => 'POST_METRICS_TO_OCI_JOB', 
                                  JOB_TYPE   => 'PLSQL_BLOCK',
                                  JOB_ACTION => 'BEGIN 
                                                  ECOMMERCE_USER.COMPUTE_AND_BUFFER_METRICS(); 
                                                  ECOMMERCE_USER.PUBLISH_BUFFERED_METRICS_TO_OCI();
                                                 END;',
                                  START_DATE => SYSTIMESTAMP,                        -- start the first run immediately
                                  REPEAT_INTERVAL => 'FREQ=SECONDLY;INTERVAL=60',    -- run this PLSQL_BLOCK every 60th second 
                                  END_DATE => SYSTIMESTAMP + INTERVAL '1200' SECOND, -- this schedule is only active
                                  AUTO_DROP => TRUE,                                 -- delete the schedule after 1200 seconds, effectively after its last run
                                  ENABLED => TRUE,                                   -- enable this schedule as soon as it is created
                                  COMMENTS => 'JOB TO POST DB METRICS TO OCI MONITORING SERVICE, RUNS EVERY 10TH SECOND');
      END;
      /   
      
  7. Oracle Cloudコンソールで公開されているカスタム・メトリックを確認します。

    1. ナビゲーション・メニューから、「メトリック・エクスプローラ」をクリックします。

      Oracle Cloudコンソールのメトリック・エクスプローラに移動

    2. 「メトリック・エクスプローラ」で、ネームスペースをcustom_metrics_from_adb、resourceGroupをecommerece_adb、メトリック名をcustomer_orders_submittedとして選択し、カスタム・メトリックに設定します。

      カスタム・メトリックに設定したすべてのメタデータおよびディメンションを使用できます。

      MQL問合せを作成して、ニーズおよびユース・ケースに従ってこれらのメトリックを分析できます。次に、メトリック・ストリームにOracle Cloudアラームを設定して、運用チームにアラートを通知できます。

      これにより、選択したOracle Autonomous Databaseメトリックの可観測性ループが自動化されます。

      公開したカスタム・メトリックの確認

まとめ

OCI SDK for PL/SQLを使用して、単純なPL/SQLスクリプトを使用してOracle Autonomous DatabaseからOracle Cloud Infrastructure (OCI) Monitoringサービスにカスタム・メトリックを生成する方法を学習しました。Oracle Databaseは多くのビジネス・ワークフローにとって「真のソース」であるため、これは非常に強力な機能です。

カスタム・メトリックは、ネイティブ・メトリックに匹敵するOCI Monitoringサービスの第一級市民です。それらを同じ強力なメトリック問合せ言語で分析し、それらに対してアラームを設定して、関心や問題が発生した場合に常に通知できます。

これにより、すべてのメトリックの最終的な「単一ペイン・オブ・グラス」ビュー(アプリケーションやデータベースで生成されたOCIサービスまたはカスタム・メトリックの生成)が提供されます。

謝辞

その他の学習リソース

docs.oracle.com/learnの他のラボを調べるか、Oracle Learning YouTubeチャネルでさらに無料の学習コンテンツにアクセスします。さらに、education.oracle.com/learning-explorerにアクセスしてOracle Learning Explorerにします。

製品ドキュメントは、Oracleヘルプ・センターを参照してください。