제12장 배치 서비스 개발

내용 목차

12.1. 개요
12.2. 설정
12.3. 배치 관련 테이블
12.3.1. 노드 관련 테이블
12.3.2. 센터컷 처리 테이블
12.4. 센터컷 개발
12.4.1. 센터컷 개발 및 실행
12.4.2. 예제

본 장에서는 배치 서비스의 소개와 Job 내부 구성 요소 및 개발에 대해 설명한다.

12.1. 개요

센터컷은 대용량의 데이터를 처리하기 위한 추가적인 개발자의 코드를 최소화 하고 기 개발된 서비스를 통해 대용량 데이터를 처리한다. 대용량 데이터를 처리하기 위하여 멀티노드 처리 및 안정성을 위한 fail-over 처리를 지원한다.

센터컷은 ProObject의 서비스로 구성되어있으며 대용량 데이터 처리를 위한 추가적인 개발자 코드를 최소화 한 대신, 프레임워크의 테이블 구조 및 항목들에 이해가 필요하다.

다음은 센터컷 서비스를 하는 서버와 데이터베이스 구성에 대한 설명이다.

[그림 12.1] 센터컷 서비스 아키텍처

센터컷 서비스 아키텍처


  • Service

    구분설명
    JobCCService센터컷을 처리하는 대표 시스템 서비스로 Input으로 전달 받은 CC_ID와 CC_EX_ID를 통해 센터컷을 처리한다.
    CCRangePartitionerJobCCService를 통해 호출되는 내부 서비스로 CC_MAIN과 CC_SUMR 테이블을 읽어 range를 분할하여 CCTaskService를 호출한다.
    CCTaskService실제 TargetSvc를 호출하는 서비스로 CCRangePartitioner를 통해 전달받은 seq만큼의 반복을 수행하며 TargetSvc를 호출한다.
  • DB 테이블

    센터컷 관련 처리를 위한 데이터를 테이블에 저장한다.

    테이블설명
    PO_CC_MAIN센터컷의 메인 테이블로 호출할 서비스 및 병렬처리 등 각종 설정이 존재한다.
    PO_CC_SUMR센터컷의 집계 테이블로 센터컷의 처리되고 있는 집계 데이터 및 실행 전 처리할 데이터의 총량을 관리한다.
    PO_CC_SVCM센터컷의 현황 테이블로 각 CCTaskService가 처리하고 있는 처리 현황에 대해 보여주는 테이블이다.
    PO_CC_DATA센터컷의 원장 테이블로, 각 row마다 서비스의 Input 및 Header 데이터를 가지고 있다.

12.2. 설정

관련된 내용은 다음의 경로에 설정한다.

${PROOBJECT_HOME}/config/proobject.xml

모든 설정은 <batch-config> 태그 아래에 설정에 존재한다. <batch-config>를 설정하면 배치 시스템의 서비스 그룹이 기동할 때 등록되게 되며, 센터컷 서비스를 호출하는데 해당 설정은 필수적이다.

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <!DOCTYPE xml>
 <ProObjectConfig>
 ...
       <batch-config>
       </batch-config>    
 ...
 </ProObjectConfig>

12.3. 배치 관련 테이블

ProObject의 배치는 상태를 기록하는 테이블, 온라인 배치 혹은 멀티노드 처리를 위한 노드 관련 테이블 그리고 센터컷 관련 처리를 위한 데이터를 테이블에 저장한다.

12.3.1. 노드 관련 테이블

노드 관련 설정이 없으면, 센터컷은 센터컷 서비스가 호출된 자신 노드로 CCTask를 호출한다.

  • PO_NODE

    온라인 배치 혹은 멀티 노드를 사용하기 위하여 사용 노드 정보 관리를 위해 사용되는 테이블이다.

    컬럼설명
    NODE_ID노드의 아이디이다.
    NODE_NAME노드명이다.
    HOST노드의 호스트명이다.
    PORT노드의 포트명이다.
    STATUS노드의 상태이며, 현재는 미사용이나, 노드 관리를 위하여 사용된다.
    UPDATE_TIME노드 정보 업데이트 시간(등록 및 수정 시간)이다.
  • PO_NODE_JOB

    배치 내에 Task 및 스탭, 파티셔너의 상태 및 종료 상태를 나타낸다.

    컬럼설명
    NODE_ID노드의 아이디(PO_NODE에 존재하는 아이디)이다.
    JOB_ID배치의 아이디이다.
    TASK_ID배치의 태스크 아이디이다.
    NODE_WEIGHT노드의 가중치이다.

