BPEL 운영 환경의 관리
저자: Stany Blanvalet
BPEL Process Manager의 API와 Dehydration Store를
이용하여 BPEL 운영 환경의 관리 업무를 자동화하는 방법을 소개합니다.
전체 BPEL Cookbook 인덱스 보기
게시일: 2006년 1월
많은 기업들이 70%에 달하는 IT 비용을 기존 IT 환경의 유지에 사용하고 있습니다. 하지만 역설적이게도, SOA(service-oriented
architecture)를 구현한 대부분의 기업이 웹 서비스의 성능과 가용성을 관리하는 업무의 우선순위를 소홀히 하고
있는 것이 현실입니다. 웹 서비스 및 BPEL을 이용하여 SOA 인프라스트럭처를 구현하는 사례가 확산되면서, 애플리케이션
운영 및 관리 비용을 절감한 새로운 전략의 필요성에 대한 인식이 강조됩니다.
특히 이러한 전략은 다양한 비즈니스 프로세스의 조합으로 구성되는 BPEL 환경에서 그 중요성이 한층 강조됩니다. 운영 환경에
점점 더 많은 프로세스가 추가되면서, 보다 효율적인 관리가 필요해지기 때문입니다. 실행을 완료한 BPEL 프로세스는
(그 성공 여부에 관계없이) 데이터베이스에 저장됩니다. 프로세스 플로우 간에 교환된 XML 메시지 역시 데이터베이스에
저장됩니다. 이러한 프로세스로 인해 데이터베이스의 규모가 기하급수적으로 증가하고 성능 문제가 발생할 수 있습니다.
이러한 점을 감안했을 때, BPEL 운영 환경에 요구되는 기능이 아래와 같습니다.
- 운영 시스템의 안정성에 영향을 미치지 않고도, 완료된 BPEL 프로세스에 대한 정보를 아카이브 할 수 있어야 합니다.
- 데이터베이스로 성공적으로 전달된 모든 XML 메시지를 자동으로 삭제할 수 있어야 합니다.
- 손상된 인스턴스(stale instance)를 삭제할 수 있어야 합니다.
- 실패한 프로세스를 재실행할 수 있어야 합니다.
이번 BPEL Cookbook 시리즈에서는 BPEL Process Manager의 API와 Dehydration Store를
이용하여 이러한 기능을 구현하고, BPEL 프로세스의 전체 인스턴스에 대한 정보를 아카이브 또는 삭제하기 위한 전략을
소개합니다. 또, 손상된 인스턴스를 삭제하고 PL/SQL 및 EJB를 이용하여 XML 메시지를 포괄적으로 호출, 콜백(callback)하는
방법을 배우실 수 있습니다. 마지막으로, BPELTest 유틸리티를 이용하여 실패한 프로세스 인스턴스를 재실행하는
방법을 설명합니다.
BPEL Process Manager API와 Dehydration Store
Oracle BPEL Process Manager Console은 BPEL 서버에 구현된 프로세스의 관리, 운영,
디버깅을 위한 사용자 친화적인 웹 기반 인터페이스를 제공합니다. 하지만 운영 환경에서, 관리자는 관리 작업에 대한
보다 강력한 통제력을 갖기를 원합니다. BPEL Dehydration Store 데이터베이스에 PL/SQL 쿼리 또는
BPEL API를 실행하면 대부분의 운영 작업을 자동화하는 것이 가능합니다. 하지만, 자동화 작업을 시작하기 전에,
Dehydration Store와 BPEL Process Manager API의 기반을 이루는 개념을 이해하는 것이
중요합니다.
Dehydration Store 데이터베이스는 (특히 비동기식 BPEL 프로세스의) 상태 정보를 저장하는 용도로
사용됩니다. 데이터베이스에 포함된 중요한 테이블의 목록이 아래와 같습니다.
테이블 |
컨텐트 |
CUBE_INSTANCE |
인스턴스 메타데이터 정보 (생성일, 현재 상태, 프로세스 아이디) |
CUBE_SCOPE |
인스턴스의 스코프(scope) 데이터 |
AUDIT_TRAIL |
인스턴스의 감사 로그(audit trail) 정보. BPEL Console에서도 확인이
가능합니다. |
AUDIT_DETAILS |
프로세스 인스턴스에 대한 자세한 감사 정보 |
DLV_MESSAGE |
콜백(callback) 메시지 메타데이터 |
DLV_MESSAGE_BIN |
콜백 메시지 페이로드 |
INVOKE_MESSAGE |
호출(invocation) 메시지 메타데이터 |
INVOKE_MESSAGE_BIN |
호출 메시지 페이로드 |
DLV_SUBSCRIPTION |
인스턴스의 전달 구독(delivery subscription) |
TASK |
Tasks created for an instance (i.e. title, assignee, status, expiration) |
표 1: BPEL Dehydration Store의 주요
테이블
데이터베이스 스키마는 $ORABPEL$\integration\orabpel\system\database\scripts 디렉토리의
domain_oracle.dll DDL 스크립트에서 확인할 수 있습니다. 이 스키마 정보를 이용하면 BPEL Console을
사용하는 대신 SQL 쿼리를 직접 실행할 수 있습니다.
SQL 대신 BPEL Process Manager API를 사용할 수도 있습니다. 이 API는 다양한 상태의 인스턴스를 조회,
아카이브, 삭제하거나, 서로 다른 도메인의 콜백/호출 메시지를 삭제하거나, 특정 도메인, 프로세스, 또는 인스턴스의
상태를 조회할 수 있습니다. (API 문서는 $ORABPEL$\integration\orabpel\docs\apidocs\index.html에서
확인할 수 있습니다.) 아래 표는 가장 중요한 클래스/인터페이스 및 관련 메소드를 요약하고 있습니다.
클래스/인터페이스 |
메소드 |
Class WhereConditionHelper |
Provides methods such as whereInstancesClosed(),
whereInstancesStale(), and whereInstancesOpen(),
등의 메소드를 제공하고, where 절을 통해 인스턴스의 검색을 수행할 수 있음. |
Interface IBPELDomainHandle |
실행 중인 BPEL 프로세스 도메인에 대한 작업 수행. archiveAllInstances(),
deleteAllInstances(), d eleteInstancesByProcessId(), deployProcess(),
and undeployPorcess(), deleteAllHandledCallback(), deleteAllHandledInvoke()등의
메소드 지원. |
Interface IinstanceHandle |
액티브 인스턴스에 대한 작업 수행. isStale() , getState()
, getModifyDate() , and delete() 등의 메소드 지원. |
Class Locator |
Orabpel 프로세스 도메인 내부에 구현된 프로세스, 인스턴스,
액티비티의 검색 수행 listInstances() and listActivities()등의
메소드를 지원하며, where 절을 매개변수로 활용 가능 |
표 2: 관리 업무의 수행을 위한 중요 클래스
다음으로, 몇 가지 중요한 관리 작업을 수행하는 방법을 알아보기로 하겠습니다.
완료된 인스턴스의 아카이브 앞에서 설명한 것처럼, 성공적으로 실행된
프로세스 인스턴스는 Dehydration Store에 저장됩니다. 인스턴스가 완료되고 나면 BPEL 인스턴스가 두
개의 테이블(cube_instance와 cube_scope)에 저장됩니다. cube_instance테이블은 도메인,
생성일, 상태(completed, running, stale, cancelled), 우선순위, 제목 등의 인스턴스
헤더 정보를 기록합니다. cube_scope 테이블은 인스턴스의 상태(변수 값 등)를 기록합니다. 디폴트 설정에서는,
두 가지 테이블 모두 완료된 인스턴스의 정보를 저장하는데 사용됩니다.
아래 그림과 같이 BPEL Console을 이용하여 데이터베이스의 인스턴스 정보를 삭제(purge)할 수 있습니다..

