1. 개요
client/server환경에서는 client의 request는 요청이 되면 바로 처리되므로,
online이고 연결된 작업이라고 볼 수 있다. 이러한 모델은 다음 작업을 진행하기 전에 처리한 작업에 대한 결과를 얻어서 이용하는 경우에 적당하다.
그러나 이러한 경우 어플리케이션이 항상 사용가능한 상태이어야 하기 때문에 network문제 등이 발생하는 경우 전체 어플리케이션이 모두 사용할 수 없게 되는 문제가 발생할 수 있다.
Queuing 기법은 프로그램들간의 disconnected/deferred communication으로 client/server환경과는 다른 요구사항에 적용되어질 수 있다. 이 방법을 이용하면 생산자 역할을 하는 프로그램은 queue에 request를 넣고 소비자 역할의 프로그램이 queue의 request를 꺼내 처리하게 된다. Oracle8에서는 이러한 queuing 기법을 기존의 TP-monitor나 다른 message-oriented middleware를 사용하지 않고 직접 사용가능하도록 하고 있다.
여기에서는 이러한 Oracle8에서 제공하는 advanced queuing에 대해서 간단한 개념과 예제를 제시한다. 여기에 적힌 예제는 oracle8 8.0.4와 8.1.4에서
성공적으로 수행되었다.
2. Advanced Queuing이란?
(1) Message
message란 queue에 들어가고 꺼내지는 정보의 가장 작은 단위이다. 이것은 raw type이나 object type인 user data (payload)와 priority 등의 추가적인 제어 정보를 담고 있는 meta data로 구성되어 있다. 하나의 메시지는 오직 하나의 queue에만 위치할 수 있으면 ENQUEUE procedure에 의해 queue에 들어가고 DEQUEUE procedure에 의해 queue에서 읽혀진다.
(2) Queue
queue는 메시지들의 저장 장소라고 할 수 있다. User queue와 exception queue라는 두가지 type이 존재하는데 이 중 user queue가 정상적인 message 처리를 위한 것이고 오류로 인해 제대로 처리되지 못한 메시지는 exception queue로 전달된다.
데이타베이스내에 생성될 수 있는 queue의 숫자에는 제한이 없으며, DBMS_AQADM package에 의해서 생성/변경/시작/멈춤/삭제되어 질 수 있다.
(3) Queue Tables
queue는 queue table에 저장되어진다. 각각의 queue table은 하나의 데이타베이스 테이블로 구성되며 하나 이상의 queue들을 포함한다. 각각의 queue table에는 하나의 default exception queue이 존재하며 DBMS_AQADM package를 이용하여 생성할 수 있다.
(4) Agents
agent는 queue user로 producer와 consumer 두가지 type이 있다. producer는 message를 queue에 전달하는데 이것을 enqueuing이라고 하고, consumer가 queue에서 message를 읽는 것을 dequeuing이라고 한다. 여러명의 producer와 consumer가 하나의 queue를 사용할 수 있으며 하나의 agent는 name, address, protocol에 의해 구분되다. 그런데 이 agent는 실제 database상의 user는 아니며 실제로는 application혹은 program이라고 생각할 수 있다.
3. 예제
advanced queuing을 사용하기 위해서는 먼저 catqueue.sql을 sys user에서 수행하여야 하는데 이것은 catproc.sql에서도 호출되도록 되어 있으므로 install당시 이미 수행되어져 있는 것이 정상이다.
(1) setup.sql
(2) enq.sql
(3) deq.sql
set serveroutput on
declare
dequeue_options dbms_aq.dequeue_options_t;
message_properties dbms_aq.message_properties_t;
message_handle raw(16);
message scott.scott_mesg;
begin
dequeue_options.consumer_name := 'app01';
dequeue_options.wait := 2;
dbms_aq.dequeue (queue_name => 'SCOTT.AS_Q',
dequeue_options => dequeue_options,
message_properties => message_properties,
payload => message,
msgid => message_handle );
dbms_output.put_line('message1 : ' || message.m1 || ',
message2 : ' || message.m2);
end;
/
SQL> @enq
Message enqueued.
PL/SQL procedure successfully completed
SQL> @deq
message1 : Hello !, message2 : World !!!
PL/SQL procedure successfully completed.
(1) setup.sql
connect sys/manager
create user scott identified by tiger
default tablespace users
temporary tablespace temp;
grant connect, resource, aq_administrator_role to scott;
execute dbms_aqadm.grant_type_access('scott');
grant execute on dbms_aq to scott ;
grant execute on dbms_aqadm to scott;
connect scott/tiger
create type scott_mesg as object (m1 varchar2(10), m2 varchar2(10));
/* 기존 환경 삭제 */
exec dbms_aqadm.stop_queue(queue_name =>'SCOTT.AS_Q',wait=>FALSE);
exec dbms_aqadm.drop_queue(queue_name => 'SCOTT.AS_Q');
exec dbms_aqadm.drop_queue_table(queue_table=>'SCOTT.AS_TABLE', force=>TRUE);
/*생성 및 구동 */
exec dbms_aqadm.create_queue_table
(queue_table => 'SCOTT.AS_TABLE',
queue_payload_type=> 'scott.scott_mesg',
storage_clause => 'storage (initial 1m next 1m pctincrease 0 )',
multiple_consumers=> TRUE,
comment => 'demo queue table' );
exec dbms_aqadm.create_queue (queue_name => 'SCOTT.AS_Q',
queue_table => 'SCOTT.AS_TABLE',
comment => 'demo queue');
exec dbms_aqadm.start_queue (queue_name => 'SCOTT.AS_Q');
create user scott identified by tiger
default tablespace users
temporary tablespace temp;
grant connect, resource, aq_administrator_role to scott;
execute dbms_aqadm.grant_type_access('scott');
grant execute on dbms_aq to scott ;
grant execute on dbms_aqadm to scott;
connect scott/tiger
create type scott_mesg as object (m1 varchar2(10), m2 varchar2(10));
/* 기존 환경 삭제 */
exec dbms_aqadm.stop_queue(queue_name =>'SCOTT.AS_Q',wait=>FALSE);
exec dbms_aqadm.drop_queue(queue_name => 'SCOTT.AS_Q');
exec dbms_aqadm.drop_queue_table(queue_table=>'SCOTT.AS_TABLE', force=>TRUE);
/*생성 및 구동 */
exec dbms_aqadm.create_queue_table
(queue_table => 'SCOTT.AS_TABLE',
queue_payload_type=> 'scott.scott_mesg',
storage_clause => 'storage (initial 1m next 1m pctincrease 0 )',
multiple_consumers=> TRUE,
comment => 'demo queue table' );
exec dbms_aqadm.create_queue (queue_name => 'SCOTT.AS_Q',
queue_table => 'SCOTT.AS_TABLE',
comment => 'demo queue');
exec dbms_aqadm.start_queue (queue_name => 'SCOTT.AS_Q');
(2) enq.sql
set serverout on
declare
enqueue_options dbms_aq.enqueue_options_t;
message_properties dbms_aq.message_properties_t;
message_handle raw(16);
recipients dbms_aq.aq$_recipient_list_t;
message scott.scott_mesg;
begin
enqueue_options.visibility := DBMS_AQ.IMMEDIATE;
message:= scott_mesg('Hello !', 'World !!!');
recipients(1) := sys.aq$_agent('app01','SCOTT.AS_Q',NULL);
message_properties.recipient_list := recipients;
dbms_aq.enqueue (queue_name => 'scott.as_Q',
enqueue_options => enqueue_options,
message_properties => message_properties,
payload => message,
msgid => message_handle );
dbms_output.put_line('Message enqueued.');
end;
/
declare
enqueue_options dbms_aq.enqueue_options_t;
message_properties dbms_aq.message_properties_t;
message_handle raw(16);
recipients dbms_aq.aq$_recipient_list_t;
message scott.scott_mesg;
begin
enqueue_options.visibility := DBMS_AQ.IMMEDIATE;
message:= scott_mesg('Hello !', 'World !!!');
recipients(1) := sys.aq$_agent('app01','SCOTT.AS_Q',NULL);
message_properties.recipient_list := recipients;
dbms_aq.enqueue (queue_name => 'scott.as_Q',
enqueue_options => enqueue_options,
message_properties => message_properties,
payload => message,
msgid => message_handle );
dbms_output.put_line('Message enqueued.');
end;
/
(3) deq.sql
set serveroutput on
declare
dequeue_options dbms_aq.dequeue_options_t;
message_properties dbms_aq.message_properties_t;
message_handle raw(16);
message scott.scott_mesg;
begin
dequeue_options.consumer_name := 'app01';
dequeue_options.wait := 2;
dbms_aq.dequeue (queue_name => 'SCOTT.AS_Q',
dequeue_options => dequeue_options,
message_properties => message_properties,
payload => message,
msgid => message_handle );
dbms_output.put_line('message1 : ' || message.m1 || ',
message2 : ' || message.m2);
end;
/
SQL> @enq
Message enqueued.
PL/SQL procedure successfully completed
SQL> @deq
message1 : Hello !, message2 : World !!!
PL/SQL procedure successfully completed.