12.3.2. 센터컷 처리 테이블

  • PO_CC_MAIN

    PO_CC_MAIN은 센터컷 메인 테이블이다.

    컬럼설명
    CC_ID센터컷 아이디이다.
    APP_NAME센터컷에서 호출할 서비스의 애플리케이션명이다.
    SVC_GRP_NAME센터컷에서 호출할 서비스의 서비스 그룹명이다.
    SVC_NAME센터컷에서 호출할 서비스명이다.
    INPUT_CLZ센터컷에서 호출할 서비스의 Input DataObject 클래스명이다.
    CONCURRENT_NUM센터컷에서 서비스 호출할 병렬 처리수이다.
    CHUNK_SIZE병렬 처리당 데이터 묶음수이다.
    CALL_RETRY_CNT요청에 실패하는 경우 재처리 횟수이다.
    HANDLER_CLASS현재 사용하지 않는 컬럼이다.
  • PO_CC_SUMR

    PO_CC_SUMR는 센터 컷 정보를 집계하는 테이블이다.

    컬럼설명
    CC_ID센터컷 아이디이다.
    CC_EXE_ID센터컷 실행 아이디이다.
    CC_STATUS

    상태 코드이다.

    • 0 : 미처리(준비됨)

    • 14 : 처리중

    • 15 : 처리완료

    • 16 : 에러

    • 20 : 일시중지

    • 21 : 종료됨

    CC_STT_TIME센터컷 시작시간이다.
    CC_END_TIME센터컷 종료시간이다.
    TOT_DSCNT전체 처리수이다.
    TOT_DSAMT총 합계이다.
    NML_CNT정상 처리수이다.
    NML_AMT정상 합계이다.
    ERR_CNT에러 처리수이다.
    ERR_AMT에러 합계이다.
    NODE_ID센터컷 파티셔너가 동작하는 노드 아이디이다.
  • PO_CC_SVCM

    PO_CC_SVCM은 센터컷 현황을 저장하는 테이블이다.

    컬럼설명
    CC_ID센터컷 아이디이다.
    CC_EXE_ID센터컷 실행 아이디이다.
    TASK_SER센터컷 처리 요청 일련번호이다.
    STT_SER센터컷 요청 데이터 시작 일련번호이다.
    END_SER센터컷 요청 데이터 끝 일련번호이다.
    CPLT_SER센터컷 요청 데이터 현재 처리 중 일련번호이다.
    CC_TASK_STATUS

    상태 코드이다.

    • 0 : 미처리

    • 14 : 처리중

    • 15 : 처리완료

    • 16 : 에러

    NML_CNT정상 처리된 건수이다.
    NML_AMT정상 처리 합계이다.
    ERR_CNT에러 건이다.
    ERR_AMT에러건 합계이다.
    NODE_ID처리 중 노드 아이디이다.
  • PO_CC_DATA

    PO_CC_DATA는 센터컷 원장 테이블이다.

    컬럼설명
    CC_ID센터컷 아이디이다.
    CC_EXE_ID센터컷 실행번호이다.
    SEQcally 서비스의 일련번호이다.
    DATA_STATUScally 서비스의 상태이다. (초기값: 0)
    AMTcally 서비스의 AMT이다.
    DATA1cally 서비스의 데이터이다.
    DATA2cally 서비스의 데이터이다.
    DATA3cally 서비스의 데이터이다.
    DATA4cally 서비스의 데이터이다.
    DATA5cally 서비스의 데이터이다.
    HEADER_DATAcally 서비스의 헤더이다.
    ERR_MSGcally 서비스의 에러 메시지이다.
  • PO_NODE_JOB_SUMR

    각 배치 노드의 처리 현황을 보여주는 테이블이며 추후 삭제될 테이블 입니다.

    컬럼설명
    JOB_ID잡 아이디(CC_ID)이다.
    JOB_EXE_ID실행 번호이다.
    NODE_ID노드 아이디이다.
    NML_CNT성공 카운트이다.
    ERR_CNT에러 카운트이다.
    UPDATE_TIME변경시간이다.
    DATA2배치의 태스크 아이디이다.
    DATA3노드의 가중치이다.
    DATA4노드의 아이디(PO_NODE에 존재하는 아이디)이다.
    DATA5배치의 아이디이다.
    ERR_MSG배치의 태스크 아이디이다.