그림 1: 완료된 인스턴스의 삭제
운영 환경에서 정보를 삭제하기 전에 PL/SQL 또는 EJB를 이용하여 정보의 아카이빙을 수행하는 것도 가능합니다. (BPEL
데이터베이스에서 정보를 삭제하기 전에 다른 위치로 이동해 두는 작업을 잊지 말고 수행해야 합니다.) 몇 가지 실행
예가 아래와 같습니다.
EJB를 이용한 아카이빙. 아래 인터페이스와 메소드를 사용합니다.
com.oracle.bpel.client |
IBPELDomainHandle 인터페이스 |
메소드 요약 |
int |
archiveInstances(WhereCondition wc, boolean deleteInstances)
(wc에 의해 지정된 검색 조건을 만족하는 모든 인스턴스를 아카이브 ) |
archiveInstances 메소드는 모든 완료된 인스턴스를 아카이브하고 삭제합니다. keepdays
매개변수를 이용하면 아카이브기 되기까지의 여유 기한을 설정할 수 있습니다.
public static int archiveInstances(Locator locator, String processId, int keepdays)
throws ORABPELAccessException {
try {
WhereCondition wc = WhereConditionHelper.whereInstancesClosed();
WhereCondition tmpWhere = new WhereCondition();
NonSyncStringBuffer buf = new NonSyncStringBuffer();
if (!"*".equals(processId)) {
buf.setLength(0);
tmpWhere.setClause(buf.append(" AND ").append(
SQLDefs.AL_ci_process_id).append(" = ? ").toString());
tmpWhere.setString(1, processId);
wc.append(tmpWhere);
}
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, -keepdays);
buf.setLength(0);
tmpWhere.setClause(buf.append(" AND ").append(
SQLDefs.AL_ci_modify_date).append(" <= ? ").toString());
tmpWhere.setTimestamp(1, cal.getTime());
wc.append(tmpWhere);
IBPELDomainHandle domain = locator.lookupDomain();
return domain.archiveInstances(wc, true);
} catch (ServerException se) {
throw new ORABPELAccessException(se.getMessage());
}
}
PL/SQL을 이용한 아카이빙. PL/SQL을 이용하여 동일한 작업을 수행하는 것
또한 가능합니다. 데이터베이스에서 레코드를 삭제하기 전에, 레코드를 다른 데이터베이스/테이블로 이동하는 방법이 아래와
같습니다:
Query: SELECT CIKEY FROM CUBE_INSTANCE, DOMAIN
WHERE BPELMNG.CUBE_INSTANCE.DOMAIN_REF = BPELMNG.DOMAIN.DOMAIN_REF
AND BPELMNG.DOMAIN.DOMAIN_ID = 'XXX' ?XXX is the name of the domain
AND STATE = 5 ?'5' mean COMPLETED
AND MODIFY_DATE < SYSDATE-X ?X is the number of day of history
AND PROCESS_ID = 'XXX'; ?XXX is the process name
Actions:
For each CIKEY, call COLLAXA.delete_ci(CIKEY); oracle procedure.
다음 섹션에서는, 콜백/호출 메시지를 삭제하는 방법을 알아보겠습니다.
콜백(Callback), 호출( Invoke) 메시지의 삭제 파트너로부터의
메시지 (receive, onMessage 등)가 인스턴스에 전달되는 시점에, 해당
receive 액티비티에 대한 구독(subscription)이 실행됩니다. 전달 메시지(delivery message)의
수신이 완료되면, 전달 계층에서 구독 내역과 메시지를 상호 연계하는 작업이 시도됩니다. 구독을 통해 성공적으로 수신된
메시지는 데이터베이스 내부에 잔류합니다. 이 메시지는 (인스턴스 아카이빙의 경우와 마찬가지로) collaxa.delete_ci(CIKEY)
스토어드 프로시저를 통해 삭제됩니다.
콜백/호출 XML 메시지의 경우에도 동일한 규칙이 적용됩니다. 메시지는 성공적으로 전달, 해결된 후에도 데이터베이스에 보관됩니다.
callback, invoke, subscription 메시지의 삭제를 위한 메소드가 아래와 같습니다.
com.oracle.bpel.client |
IBPELDomainHandle 인터페이스 |
메소드 요약 |
int |
deleteAllHandledCallback ()
(도메인에서 성공적으로 해결, 전달된 모든 callback 메시지를 삭제) |
int |
DeleteAllHandledInvoke ()
(도메인에서 성공적으로 해결, 전달된 모든 invocation 메시지를 삭제) |
int |
DeleteAllHandledSubscription ()
(성공적으로 해결, 처리된 모든 message subscriber를 삭제) |
아래 코드 예제에서 확인할 수 있는 것처럼, PL/SQL을
이용해서도 동일한 작업을 수행할 수 있습니다. 아래의 코드를 수정하여 기업 내부의 요구사항에 적합한 아카이빙 환경을
구현할 수 있을 것입니다.
/**
* Procedure to clean invocation messages for a particular domain.
* Invocation messages are stored in invoke_message and invoke_message_bin table
* It will select all the invocation messages from invoke_message table.
* For each message which has been delivered or resolved, delete it from
* invoke_message and invoke_message_bin table
*/
procedure delete_invoke( p_domain_ref in integer )
as
cursor c_invoke_message is
select message_guid
from invoke_message
where ( state = 2 or state = 3 )
and domain_ref = p_domain_ref
for update;
begin
for r_invoke_message in c_invoke_message loop
delete from invoke_message_bin where message_guid = r_invoke_message.message_guid;
delete from invoke_message where current of c_invoke_message;
end loop;
commit;
end delete_invoke;
/**
* Procedure to clean callback messages for a particular domain.
* Callback messages are stored in dlv_message and dlv_message_bin table
* It will select all the invocation messages from dlv_message table.
* For each message which has been delivered or resolved, delete it from
* dlv_message and dlv_message_bin table
*/
procedure delete_callback( p_domain_ref in integer )
as
cursor c_dlv_message is
select message_guid
from dlv_message
where ( state = 2 or state = 3 )
and domain_ref = p_domain_ref
for update;
begin
for r_dlv_message in c_dlv_message loop
delete from dlv_message_bin
where message_guid = r_dlv_message.message_guid;
delete from dlv_message
where current of c_dlv_message;
end loop;
commit;
end delete_callback;
다음으로, 손상된 인스턴스를 삭제하는 방법을 알아보겠습니다.
손상된 인스턴스(stale instance)의 삭제 BPEL Console을
이용하여, 모든 손상된 인스턴스를 삭제하고 아래와 같이 제거할 수 있습니다.

