Site Search :
Standard Enterprise XML Methodology Pattern Setting Tunning Other
Article Contributors
GuestBook
Javapattern Maven
XSourceGen Dev
JetSpeed Test
JLook Image
jLook Family Site


NIO Reactor Pattern의 사용
 
분산환경 시스템에서 구축되는 서버는 클라이언트의 동시다발적인 요청을 어떻게 처리해야할까요? 글쎄요. 그것을 처리하기 위한 여러가지 방법중에 하나인 Reactor Pattern 을 소개합니다. 그리고 NIO 에서 Reactor 를 어떻게 현실적으로 구현하고 있는지도 살짝 엿보기로 하죠. ( 2003/09/04 ) 264
Written by ienvyou - 최지웅
1 of 1
 
미리보기

분산환경 시스템에서 구축되는 서버는 클라이언트의 동시다발적인 요청을 어떻게 처리해야할까요?
글쎄요. 그것을 처리하기 위한 여러가지 방법중에 하나인 Reactor Pattern 을 소개합니다.
그리고 NIO 에서 Reactor 를 어떻게 현실적으로 구현하고 있는지도 살짝 엿보기로 하죠. 

▶스터디내용

- Reactor Pattern 을 이해한다.
- NIO 에서 Reactor Pattern 을 어떻게 구현했는지를 알아본다

1장 Reactor Pattern

문제점 분산환경의 서버들은 클라이언트들의 요청을 효율적으로 처리를 해야합니다. 하나의 요청을 처리시간이 좀 걸리는동안 다른 요청들을 대기시키는 한이 있어도 처리를 해야합니다. 처리속도는 최대한 빨리하고 대기시간은 최소한 해야만 좋은 서버겠죠. 아마도… 새로운 서비스들을 추가함에 있어서 기존의 코드들의 변동이 없어야 합니다. 그리고 병행처리나 동시처리 정책을 사용함에 있어서도 간단해야 합니다. ▶기본구조 POSA2 (Pattern Oriented Software Architecture 2) 에 이러한 문제점을 해결하기 위한것들중에 하나로 Reactor Pattern 을 설명해놨습니다. 기본적인 정의 내용을 보면 아래와 같습니다.
  1. Reactor 는 어플리케이션에 독립적인 이벤트 Demultiplexing 과 처리로직을 구현한다.
  2. Demultiplexing 은 하나의 전송통로로 입력받은 정보를 다중의 출력방법중 하나를 선택해서 출력하는 방식을 말합니다. 즉, Event Source 로부터 event 를 받아 Reactor 에 등록되어 있는 적절한 Event Handler 를 이용하여 처리하게 되는 방식입니다.
  3. 서로 다른 타입의 Event Handler 들은 각자의 서비스를 구현하고 있습니다.
  4. Acceptor 는 새로운 요청이 들어왔을 때 해당 요청을 처리할 수 있는 Event Handler 를 생성합니다.
작동순서 아래의 그림은 Reactor Pattern 의 구조 및 동작하는 방식을 도식화 한것입니다. 그림을 보고 순서를 설명드리겠습니다. [참고1] Reactor 동작 순서도 ① Reactor 를 생성합니다. ② Main Program 은 Accptor 들을 생성합니다. ③ 모든 생성된 Acceptor 들은 Reactor 에 그들이 담당할 event 종류와 함께 Reactor 에 등록합니다. ④ Event Source 는 새로운 event 가 발생할 때까지 listen 상태로 대기합니다. ⑤ 새로운 Connection event 가 Event Source 에 도착을 합니다. ⑥ Event Source 는 Reactor 를 notify 시킵니다. ⑦ Reactor 는 이 event 를 처리하기 위한 Acceptor 를 notify 시킵니다. ⑧ Acceptor 는 자신이 Control 하는 새로운 Event Handler 를 Thread 로 생성합니다. ⑨ 새로 생성된 Thread 를 그들이 담당할 event 종류와 함께 Reacotr 에 등록합니다. ⑩ 등록된 Thread 와 일치하는 event 가 발생한다고 가정합니다. ⑪ 이 event 를 처리하기 위해서 Reactor 를 통하여 해당 event 를 처리 가능한 모든 등록된 Evnet Handler 에게 event 를 전달하여 처리합니다. ▶장점 모든 서비스들은 각각 독립적으로 실행가능하다. 오랜 처리 시간을 요하는 많은 서비스들의 처리를 관리하는 Thread 관리가 전반적인 성능저하를 가져오지 않습니다. 그리고 새로운 서비스의 추가가 쉽습니다. Thread 관리가 쉽습니다. 지정된 Acceptor 를 통하여 요구에 따라 생성되어지기 때문입니다. 그리고 중앙 Thread Manager 에 의해서 유지되기 때문입니다. Connection 당 Thread 의 이동도 쉽습니다.

