Akka classic에서 소스를 보다보면 붕~뜬 느낌이 들곤 합니다.
마치 Springframework에서도 내부적으로 동작하는 것들이 많은데(ex. DispatcherServlet) 이것을 알지 못하면 이해가 어렵습니다.
그러므로 Akka 프레임워크에서 내부적으로 동작하는 액션을 파악해야합니다.
1. Client가 Akka HTTP를 통해 접근
2. 메시지가 들어오고 Route를 통해 어떤 Actor에게 보낼지 결정 합니다.
3. Route핸들러에서 서비스 Actor에 메시지를 보냅니다.
3.1 ask(Future의 리턴이 있는) 메소드를 사용하게 되면
4. Akka는 내부적으로 Future를 리턴 시킵니다.
5. 또한 내부적으로 한쌍인 비어있는 promise와 replyTo Actor를 메시지에 담아 MailBox(Queue)에 넣습니다.
6. Akka는 MailBox에 넣을때 스케줄을 생성하는데 이 스케줄에 따라 Dispatcher가 MailBox에 있는 메시지를 꺼내서
해당 Actor의 recive를 수행합니다.
7. Actor가 로직을 수행 합니다.
7.1 이때 Actor는 메시지 당 단일 쓰레드로 처리 합니다.(ForkJoinPool)
8. 그리고 sender() ! value를 통해 호출했던 Actor의 promise에 메시지를 채웁니다.
8.1 promise가 채워지면 promise와 한쌍인 Future는 완료가 됩니다.
8.2 완료가 되면 Akka 내부적으로 onComplete가 실행 됩니다.(CallBack)
참고사항
Future&Promise
- Future = 비동기적으로 돌고 있는 작업의 결과를 담는 Promise(값 또는 예외)
- Promise = 언젠가 값 줄께! 하고 약속하는 빈 상자
-
- Promise와 Future는 한쌍!
- Promise가 값을 채우면 Future에서도 그 값을 볼수 있음.
- Promise가 값을 채우면 Future가 완료된다.
- ExecutionContext가 실제 실행을 담당하고, 값이 준비되면 Future가 콜백으로 알려줍니다.
implicit val executionContext = system.dispatcher
// 실제 실행을 담당! - 쓰레드풀로 뒤에서 돌려줌(큐에서 꺼내서 액터 실행!)
// default-ForkJoinPool
ask호출 시(registry.ask(message))
- 내부적으로 Promise와 임시 replyTo Actor를 만듭니다.
- message와 함께 응답은 이쪽으로 보내라(replyTo)를 포함시켜 액터로 전달
- 즉, Dispatcher가 메시지를 꺼내 액터의 receive를 실행 → 액터 로직이 끝나면 sender() ! value
- 여기서 sender()는 ask가 전달한 임시 replyTo 액터
- replyTo 액터가 value를 받으면 아까 만든 Promise에 값을 채웁니다. 즉, Future가 완료 됩니다.
- 여기서 sender()는 ask가 전달한 임시 replyTo 액터
그리고 분산된 데이터들에 대한 관리가 필요한데 중요한 개념이 CRDT입니다.
Akka Classic Framework에서는 ORSet이라는 것을 제공 합니다.
분산된 데이터들을 충돌없이 사용하기 위함 입니다.
Akka Classic Distributed Data
- Replicator = Akka Distributed Data에서 데이터를 관리/동기화하는 핵심 액터.
- ClusterBoxRegistry 같은 레지스트리 액터가 내부적으로 ORSet[Box] 같은 CRDT
- CRDT: Conflict-free Replicated Data Type(충돌없는 분산 데이터 타입)
- ORSet (Observed-Remove Set) : Akka Distributed Data에서 많이 쓰는 CRDT 중 하나
- 집합(Set)인데, 동시에 추가(add)와 삭제(remove)가 일어나도 안전하게 합칠 수 있음!
- 왜 필요한가?
- 예를들어 서버A에서 add("teri") / 서버B에서 remove("teri") 이게 동시에 일어나면 teri가 있어야할까요? 없어야할까요?
- 일반 Set이라면 충돌이 나지만 ORSet은 충돌이 일어나지 않음.
- 추가할 때 그냥 "teri"만 넣는게 아니라 "teri"에 tag를 붙여서 저장 함.
- ex) "teri#A1"
- 삭제는 알고 있는 tag로만 삭제를 합니다. 즉, 아직 전파가 안된 #A1은 삭제 할 게 없습니다.
- 결론적으로 merge할 때는 "teri#A1" 만 있습니다.(서버 A, B 합집합)
- 추가할 때 그냥 "teri"만 넣는게 아니라 "teri"에 tag를 붙여서 저장 함.
- Box 추가/수정/삭제 요청이 각 노드에 흩어져도, 결국 모든 노드의 Box 상태가 동일하게 수렴
- HBase, MySQL은 DB로 사용, CRDT 레지스트리는 빠른 조회용, 동기화된 클러스터 캐시 역할을 함
'Data Platform > Akka' 카테고리의 다른 글
Akka HelloWorld(Akka HTTP + Akka Actor연동) (2) | 2025.04.15 |
---|---|
Akka Classic 뽀개기_Actors(1~4. Actor API) (1) | 2025.04.10 |
Akka에서 Actor 생성 시 금지하는 방식 (0) | 2025.03.27 |
Akka Classic 뽀개기_Overview (0) | 2025.03.26 |
Akka Classic (0) | 2025.03.25 |