다음은 테이블 생성 스크립트 예제이다.

DROP TABLE PO_NODE_JOB_SUMR;
CREATE TABLE PO_NODE_JOB_SUMR(
    JOB_ID         VARCHAR2(20),
    JOB_EXE_ID     VARCHAR2(64 BYTE),
    NODE_ID        VARCHAR2(128), 
    NML_CNT        NUMBER(10),
    ERR_CNT        NUMBER(10),
    UPDATE_TIME TIMESTAMP DEFAULT SYSDATE, /** 최종 상태 변경 시간 **/
    PRIMARY KEY (JOB_ID,JOB_EXE_ID,NODE_ID)
);

COMMENT ON TABLE  PO_NODE_JOB_SUMR IS 'JOB 노드별 통계 테이블';
COMMENT ON column PO_NODE_JOB_SUMR.JOB_ID IS 'JOB ID';
COMMENT ON column PO_NODE_JOB_SUMR.JOB_EXE_ID IS 'JOB 실행 ID';
COMMENT ON column PO_NODE_JOB_SUMR.NODE_ID IS '노드 ID';
COMMENT ON column PO_NODE_JOB_SUMR.NML_CNT IS '정상건수';
COMMENT ON column PO_NODE_JOB_SUMR.ERR_CNT IS '실패건수';
COMMENT ON column PO_NODE_JOB_SUMR.UPDATE_TIME IS '업데이트시간';

DROP TABLE PO_NODE;
CREATE TABLE PO_NODE(
    NODE_ID    VARCHAR2(128), 
    NODE_NAME  VARCHAR2(256), 
    HOST       VARCHAR2(256), 
    PORT       NUMBER(5), 
    STATUS     VARCHAR2(20), /** 노드 상태 **/
    UPDATE_TIME TIMESTAMP DEFAULT SYSDATE, /** 최종 상태 변경 시간 **/
    PRIMARY KEY (NODE_ID)
);

COMMENT ON TABLE PO_NODE IS 'ProObject Node 관리 테이블, 배치에서 활용';
COMMENT ON column PO_NODE.NODE_ID IS '노드 ID';
COMMENT ON column PO_NODE.NODE_NAME IS '센터컷 실행 애플리케이션명';
COMMENT ON column PO_NODE.HOST IS '호스트명, ex) 192.168.0.1';
COMMENT ON column PO_NODE.PORT IS '포트명 ex) 8888';
COMMENT ON column PO_NODE.STATUS IS '상태';
COMMENT ON column PO_NODE.UPDATE_TIME IS '업데이트시간';

DROP TABLE PO_NODE_JOB;
CREATE TABLE PO_NODE_JOB(
    NODE_ID  VARCHAR2(128), 
    JOB_ID   VARCHAR2(128),
    TASK_ID  VARCHAR2(128),
    NODE_WEIGHT NUMBER(3) DEFAULT 0,
    unique(NODE_ID,JOB_ID,TASK_ID)    
);

COMMENT ON TABLE PO_NODE_JOB IS 'JOB에서 사용되는 NODE 정보 테이블';
COMMENT ON column PO_NODE_JOB.NODE_ID IS '노드 ID';
COMMENT ON column PO_NODE_JOB.JOB_ID IS 'JOB ID';
COMMENT ON column PO_NODE_JOB.TASK_ID IS 'TASK ID, CC의 경우 null';
COMMENT ON column PO_NODE_JOB.NODE_WEIGHT IS '노드 가중치';

