備註:

使用 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 監督服務度量。

本教學課程示範如何使用 Oracle Cloud 主控台中只有少數 PL/SQL 命令檔,輕鬆發布 Oracle Autonomous Database 的客製化度量。

本教學課程使用電子商務購物單資料庫綱要作為範例,示範如何運算和收集資料的度量。您會看到如何定期計算代表電子商務應用程式收到之每個訂單狀態 (已履行、已接受、已拒絕等等) 的單位標準。最後,您將將這些客製化的度量發布到 Oracle Cloud Monitoring Service。

必要條件

  1. 存取 Oracle Cloud 免費層或付費帳戶。
  2. 任何類型的 Oracle Autonomous Database 執行處理,不論是共用或專用。

    注意:在本教學課程中,您使用的 Oracle Autonomous Database 就是 Oracle Autonomous Transaction Processing 執行處理,共用基礎架構上只需要 1 個 OCPU 和 1 TB 的儲存。您可以使用 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,請參閱 SQL Developer Web,可從 Oracle Cloud 主控台頁面取得 Oracle Autonomous Transaction Processing。使用 SQL Developer Web 時不需要 Oracle Wallet。
  6. ADMIN 使用者存取您的 Oracle Autonomous Transaction Processing 執行處理。
  7. 基本瞭解 Oracle Cloud 概念,例如 OCI 監督服務PostMetricData API 用於發布自訂度量以及動態群組和資源原則

解決方案瀏覽

我們部署在 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. 建立一個名為 SHOPPING_ORDER 的表格,以儲存我們的範例電子商務應用程式資料 (您可以在表格中儲存的客戶訂單上計算自訂度量)。
  4. 定義 PL/SQL 命令檔以在 SHOPPING_ORDER 表格中植入客戶訂單的隨機資料。
  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,將度量張貼至 OCI 監督服務,其中原則名稱為 adb_dg_policy 且原則規則為 Allow dynamic-group adb_dg to read metrics in compartment <Your Oracle Autonomous Transaction Processing compartment OCID>

      現在,您的 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 使用者 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. 使用 PL/SQL 函數 PREPARE_JSON_OBJECT_FROM_METRIC_ROWS,將緩衝度量從 SHOPPING_ORDER_METRICS_TABLE 轉換成 PostMetricsData API 要求中預期 JSON 物件。

      備註:

      • 此函數會將最近度量資料點的 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 的變數。我們建構的 OCI_METADATA_JSON_OBJ,其 JSON 結構與 PostMetricDataDetails (PostMetricsData API 的要求主體) 相同。
       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 程式碼,使用這些轉換的測量結果發布到 OCI 監督服務,以及 PostMetricsData API。

      注意: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 使用者已有存取權。

      Hence by chain of trust, this PL/SQL script executed by ECOMMERCE_USER has authorization to post the custom metrics to the OCI Monitoring service.

      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 是內建的 PL/SQL 預存程序,可呼叫任何其餘端點,並為每個 Oracle Autonomous Database 預先安裝。此處用它來呼叫 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 和 1 TB 儲存的 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 Alarms,以警示您的作業團隊。

      這可將您所選 Oracle Autonomous Database 度量的觀察性迴圈自動化。

      探索您已發布的自訂度量

結論

學員將如何使用 OCI SDK for PL/SQL,藉由簡單的 PL/SQL 命令檔發出從 Oracle Autonomous Database 到 Oracle Cloud Infrastructure (OCI) 監督服務的自訂度量。Oracle Database 是許多業務工作流程的「事實來源」,因此這是一項非常強大的功能。

自訂度量是 OCI 監督服務的一流公民,與原生度量相同。您可以使用相同的功能強大的測量結果查詢語言來分析它們,並在它們上設定警示,以便在發生任何感興趣或發生問題時通知您。

這能為您提供所有測量結果的最終「單一窗格」檢視,包括產生 OCI 服務,或是由您應用程式和資料庫產生的自訂測量結果。

致謝

其他學習資源

探索 docs.oracle.com/learn 上的其他實驗室,或是存取更多免費學習內容至 Oracle Learning YouTube 通道。此外,瀏覽 education.oracle.com/learning-explorer 以成為 Oracle Learning Explorer。

如需產品文件,請瀏覽 Oracle Help Center