2019년 4월 2일 화요일

이벤트-드리븐 아키텍쳐 (Event-Driven Architecture)

TCP 연결을 처리하는 방식에서 비교되는 개념으로 Thread-Based Architecture와 Event-Driven Architecture가 있다. 이 글에선 Event-Driven Architecture에 대해서 정리하고자 한다.

이벤트-드리븐 아키텍쳐의 구동방식은 일반적으로 아래의 두 가지 형태로 구분된다.


1. 이벤트 리스너 방식.
  대상 객체의 특정 이벤트 리스너에 이벤트 처리 로직을 가진 이벤트 메서드를 등록하는 방식. 객체의 이벤트가 발생할 때 이벤트 처리 스레드에서 등록된 메서드를 수행한다. 등록된 메서드가 없으면 이벤트는 씹힌다. 대부분의 UI 프레임워크가 쓰는 방식이다.


2. 이벤트 큐를 이용하는 방식.
  이벤트 발생 객체(Event Emitter)는 이벤트를 큐에 쌓고, 이벤트를 처리하는 객체(Event Loop)는 큐에 입력된 이벤트가 있을 때 이벤트를 꺼내 이벤트를 실행하는 방식. 위의 방법보다 일반적이나 구현 난이도는 높다.

  이 방법에선 구현 목적에 따라 이벤트 처리 스레드를 하나로 둘 수도 있고, 여러 개로 둘 수도 있다. trade-off가 있다.

  2.1 싱글 스레드 기반 : 이벤트를 순서대로 처리할 수 있다. 다중 코어 CPU의 자원을 효과적으로 사용할 수 없다.
  2.2 멀티 스레드 기반 : 다중 코어 CPU 자원을 효과적으로 사용할 수 있다. 이벤트 처리 순서를 보장할 수 없다. 이벤트 큐에 대한 스레드 경합이 발생한다.

→ Netty 같은 I/O 프레임워크에선 채널(하나의 연결) 별로 전용 이벤트 큐를 할당시키는 방식을 채택한다. 전체 메시지의 처리 순서를 보장할 순 없어도 특정 채널에서 발생하는 메시지의 처리 순서는 보장해준다.
(채널과 큐의 관계는 1:1은 아니고, N:1의 관계.)

두 번째 방식을 좀더 구체화한 아키텍쳐 패턴으로 Reactor Pattern이 있다.

Reactor Pattern은 이벤트에 반응하는 객체(Reactor)가 이벤트가 발생할 때 Event Handler에게 전달해주고, Event Handler는 알맞은 method를 사용해 처리하는 구조를 갖는다.

Reactor가 계속해서 이벤트를 Dispatching 할 수 있게 해줘야 하므로 Event Handler는 새로운 스레드(스레드 풀)에서 실행되는 것이 일반적이다.

Reactor Pattern은 아래 링크에서 친절하게 설명되어 있다.
http://jeewanthad.blogspot.com/2013/02/reactor-pattern-explained-part-1.html

The beauty of non blocking architecture is that we can write the server to run in a single Thread while catering all the requests from clients. Just forget about the Thread pool for a while. Naturally when concurrency is not used to design a server it should obviously be less responsive to events. In this scenario when the system runs in a single Thread the Reactor will not respond to other events until the Handler to which the event is dispatched is done with the event. Why? Because we are using one Thread to handle all the events. We naturally have to go one by one. 
We can add concurrency to our design to make the system more responsive and faster. When the Reactor dispatches the event to a Handler, it can start the Handler in a new Thread so that the Reactor can happily continue to deal with other events. This will always be a better design when performance is concerned. To limit the number of Threads in the system and to make things more organized, a Thread pool can be used.

댓글 없음:

댓글 쓰기