2장 NIO 에서의 Reactor Pattern 이용

NIO 에서의 Reactor 역할의 Selector NIO 에서 Reactor 의 역할을 하는 클래스가 있다. 이것이 바로 Selector 클래스이다. 1장에서 보았듯이 Reactor Pattern 에는 여러가지 필수 요소들이 있는데 그것은 Reactor, Acceptor, Event Handler 그리고 event 였다. ▶Selector Class 구조 Selector Class 는 내부적으로 3가지의 Key Set 을 가지고 있다. ①Key Set 하나의 Selector 에 등록되어진 channel 들을 대표하는 key 들의 집합이다. 여기서 chnnel 이라는 것은 Acceptor, Event Handler 들을 총칭하는것으로 보면 된다. keys() 라는 메서드를 이용하여 얻을수 있다. chnnel 의 register() method 를 이용한다. ②selected-key set select() 메서드에 의해서 얻어진 key 들의 집합이다. 이것의 위의 Key set 의 subset 이라 보면 되고, Selector 가 demultiplexing 을 하는 key 값들이라고 보면 된다. notify 시킨 event 를 처리하는 Event Handler (channel) 들의 key 값이다. selectedKeys() 라는 메서드를 이용하여 얻을 수 있다. ③cancelled-key set 취소된 key 들의 집합이다. 이것은 직접 접속이 불가능하다. cancel() method 에 의하거나 chnnel 을 close 하면 된다 ▶Reactor Pattern 을 이용한 NIO Package 코드 샘플 다음이 코드 샘플은 이민수씨가 제공한 소스를 가지고 설명을 합니다. 그리고 위의 그림을 변경한것을 다시 첨부합니다.

public void initServer() {
try { 
    // 1. Reactor 를 생성합니다.
    selector = Selector.open();
        // 2. Accptor 를 생성합니다
    serverSocketChannel = ServerSocketChannel.open();
    // 3. 모든 생성된 Acceptor 는 Reactor 에 그들이 담당할 event 종류와 함께 Reactor 에 
    등록합니다. 현재 OP_ACCEPT 는 클라이언트가 접속을 시도할때 발생하는 이벤트입니다.
    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    ......
    .....
}

public void startServer() {
try {
        while (true) {
    //  Event Source 는 새로운 event 가 발생할 때까지 listen
    상태로 대기합니다.
    // 새로운 Connection event 가 Event Source 에 도착을 합니다.
    // Event Source 는 Reactor 를 notify 시킵니다
            selector.select();
                        // selected-key set 을 추출
            Iterator it = selector.selectedKeys().iterator();
            while (it.hasNext()) {
            SelectionKey key = (SelectionKey) it.next();
           // 새로운 Connection event 가 Event Source 에 도착을 합니다
            // Event Source 는 Reactor 를 notify 시킵니다
        if (key.isAcceptable()) {
        // Reactor 는 이 event 를 처리하기 위한 Acceptor 를 
        notify 시킵니다
                ServerSocketChannel server = (ServerSocketChannel) key.channel();
                // Acceptor 는 자신이 Control 하는 새로운 Event Handler 를 Thread 로 생성합니다
                SocketChannel sc = server.accept();
                // 새로 생성된 Thread 를 그들이 담당할 event 종류와 함께 Reacotr 에 등록합니다.
                registerChannel(selector, sc, SelectionKey.OP_READ);
        
                // 등록된 Thread 와 일치하는 event 가 발생한다고 가정합니다
                } else if (key.isReadable()) {
                // 이 event 를 처리하기 위해서 Reactor 를 통하여 해당 
                event 를 처리 가능한 모든 등록된 Evnet Handler 
                에게 event 를 전달하여 처리합니다.
                service(key);
                }
// 이벤트 처리가 끝나면 대기상태로 가기전에 
//꼭 selected-key set 을 remove 해야한다. 그렇지 
//않으면 다음에 다시 notify 되더라도
//기존의 selected-key set 이 설정되어 있기때문에 
//오작동을 한다.
                it.remove();
                   }								
              }      
        } catch (Exception e) {
        } 
    }

[참고2] 참고1을 nio package class 와 mapping 이상으로 reactor에 대하여 알아보았다.
 
1
References
 
Copyright ⓒ 2003 www.javapattern.info & www.jlook.com, an jLOOK co.,LTD