이야기박스

LMAX Architecture - Disruptor 본문

Computer & Data/Big Data

LMAX Architecture - Disruptor

박스님 2018. 10. 10. 19:11
반응형

공식 문서를 번역(구글 번역기)하고 정리 하였습니다.

Introduction

Disruptor의 목적

동일 프로세스 내, 스레드 간의 데이터(메시지, 이벤트 등..)를 이동시키는 것 


일반적으로 Java의 BlockingQueue와 유사하지만 다음과 같은 차이가 있습니다.

  • Multicast events to consumers, with consumer dependency graph.
  • Pre-allocate memory for events.
  • Optionally lock-free.


Core Concepts
Disruptor를 이해하기 위해, 여기서 사용되는 용어를 정리해보았습니다.

Ring Buffer

이런 형식의 버퍼입니다. 버퍼 크기는 제한이 있지만, 무한 순환이 가능한 구조입니다.
Disruptor의 핵심이었지만, 3.0 이후 버전으로부터는 저장 & 업데이트 용도로 주로 사용되고 있습니다.

ring buffer도 일종의 queue라서 FIFO를 완벽하게 이행하고 있습니다. 
다수의 생산자가 접근하더라도 들어온 순서에 따라서 커서의 위치를 변환시키며 소비자가 값을 소비하게 합니다.

Sequence
Disruptor가 구성요소들의 위치를 식별하는데 사용하는 방법입니다.
각 소비자(EventProcessor)는 disruptor와 마찬가지로 sequence를 유지, 관리합니다.
Sequence는 AtomicLong의 많은 기능을 지원하며, 차이점은 다른 값과의 잘못된 공유를 방지하는 기능을 가지고 있다는 점입니다.

Sequencer
Disruptor의 진짜배기 핵심입니다.
Single & Multi Producer를 통해서 빠르고 정확하게 데이터를 전달하는 모든 concurrent 알고리즘을 구현합니다.

Sequence Barrier
Sequencer에 의하여 생성되며, Main Published Sequence에 대한 참조를 가지고 소비자가 처리할 수 있는 이벤트가 있는지 결정하는 로직들을 가지고 있습니다.

Wait Strategy
Producer는 이벤트를 만들면 Disruptor에 배치를 하는데, Wait Strategy는 Consumer가 이를 어떻게 기다릴 것인지 결정합니다.

Event
데이터가 Producer로부터 Consumer로 전달되는 것을 뜻합니다. 특별한 코드 표현은 없습니다. 전적으로 사용자의 재량에 달려있다고 하네요.

EventProcessor
Disruptor의 이벤트를 다루는 메인 루프입니다. 그리고 Consumer의 Sequence에 대한 소유권을 가지고 있습니다.
BatchEventProcessor라는 단일 표현이 있는데, 이것은 루프를 효율적으로 구현하며 EventHandler 인터페이스의 콜백이 가능하게 합니다.

EventHandler
사용자가 구현하고 Disruptor의 Consumer를 나타내는 인터페이스 입니다.

Producer
이벤트를 큐에 넣기 위해 Disruptor를 호출하는 사용자코드입니다. 

Disruptor

Multicast Event

위에서 언급했듯이 큐와 disruptor의 가장 큰 차이 중 하나입니다. 큐가 단일 소비자에게 단일 이벤트를 전달하는 것과 다르게, disruptor는 여러 소비자가 모든 이벤트에 대한 정보를 받습니다.


Disruptor의 동작은 동일한 데이터에 대해 여러 병렬 작업을 독립해야 하는 경우 사용합니다.

LMAX의 3가지 작업

- journaling : 입력 데이터를 영구 저널 파일에 쓰기

- replication : 입력 데이터를 다른 머신으로 전송

- business logic : 실제 프로세스 동작 부분


위의 그림에서 보면, JournalConsumer, ReplicationConsumer, ApplicationConsumer가 병렬로 동작하는 것을 확인할 수 있습니다.


Consumer Dependency Graph

실제 동작을 위해서는, 소비자들간의 조정이 필요합니다.


gating

journaling & replication 소비자가 작업을 완료하기 전까지, 다른 business logic 소비자가 동작하지 않도록 하는 것입니다.


gating 동작이 일어나는 시기

- producer들이 consumer들보다 overrun하지 않도록 할 때 --> RingBuffer.addGatingConsumers()를 동작함

- SequenceBarrier를 구성하여 구현될 때


위 그림의 예에서 JournalConsumer와 ReplicationConsumer는 자유롭게 병렬 실행이 가능합니다. ApplicationConsumers 시퀀스는 다른 JournalConsumer나 ReplicationConsumer보다 작아야 합니다.

Event Preallocation

disruptor의 또다른 목표 중 하나는 짧은 지연시간에서 사용할 수 있도록 하는 것이었습니다. gc 동작을 줄이기 위해 disruptor에서는 필요한 공간을 미리 할당하는 preallocation 방식을 사용하였습니다.

Optionally Lock-free

짧은 대기 시간을 추진하기 위하여 무잠금 알고리즘을 지향한다고 하네요.


참조

disruptor 공식 문서(git)

반응형