DROP TABLE PO_CC_MAIN;
CREATE TABLE PO_CC_MAIN(
  CC_ID             VARCHAR2(20),
  APP_NAME          VARCHAR2(256),
  SVC_GRP_NAME      VARCHAR2(256),
  SVC_NAME          VARCHAR2(256),
  INPUT_CLZ         VARCHAR2(256) not null,
  CONCURRENT_NUM    NUMBER(3),
  CHUNK_SIZE        NUMBER(4),
  CALL_RETRY_CNT    NUMBER(4) not null,
  HANDLER_CLASS     VARCHAR2(256 BYTE),
  CONSTRAINT PO_CC_MAIN_PK PRIMARY KEY (CC_ID)
);

COMMENT ON TABLE PO_CC_MAIN IS '센터컷 메인 테이블';
COMMENT ON column PO_CC_MAIN.CC_ID IS '센터컷 ID';
COMMENT ON column PO_CC_MAIN.APP_NAME IS '센터컷 실행 애플리케이션명';
COMMENT ON column PO_CC_MAIN.SVC_GRP_NAME IS '센터컷 실행 서비스그룹명';
COMMENT ON column PO_CC_MAIN.SVC_NAME IS '센터컷 실행 서비스명';
COMMENT ON column PO_CC_MAIN.INPUT_CLZ IS '센터컷 실행 서비스 InputDO 클래스명';
COMMENT ON column PO_CC_MAIN.CONCURRENT_NUM IS '동시처리수(0일경우 일시중지, -1이하 중지)';
COMMENT ON column PO_CC_MAIN.CHUNK_SIZE IS '호출당 데이터 묶음수';
COMMENT ON column PO_CC_MAIN.HANDLER_CLASS IS '센터컷 핸들러 클래스명';

DROP TABLE PO_CC_SUMR;
CREATE TABLE PO_CC_SUMR(
  CC_ID            VARCHAR2(20),
  CC_EXE_ID        VARCHAR2(64 BYTE),
  CC_STATUS        NUMBER(2),
  CC_STT_TIME      VARCHAR2(14),--YYYYMMddHHmmss
  CC_END_TIME      VARCHAR2(14),
  TOT_DSCNT        NUMBER(10),
  TOT_DSAMT        NUMBER(18,2),
  NML_CNT          NUMBER(10),
  NML_AMT          NUMBER(18,2),
  ERR_CNT          NUMBER(10),
  ERR_AMT          NUMBER(18,2),
  NODE_ID          VARCHAR2(128),
  CONSTRAINT PO_CC_SUMR_PK PRIMARY KEY (CC_ID, CC_EXE_ID)
);

COMMENT ON column PO_CC_SUMR.CC_ID IS '센터컷 ID';
COMMENT ON column PO_CC_SUMR.CC_EXE_ID IS '센터컷 실행 ID';
COMMENT ON column PO_CC_SUMR.CC_STATUS IS '상태(추후 상세정보)';
COMMENT ON column PO_CC_SUMR.CC_STT_TIME IS '시작시간(YYYYMMddHHmmss)';
COMMENT ON column PO_CC_SUMR.CC_END_TIME IS '종료시간(YYYYMMddHHmmss)';
COMMENT ON column PO_CC_SUMR.TOT_DSCNT IS '총처리건수';
COMMENT ON column PO_CC_SUMR.TOT_DSAMT IS '총금액';
COMMENT ON column PO_CC_SUMR.NML_CNT IS '정상건수';
COMMENT ON column PO_CC_SUMR.NML_AMT IS '정상금액';
COMMENT ON column PO_CC_SUMR.ERR_CNT IS '에러건수';
COMMENT ON column PO_CC_SUMR.ERR_AMT IS '에러금액';

