참고:

Oracle Cloud Infrastructure Monitoring 서비스를 사용하여 Oracle Autonomous Database에서 맞춤형 측정 지표 게시

소개

Oracle Autonomous Database는 세계 최초의 "자율 구동" 데이터베이스가 도입되어 데이터 관리 방식을 혁신하고 있습니다. Oracle Autonomous Database는 전 세계에서 주요 데이터 소스로 기업의 주요 비즈니스 애플리케이션을 지원하고 있습니다.

Oracle Autonomous Database provides many important database related service metrics out of the box, thanks to its deep integration with Oracle Cloud Infrastructure (OCI) Monitoring service. That being said, many of our innovative customers want to take their observability journey a step further. These customers want to collect, publish, and analyze their own metrics about the application data stored in the Oracle Autonomous Database. We call these custom metrics and they are the metrics that applications can collect and post to OCI Monitoring service by a simple REST API provided by the OCI SDK.

이 사용지침서에서는 몇 개의 PL/SQL 스크립트만 사용하여 Oracle Autonomous Database에서 커스터마이징 측정지표를 쉽게 게시하고 Oracle Cloud 콘솔에서 클릭 몇 번으로 간단하게 게시할 수 있는 방법을 보여줍니다.

이 사용지침서에서는 전자상거래 쇼핑 주문 데이터베이스 스키마를 예로 사용하여 데이터에 대한 측정지표를 계산하고 수집하는 방법을 보여 줍니다. 전자상거래 애플리케이션이 수신하는 각 주문에 대해 각 주문 상태(이행, 수락됨, 거부됨 등)의 수를 나타내는 측정 단위를 주기적으로 계산할 수 있는 방법을 알아봅니다. 마지막으로, 이러한 커스터마이징 측정지표를 Oracle Cloud Monitoring Service에 게시합니다.

필요 조건

  1. Oracle Cloud 무료 계층 또는 유료 계정에 접근합니다.
  2. 공유 또는 전용의 Oracle Autonomous Database 인스턴스 유형

    주: 이 사용지침서에서는 공유 인프라에 OCPU가 1개, 스토리지 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. ADMIN 사용자가 Oracle Autonomous Transaction Processing 인스턴스에 액세스할 수 있습니다.
  7. OCI Monitoring service, 커스텀 측정지표를 게시하기 위한 PostMetricData API동적 그룹 및 리소스 원칙과 같은 Oracle Cloud 개념에 대한 기본적인 이해

솔루션 개요

오라클은 Oracle Autonomous Database 인스턴스에 배치된 간단한 PL/SQL 스크립트를 사용합니다. 이 스크립트는 OCI 모니터링 서비스에서 커스터마이징 측정 지표를 계산, 수집 및 게시하기 위해 주기적으로 실행되도록 예약됩니다.

또한 Oracle Autonomous Database 인스턴스는 전용 또는 공용 끝점을 포함할 수 있습니다. Oracle Autonomous Database와 OCI Monitoring 서비스 간의 의사 소통은 매우 빠르고 가용성이 높은 Oracle Cloud 네트워크에서 발생합니다. 서비스 게이트웨이를 설정할 필요가 없습니다.

이 사용지침서에서는 Oracle Autonomous Database에서 OCI Monitoring 서비스에 커스터마이징 측정지표를 가져올 때까지 알아야 할 모든 내용에 대해 다룹니다.

개요

  1. Oracle Autonomous Transaction Processing 인스턴스에 대한 동적 그룹을 생성하고 정책을 사용하여 OCI(Oracle Cloud Infrastructure) 모니터링 서비스에 측정항목을 게시하도록 권한을 부여합니다.
  2. Oracle Autonomous Transaction Processing 인스턴스에 필요한 권한으로 새 데이터베이스 사용자 또는 스키마를 생성하거나, 필요한 권한으로 기존 데이터베이스 사용자 또는 스키마를 업데이트합니다.
  3. 예시 전자상거래 애플리케이션에 대한 데이터를 저장할 SHOPPING_ORDER이라는 테이블을 생성합니다(이 테이블에 저장된 고객 주문에 대한 커스터마이징 측정지표를 계산합니다).
  4. SHOPPING_ORDER 테이블에서 고객 주문에 대한 임의 데이터를 채우는 PL/SQL 스크립트를 정의합니다.
  5. OCI 모니터링 서비스에서 사용자정의 측정항목을 계산, 수집 및 버퍼링하고 게시하도록 PL/SQL 스크립트를 정의합니다.
  6. 4단계와 5단계에서 스크립트를 스케줄링하고 실행합니다.
  7. Oracle Cloud 콘솔에서 게시된 사용자정의 측정항목을 살펴봅니다.

운용 활용 사례에서 실제 데이터와 업데이트를 채울 수 있는 자체 애플리케이션이 있습니다. 따라서 이 경우 3단계와 4단계는 필요하지 않습니다.