그림 2: BPEL Console에서 손상된 인스턴스의
제거(kill)
손상된 인스턴스의 검색은 특정 도메인 내부에서만 가능합니다. 하지만 실제 운영 환경에서는 여러 가지 프로세스가 다양한 도메인에
걸쳐 사용되고 있기 때문에, 심각한 업무 부담을 유발시킬 수 있습니다. 또 특정 도메인 내부에서 손상된 인스턴스들을
한꺼번에 제거하는 것 또한 불가능합니다.
그 대신, 아래 SQL 쿼리를 이용하여 각각의 손상된 인스턴스의 cube instance key(cikey)를 조회할 수 있습니다.
SELECT CUBE_INSTANCE.cikey, CUBE_INSTANCE.root_id, CUBE_INSTANCE.process_id,
CUBE_INSTANCE.domain_ref
FROM CUBE_INSTANCE
WHERE STATE = 9
손상된 인스턴스의 cikey를 확인했다면 delete_ci(CIKEY)를 실행하여 CUBE_INSTANCE
및 다른 테이블의 인스턴스를 삭제할 수 있습니다. delete_ci(CIKEY) 는 큐브 인스턴스를
매개변수로 취하고, 해당 큐브 인스턴스를 참조하는 BPEL 테이블의 모든 로우를 삭제하는 스토어드 프로시저입니다.
이와 같은 방법을 사용하여, 여러 도메인에 존재하는 손상된 인스턴스들을 삭제할 수 있습니다. 또 다수 인스턴스의
동시 삭제가 가능합니다. 이러한 두 가지 장점 때문에 실제로 PL/SQL이 운영 환경에서 자주 사용되고 있습니다.
아래 샘플 코드는 EJB를 이용하여 손상된 인스턴스를 조회하고 삭제하는 방법을 예시하고 있습니다.
WhereCondition where = WhereConditionHelper.whereInstancesStale();
IInstanceHandle[] instances = getLocator(domainId, domainPassword).listInstances(where);
for(int i=0; i<instances.length; i++){
instances[i].delete();
}
처음의 두 라인은 각 도메인 별로 모든 손상된 인스턴스의 IInstanceHandle 빈(bean)을 어레이 형태로
반환합니다. 그런 다음 IInstanceHandle.delete()을 실행하여 모든 인스턴스를 삭제할
수 있습니다. 이 코드은 모든 도메인을 포함하는 형태로 쉽게 확장될 수 있습니다.
오래된 인스턴스를 아카이브하고, 손상된 인스턴스 및 XML 메시지를 삭제함으로써 테이블의 사이즈를 줄일 수 있습니다. 하지만
테이블의 truncate, rebuild 작업을 수행하지 않고 로우의 삭제 작업만을 수행하는 경우에는 테이블의 여유
공간이 반환되지 않는다는 문제가 있습니다.
아래 커맨드를 이용하여 여유 공간을 확보할 수 있습니다. Dehydration Store의 다른 테이블에 대해서도 같은
방법으로 작업할 수 있습니다.
alter table cube_scope enable row movement;
alter table cube_scope shrink space compact;
alter table cube_scope shrink space;
alter table cube_scope disable row movement;
또 테이블의 용량이 지나치게 커지는 것을 막기 위해 PCTFREE, PCTUSED, PCTVERSION 매개변수를
조정할 수도 있습니다.
마지막으로, 런타임 시점에 실패한 인스턴스를 처리하는 방법을 알아 보겠습니다.
실패한 인스턴스의 재실행 BPEL 프로세스가 실패하는 이유에는 여러
가지가 있습니다. 잘못된 입력이 제공되었을 수도 있고, 프로세스 설계가 잘못되었을 수도 있으며, 또는 외부 애플리케이션의
접속이 불가능한 때문일 수도 있습니다. 어떤 경우든, 프로세스의 실행은 성공적으로 완료되지 못하며 ‘fault’ 상태로
종료됩니다. 설계상의 문제로 프로세스가 실패한 경우에는 프로세스 설계를 수정하고 BPEL 프로세스의 deploy 작업을
다시 수행해야 합니다.
하지만 입력의 문제 또는 외부적인 문제(네트워크 장애, 외부 애플리케이션의 장애)로 인해 프로세스가 실패한 경우,
문제가 해결된 이후에 프로세스를 다시 재실행하기를 원할 수 있습니다. 또 기존에 입력된 값을 그대로 이용하여 프로세스를
재실행하는 것이 가장 이상적일 것입니다.
유닛 테스트 및 통합 테스트를 위한 BPEL Process의 테스트 케이스 생성 및 실행을 지원하는 유틸리티인 BPELTest(10.1.3
및 이후 버전)를 이용하면 이러한 목표를 달성할 수 있습니다. BPELTest는 파트너 호출(partner invocation)의
시뮬레이션, assertion의 실행과 같은 기능을 지원하며 테스트 결과에 대한 상세한 정보를 제공합니다. (자세한
정보는
BPELTest webinar 자료를 참고하시기 바랍니다.)
BPELTest는 감사 로그로부터 테스트 케이스를 생성하는 기능을 지원합니다 (이 기능을 Automatic Test Generation이라
부르기도 합니다). 예를 들어, 외부 애플리케이션이 다운되어 프로세스 인스턴스가 실패한 경우를 생각해 봅시다. 이
경우, 외부 애플리케이션이 다시 온라인 상태에 된 후 이전과 동일한 시나리오를 사용하여 프로세스를 재실행하는 것이
가장 이상적일 것입니다.
하지만 이러한 작업은 무척 번거로울 수 있습니다. 프로세스 소유자에 의해 통제 불가능한 외부 조건을 감안해야 하기
때문입니다.
그 대신 BPELTest를 이용하여 실패한 인스턴스의 감사로그로부터 기본적인 테스트 케이스를 생성할 수 있습니다.
생성된 테스트 케이스에는 실패한 인스턴스와 동일한 파트너를 이용한 에뮬레이션 커맨드가 포함되어 있습니다. 잘못된 데이터가
입력된 경우에는 테스트 케이스에서 데이터를 수정할 수 있습니다. 또 외부 애플리케이션의 연결 문제가 원인이었다면,
애플리케이션이 다시 온라인 상태로 돌아온 후에 테스트 케이스를 재실행하기만 하면 됩니다.
결론 지금까지 살펴본 것처럼, BPEL Dehydration Store에
대해 BPEL Process Manager AP, EJB 또는 PL/SQL을 실행하여 BPEL 운영 환경의 관리 작업을
자동화할 수 있습니다. 사용되는 BPEL 프로세스의 증가하면 할수록, 일상적인 업무를 자동화하고 잠재적인 문제에 사전예방적으로
대처하기 위한 전략의 필요성 또한 강조되어야 합니다.
Stany
Blanvalet 은BPEL / J2EE 컨설턴트입니다. Stany는 과거 Java EE 설계 전문가로 일하면서,
Belgacom의 BPEL 기반 DSL 프로비저닝 애플리케이션을 구현하고 운영한 경험을 보유하고 있습니다. Stany는
Oracle BPEL Process Manager의 오픈소스 JMX 모니터링 툴인 jaisy-OrabpelInterface
프로젝트에 참여하고 있기도 합니다.
여러분의
의견을 보내 주십시오. |