diff --git a/src/main/java/com/eactive/ext/kjb/statistics/통계테이블_설계.md b/src/main/java/com/eactive/ext/kjb/statistics/통계테이블_설계.md index 3fb40b5..671acd5 100644 --- a/src/main/java/com/eactive/ext/kjb/statistics/통계테이블_설계.md +++ b/src/main/java/com/eactive/ext/kjb/statistics/통계테이블_설계.md @@ -4,7 +4,7 @@ ### 수집 차원 - **시간 단위**: 분 단위 -- **분류 차원**: API명, API Gateway Instance, ClientId, Scope, 업무구분코드 (값이 없을 경우 'NONE' 으로 대체) +- **분류 차원**: API명, API Gateway Instance, ClientId, Inbound Adapter, Outbound Adapter, 업무구분코드 (값이 없을 경우 'NONE' 으로 대체) ### 메트릭 - **처리 건수**: @@ -24,6 +24,23 @@ --- +## 구현 완료 + +### 구현 위치 +- **패키지**: `com.eactive.eai.custom.statistics` +- **경로**: `eapim-online/src/main/java/com/eactive/eai/custom/statistics/` + +### 주요 컴포넌트 +1. **ApiStatsCollector**: 거래마다 호출되어 메모리에 집계 +2. **MinuteStatsAggregator**: HdrHistogram 기반 백분위 계산 +3. **ApiStatsScheduler**: 매 분 5초에 DB 저장 +4. **TransactionEvent**: 거래 이벤트 DTO + +### 사용법 +상세한 사용법은 `eapim-online/src/main/java/com/eactive/eai/custom/statistics/README.md` 참조 + +--- + ## 테이블 DDL ```sql @@ -32,9 +49,10 @@ CREATE TABLE API_STATS_MINUTE ( STAT_TIME TIMESTAMP(0) NOT NULL, -- 통계 시간 (분 단위, 초는 00) API_NAME VARCHAR2(100) NOT NULL, -- API명 GW_INSTANCE_ID VARCHAR2(50) NOT NULL, -- API Gateway 인스턴스 ID - CLIENT_ID VARCHAR2(100) NOT NULL, -- 클라이언트 ID - SCOPE VARCHAR2(100) DEFAULT 'NONE' NOT NULL, -- 스코프 BIZ_DIV_CODE VARCHAR2(50) DEFAULT 'NONE' NOT NULL, -- 업무구분코드 + CLIENT_ID VARCHAR2(100) DEFAULT 'NONE' NOT NULL, -- 클라이언트 ID + INBOUND_ADAPTER VARCHAR2(100) DEFAULT 'NONE' NOT NULL, -- Inbound Adapter + OUTBOUND_ADAPTER VARCHAR2(100) DEFAULT 'NONE' NOT NULL, -- Outbound Adapter -- 건수 메트릭 TOTAL_CNT NUMBER(12) DEFAULT 0 NOT NULL, @@ -43,6 +61,11 @@ CREATE TABLE API_STATS_MINUTE ( SYSTEM_ERR_CNT NUMBER(12) DEFAULT 0 NOT NULL, BIZ_ERR_CNT NUMBER(12) DEFAULT 0 NOT NULL, + -- 로그 시퀀스 900 구간 에러 카운트 + SEQ900_TIMEOUT_CNT NUMBER(12) DEFAULT 0 NOT NULL, + SEQ900_SYSTEM_ERR_CNT NUMBER(12) DEFAULT 0 NOT NULL, + SEQ900_BIZ_ERR_CNT NUMBER(12) DEFAULT 0 NOT NULL, + -- 응답시간 메트릭 (ms, 소수점 3자리) AVG_RESP_TIME NUMBER(10,3) DEFAULT 0, MIN_RESP_TIME NUMBER(10,3) DEFAULT 0, @@ -50,12 +73,8 @@ CREATE TABLE API_STATS_MINUTE ( P50_RESP_TIME NUMBER(10,3) DEFAULT 0, P95_RESP_TIME NUMBER(10,3) DEFAULT 0, - -- 관리 정보 - REG_DTIME TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL, - UPD_DTIME TIMESTAMP DEFAULT SYSTIMESTAMP, - CONSTRAINT PK_API_STATS_MINUTE PRIMARY KEY ( - STAT_TIME, API_NAME, GW_INSTANCE_ID, CLIENT_ID, SCOPE, BIZ_DIV_CODE + STAT_TIME, API_NAME, GW_INSTANCE_ID, BIZ_DIV_CODE, CLIENT_ID, INBOUND_ADAPTER, OUTBOUND_ADAPTER ) ); @@ -64,14 +83,18 @@ COMMENT ON TABLE API_STATS_MINUTE IS 'API Gateway 분단위 처리 통계'; COMMENT ON COLUMN API_STATS_MINUTE.STAT_TIME IS '통계시간(분단위, 초는 00초로 절사)'; COMMENT ON COLUMN API_STATS_MINUTE.API_NAME IS 'API 명칭'; COMMENT ON COLUMN API_STATS_MINUTE.GW_INSTANCE_ID IS 'API Gateway 인스턴스 ID'; -COMMENT ON COLUMN API_STATS_MINUTE.CLIENT_ID IS '클라이언트 ID'; -COMMENT ON COLUMN API_STATS_MINUTE.SCOPE IS '스코프 (없으면 NONE)'; COMMENT ON COLUMN API_STATS_MINUTE.BIZ_DIV_CODE IS '업무구분코드 (없으면 NONE)'; +COMMENT ON COLUMN API_STATS_MINUTE.CLIENT_ID IS '클라이언트 ID (없으면 NONE)'; +COMMENT ON COLUMN API_STATS_MINUTE.INBOUND_ADAPTER IS 'Inbound Adapter (없으면 NONE)'; +COMMENT ON COLUMN API_STATS_MINUTE.OUTBOUND_ADAPTER IS 'Outbound Adapter (없으면 NONE)'; COMMENT ON COLUMN API_STATS_MINUTE.TOTAL_CNT IS '총 처리 건수'; COMMENT ON COLUMN API_STATS_MINUTE.SUCCESS_CNT IS '성공 건수'; COMMENT ON COLUMN API_STATS_MINUTE.TIMEOUT_CNT IS 'Timeout 오류 건수'; COMMENT ON COLUMN API_STATS_MINUTE.SYSTEM_ERR_CNT IS '시스템 오류 건수'; COMMENT ON COLUMN API_STATS_MINUTE.BIZ_ERR_CNT IS '업무 오류 건수'; +COMMENT ON COLUMN API_STATS_MINUTE.SEQ900_TIMEOUT_CNT IS '로그시퀀스900 Timeout 오류 건수'; +COMMENT ON COLUMN API_STATS_MINUTE.SEQ900_SYSTEM_ERR_CNT IS '로그시퀀스900 시스템 오류 건수'; +COMMENT ON COLUMN API_STATS_MINUTE.SEQ900_BIZ_ERR_CNT IS '로그시퀀스900 업무 오류 건수'; COMMENT ON COLUMN API_STATS_MINUTE.AVG_RESP_TIME IS '평균 응답시간(ms)'; COMMENT ON COLUMN API_STATS_MINUTE.MIN_RESP_TIME IS '최소 응답시간(ms)'; COMMENT ON COLUMN API_STATS_MINUTE.MAX_RESP_TIME IS '최대 응답시간(ms)'; @@ -81,3 +104,66 @@ COMMENT ON COLUMN API_STATS_MINUTE.P95_RESP_TIME IS '95 백분위 응답시간(m --- +## 시간별 통계 테이블 DDL + +```sql +-- API Gateway 시간별 통계 테이블 +CREATE TABLE API_STATS_HOUR ( + STAT_TIME TIMESTAMP(0) NOT NULL, -- 통계 시간 (시간 단위, 분/초는 00) + API_NAME VARCHAR2(100) NOT NULL, -- API명 + GW_INSTANCE_ID VARCHAR2(50) NOT NULL, -- API Gateway 인스턴스 ID + BIZ_DIV_CODE VARCHAR2(50) DEFAULT 'NONE' NOT NULL, -- 업무구분코드 + CLIENT_ID VARCHAR2(100) DEFAULT 'NONE' NOT NULL, -- 클라이언트 ID + INBOUND_ADAPTER VARCHAR2(100) DEFAULT 'NONE' NOT NULL, -- Inbound Adapter + OUTBOUND_ADAPTER VARCHAR2(100) DEFAULT 'NONE' NOT NULL, -- Outbound Adapter + + -- 건수 메트릭 + TOTAL_CNT NUMBER(12) DEFAULT 0 NOT NULL, + SUCCESS_CNT NUMBER(12) DEFAULT 0 NOT NULL, + TIMEOUT_CNT NUMBER(12) DEFAULT 0 NOT NULL, + SYSTEM_ERR_CNT NUMBER(12) DEFAULT 0 NOT NULL, + BIZ_ERR_CNT NUMBER(12) DEFAULT 0 NOT NULL, + + -- 로그 시퀀스 900 구간 에러 카운트 + SEQ900_TIMEOUT_CNT NUMBER(12) DEFAULT 0 NOT NULL, + SEQ900_SYSTEM_ERR_CNT NUMBER(12) DEFAULT 0 NOT NULL, + SEQ900_BIZ_ERR_CNT NUMBER(12) DEFAULT 0 NOT NULL, + + -- 응답시간 메트릭 (ms, 소수점 3자리) + AVG_RESP_TIME NUMBER(10,3) DEFAULT 0, + MIN_RESP_TIME NUMBER(10,3) DEFAULT 0, + MAX_RESP_TIME NUMBER(10,3) DEFAULT 0, + P50_RESP_TIME NUMBER(10,3) DEFAULT 0, + P95_RESP_TIME NUMBER(10,3) DEFAULT 0, + + CONSTRAINT PK_API_STATS_HOUR PRIMARY KEY ( + STAT_TIME, API_NAME, GW_INSTANCE_ID, BIZ_DIV_CODE, CLIENT_ID, INBOUND_ADAPTER, OUTBOUND_ADAPTER + ) +); + +-- 코멘트 +COMMENT ON TABLE API_STATS_HOUR IS 'API Gateway 시간별 처리 통계'; +COMMENT ON COLUMN API_STATS_HOUR.STAT_TIME IS '통계시간(시간단위, 분/초는 00으로 절사)'; +COMMENT ON COLUMN API_STATS_HOUR.API_NAME IS 'API 명칭'; +COMMENT ON COLUMN API_STATS_HOUR.GW_INSTANCE_ID IS 'API Gateway 인스턴스 ID'; +COMMENT ON COLUMN API_STATS_HOUR.BIZ_DIV_CODE IS '업무구분코드 (없으면 NONE)'; +COMMENT ON COLUMN API_STATS_HOUR.CLIENT_ID IS '클라이언트 ID (없으면 NONE)'; +COMMENT ON COLUMN API_STATS_HOUR.INBOUND_ADAPTER IS 'Inbound Adapter (없으면 NONE)'; +COMMENT ON COLUMN API_STATS_HOUR.OUTBOUND_ADAPTER IS 'Outbound Adapter (없으면 NONE)'; +COMMENT ON COLUMN API_STATS_HOUR.TOTAL_CNT IS '총 처리 건수'; +COMMENT ON COLUMN API_STATS_HOUR.SUCCESS_CNT IS '성공 건수'; +COMMENT ON COLUMN API_STATS_HOUR.TIMEOUT_CNT IS 'Timeout 오류 건수'; +COMMENT ON COLUMN API_STATS_HOUR.SYSTEM_ERR_CNT IS '시스템 오류 건수'; +COMMENT ON COLUMN API_STATS_HOUR.BIZ_ERR_CNT IS '업무 오류 건수'; +COMMENT ON COLUMN API_STATS_HOUR.SEQ900_TIMEOUT_CNT IS '로그시퀀스900 Timeout 오류 건수'; +COMMENT ON COLUMN API_STATS_HOUR.SEQ900_SYSTEM_ERR_CNT IS '로그시퀀스900 시스템 오류 건수'; +COMMENT ON COLUMN API_STATS_HOUR.SEQ900_BIZ_ERR_CNT IS '로그시퀀스900 업무 오류 건수'; +COMMENT ON COLUMN API_STATS_HOUR.AVG_RESP_TIME IS '평균 응답시간(ms)'; +COMMENT ON COLUMN API_STATS_HOUR.MIN_RESP_TIME IS '최소 응답시간(ms)'; +COMMENT ON COLUMN API_STATS_HOUR.MAX_RESP_TIME IS '최대 응답시간(ms)'; +COMMENT ON COLUMN API_STATS_HOUR.P50_RESP_TIME IS '50 백분위 응답시간(ms)'; +COMMENT ON COLUMN API_STATS_HOUR.P95_RESP_TIME IS '95 백분위 응답시간(ms)'; +``` + +--- +