DROP TABLE PO_CC_SVCM;
CREATE TABLE PO_CC_SVCM(
  CC_ID         VARCHAR2(20),
  CC_EXE_ID     VARCHAR2(64 BYTE),
  TASK_SER      NUMBER(10),
  STT_SER       NUMBER(10),
  END_SER       NUMBER(10),
  CPLT_SER      NUMBER(10),
  CC_TASK_STATUS     NUMBER(2) DEFAULT 0,
  NML_CNT       NUMBER(10) DEFAULT 0,
  NML_AMT       NUMBER(18,2) DEFAULT 0,
  ERR_CNT       NUMBER(10) DEFAULT 0,
  ERR_AMT       NUMBER(18,2) DEFAULT 0,
  NODE_ID       VARCHAR2(20),
  CONSTRAINT PO_CC_SVCM_PK PRIMARY KEY (CC_ID, CC_EXE_ID,TASK_SER)
);

COMMENT ON column PO_CC_SVCM.CC_ID IS '센터컷 ID';
COMMENT ON column PO_CC_SVCM.CC_EXE_ID IS '센터컷 실행 ID';
COMMENT ON column PO_CC_SVCM.TASK_SER IS 'Task일련번호';
COMMENT ON column PO_CC_SVCM.STT_SER IS '시작일련번호';
COMMENT ON column PO_CC_SVCM.END_SER IS '끝일련번호';
COMMENT ON column PO_CC_SVCM.CPLT_SER IS '현재일련번호';
COMMENT ON column PO_CC_SVCM.CC_TASK_STATUS IS '상태(추후 상세정보)';
COMMENT ON column PO_CC_SVCM.NML_CNT IS '정상건수';
COMMENT ON column PO_CC_SVCM.NML_AMT IS '정상금액';
COMMENT ON column PO_CC_SVCM.ERR_CNT IS '에러건수';
COMMENT ON column PO_CC_SVCM.ERR_AMT IS '에러금액';

DROP TABLE PO_CC_DATA;
CREATE TABLE PO_CC_DATA(
    CC_ID         VARCHAR2(20),
    CC_EXE_ID     VARCHAR2(64 BYTE),
    SEQ           NUMBER(10),
    DATA_STATUS   NUMBER(2),
    AMT           NUMBER(18),
    DATA1         VARCHAR2(4000),
    DATA2         VARCHAR2(4000),
    DATA3         VARCHAR2(4000),
    DATA4         VARCHAR2(4000),
    DATA5         VARCHAR2(4000),
    HEADER_DATA   VARCHAR2(4000),
    ERR_MSG       VARCHAR2(4000),
    CONSTRAINT PO_CC_DATA_PK PRIMARY KEY (CC_ID, CC_EXE_ID,SEQ)
);

COMMENT ON column PO_CC_DATA.CC_ID IS '센터컷 ID';
COMMENT ON column PO_CC_DATA.CC_EXE_ID IS '센터컷 실행 ID';
COMMENT ON column PO_CC_DATA.SEQ IS '일련번호(0~)';
COMMENT ON column PO_CC_DATA.DATA_STATUS IS '상태(추후 상세정보)';
COMMENT ON column PO_CC_DATA.AMT IS '금액';
COMMENT ON column PO_CC_DATA.DATA1 IS '데이터1';
COMMENT ON column PO_CC_DATA.DATA2 IS '데이터2';
COMMENT ON column PO_CC_DATA.DATA3 IS '데이터3';
COMMENT ON column PO_CC_DATA.DATA4 IS '데이터4';
COMMENT ON column PO_CC_DATA.DATA5 IS '데이터5';
COMMENT ON column PO_CC_DATA.ERR_MSG IS '에러메시지';

12.4. 센터컷 개발

본 절에서는 센터컷 개발 및 실행하는 방법을 설명한다.

12.4.1. 센터컷 개발 및 실행

센터컷은 이미 개발된 서비스를 통해 데이터를 처리하는 방식을 제공한다는 점은 온라인 배치와 동일하지만, 프레임워크의 원장을 활용하여 개발자의 코딩을 최소화한다는 점이 다르다. 센터컷은 개발자의 코딩을 최소화하기 위하여 프레임워크의 각 테이블에 대해 정확히 이해해야 한다.