단계

  1. Oracle Autonomous Transaction Processing 인스턴스에 대한 동적 그룹을 생성하고 정책을 사용하여 OCI(Oracle Cloud Infrastructure) 모니터링 서비스에 측정항목을 게시하도록 권한을 부여합니다.

    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_dgadb_dg_policy라는 정책 및 정책 규칙 Allow dynamic-group adb_dg to read metrics in compartment <Your Oracle Autonomous Transaction Processing compartment OCID>을 사용하여 OCI 모니터링 서비스에 측정항목을 게시하도록 부여합니다.

      이제 동적 그룹 adb_dg의 정의에 따라 Oracle Autonomous Transaction Processing 서비스가 동일한 구획에 측정항목을 게시할 수 있는 권한을 부여했습니다.

      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 인스턴스에 대한 관리자 사용자로 생성할 수 있습니다. 기존 사용자를 사용하도록 선택한 경우 이 단계를 건너뛸 수 있습니다.

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

      주: 이제 사용자(또는 스키마)를 ECOMMERCE_USER으로, 나머지 단계는 기존 사용자나 새로 생성된 사용자를 사용하든 동일하게 유지됩니다.

    2. ECOMMERCE_USER에 필요한 Oracle Database 관련 권한을 부여합니다.

      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 Resource Principal에 대한 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. 데이터베이스 테이블의 metrics 계산을 소개하는 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 클라이언트에서 실행합니다. 스크립트는 여러 실행에서 재생할 수 있도록 idempotent입니다. 이제 스크립트 조각을 분석합니다.

    1. SHOPPING_ORDER_METRICS_TABLE 테이블을 생성하고 이 테이블을 사용하여 계산된 metrics를 수집하고 버퍼링합니다.

      데이터 테이블이 Metric 계산을 실행하는 Query에 맞게 최적화되었는지 확인합니다. 이러한{\f2732 query}를 데이터베이스에 너무 많이 로드하여 운용 사용 사례를 방해하지 않도록 해야 합니다{\f2732 .}

      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에 계산된 metrics를 버퍼링합니다. 측정항목을 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을 사용합니다.

      참고:

      • 이 함수는 SHOPPING_ORDER_METRICS_TABLE에서 OCI_METADATA_JSON_OBJ JSON_OBJECT_T로 가장 최근 측정항목 데이터 포인트의 BATCH_SIZE_FOR_EACH_POST 번호를 변환합니다.
      • 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를 사용하여 이러한 변환된 metrics를 OCI Monitoring 서비스에 게시합니다.

      주: POST_METRICS_DATA_TO_OCI라는 PL/SQL 함수와 내장 프로시저 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와 마찬가지로 해당 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는 지금까지 설명한 모든 함수 및 프로시저를 사용하여 버퍼된 모든 metrics를 OCI Monitoring 서비스에 게시합니다. 수행자가 되려면 각 PostMetricsData API 호출에 대해 측정항목 데이터 포인트의 BATCH_SIZE_FOR_EACH_POST 크기의 일괄 처리를 생성합니다.

  6. 4단계와 5단계에서 스크립트를 스케줄링하고 실행합니다. 4단계와 5단계에서 Oracle Database에 내장 프로시저 및 함수를 정의했지만 아직 실행하지 않았습니다.

    1. 4단계의 스크립트를 실행하여 SHOPPING_ORDER 테이블의 데이터를 채웁니다. OCPU가 1개이고 스토리지가 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를 생성합니다. 커스터마이징 측정지표는 계산하여 1분마다 게시합니다.

      프로덕션 사용 사례의 경우 필요에 따라 구성합니다.

      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 Console에서 게시된 커스터마이징 측정지표를 살펴봅니다.

    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에서 OCI(Oracle Cloud Infrastructure) Monitoring 서비스로 커스터마이징 측정지표를 내보내는 방법을 배웠습니다. Oracle Database는 많은 비즈니스 워크플로우를 위한 '신뢰성 있는 소스'이므로 강력한 기능을 제공합니다.

커스터마이징 측정지표는 기본 측정지표를 사용하여 최고 수준의 OCI 모니터링 서비스를 제공합니다. 동일한 강력한 척도 질의 언어를 사용하여 이를 분석하고 알람을 설정하여 관심 이벤트나 문제가 발생할 때마다 통지할 수 있습니다.

이를 통해 OCI 서비스 또는 애플리케이션 및 데이터베이스에서 생성된 사용자정의 측정항목을 생성하므로 모든 측정항목에 대한 '단일 유리' 뷰가 제공됩니다.

감사의 글

추가 학습 자원

docs.oracle.com/learn에서 다른 실습을 찾아보거나 Oracle Learning YouTube channel에서 무료 학습 콘텐츠에 액세스할 수 있습니다. 또한 education.oracle.com/learning-explorer를 방문하여 Oracle Learning Explorer로 변경하십시오.

제품 설명서는 Oracle Help Center를 참조하십시오.