다음은 센터컷의 개발 과정에 대한 설명이다.

  1. PO_CC_MAIN 데이터를 삽입한다.

  2. 멀티노드 처리가 필요한 경우 PO_NODE 테이블에 노드 정보를 추가하고 PO_NODE_JOB 테이블에 데이터를 삽입한다.

센터컷의 개발이 완료된 후 다음의 과정으로 센터컷의 실행 및 준비를 한다.

  1. 실행하기 위해 필요한 고유값인 실행번호(아이디, 고유값, 날짜 혹은 시간)를 정의한다.

  2. 센터컷에 활용할 데이터를 센터컷 아이디, 센터컷 실행번호를 포함하여 프레임워크 원장(PO_CC_DATA)에 저장한다.

  3. 프레임워크 원장에 적재한 데이터 카운터 및 일자를 포함한 PO_CC_SUMR 테이블에 삽입한다.

  4. 센터컷을 센터컷 아이디와 실행번호를 INPUT으로 실행한다.

12.4.2. 예제

다음은 센터컷 테이블을 사용하는 예제이다.

--PO_CC_MAIN 데이터 삽입, 동시 요청수 1, 데이터 분할 수 10
--com.tmax.proobject.batch.dataobject.CCParameter Input 클래스를 가진 
--app.svcG1.JobServiceCCTargetSample 서비스 호출
insert into po_cc_main(CC_ID, APP_NAME, SVC_GRP_NAME, SVC_NAME, 
    INPUT_CLZ, CONCURRENT_NUM, CHUNK_SIZE, HANDLER_CLASS, CALL_RETRY_CNT) 
VALUES ('CC_ID_SAM1','app','svcG1','JobServiceCCTargetSample',
    'com.tmax.proobject.batch.dataobject.CCParameter',1,10,null,0);

--ProObject7_2 노드 추가
insert into PO_NODE(NODE_ID, NODE_NAME, HOST, TCP_PORT, STATUS) 
VALUES ('ProObject7_2','ProObject7_2','192.168.0.128',6778,1);

--ProObject7_3 노드 추가
insert into PO_NODE(NODE_ID, NODE_NAME, HOST, TCP_PORT, STATUS) 
VALUES ('ProObject7_3','ProObject7_3','192.168.0.128',6779,1);

--ProObject7_2에 비율 1
insert into PO_NODE_JOB(NODE_ID, JOB_ID, NODE_WEIGHT) 
VALUES ('ProObject7_2','CC_ID_SAM1',1);

--ProObject7_3에 비율 1 
insert into PO_NODE_JOB(NODE_ID, JOB_ID, NODE_WEIGHT) 
VALUES ('ProObject7_3','CC_ID_SAM1',1);

--센터컷은 ProObject7_2 노드, ProObject7_3 노드 1:1 비율로 호출


--데이터 삽입, 실행번호는 'ex_190219'으로 임의 생성
insert into po_cc_data(CC_ID, CC_EXE_ID, SEQ, DATA_STATUS, AMT, DATA1, DATA2, DATA3, DATA4, DATA5) 
VALUES ('CC_ID_SAM1', 'ex_190219', 0, '0', 0, '{"cc_id":"123","cc_exe_id":"testEx0","retry_yn":"n"}', null, null, null, null);
insert into po_cc_data(CC_ID, CC_EXE_ID, SEQ, DATA_STATUS, AMT, DATA1, DATA2, DATA3, DATA4, DATA5) 
VALUES ('CC_ID_SAM1', 'ex_190219', 1, '0', 0, '{"cc_id":"123","cc_exe_id":"33","retry_yn":"n"}', null, null, null, null);


--sumr 삽입
insert into po_cc_sumr(CC_ID, CC_EXE_ID, CC_STATUS, CC_STT_TIME, CC_END_TIME, TOT_DSCNT, TOT_DSAMT, NML_CNT, NML_AMT, ERR_CNT, ERR_AMT)
VALUES ('CC_ID_SAM1', 'ex_190219', '0', '', '', 2, 0, 0, 0, 0, 0);