- 원문영상
유튜브요약 by 릴리AI
이 컨텐츠는 액터 모델(Actor Model)과 도메인 주도 설계(DDD)를 활용하여 반응형 시스템(Reactive Systems)을 구축하는 방법에 대해 설명합니다. 특히, 멀티코어 프로세서 시대에 스레딩의 어려움을 극복하고 비동기 메시징을 통해 시스템의 응답성, 복원성, 탄력성을 향상시키는 액터 모델의 장점을 강조하며, DDD의 유비쿼터스 언어와 바운디드 컨텍스트 개념을 액터와 메시지에 적용하여 복잡성을 줄이고 도메인 모델을 효과적으로 구현하는 방법을 제시합니다.
1. 배우 모델과 도메인 주도 설계(DDD)의 개념과 역사 ( )
배우 모델은 1973년에 처음 설계된 오래된 개념으로, 20년 이상 전에 Yahoo와 Hotmail이 등장하기 전부터 존재함.
이 모델은 컴퓨팅과 소프트웨어 개발의 장기적인 방향성을 해결하기 위해 만들어졌으며, 객체지향 프로그래밍과 거의 같은 시기에 등장함.
오늘날 클라우드의 동시성문제 해결을 위해 다시 관심을 받고 있으며, Intel, Samsung, Walmart, PayPal, Norwegian Cruise Lines 등 많은 기업이 Akka와 함께 배우 모델을 도입하여 분산 반응형 시스템을 구축하고 있음.
배우 모델은 단순성과 실패 처리, 탄력성, 반응성 유지에 뛰어나며, 도메인 주도 설계와 결합하여 시스템을 효율적으로 확장하는 데 유리함.
2. 배우 모델의 핵심 원리와 특징 ( )
배우는 메시지 기반으로 작동하며, 비차단(non-blocking) 방식으로 메시지를 주고받음.
송신자는 메시지를 보내고 즉시 다음 작업으로 넘어가며, 수신자는 별도의 스레드에서 메시지를 처리함.
메시지는 비동기적으로 전달되어, 송신자는 메시지를 큐에 넣고 바로 작업을 계속할 수 있음.
배우는 객체와 유사하지만, 메시지 전달과 비동기 처리라는 추가 메커니즘이 있음.
메시지 전달 후, 수신 배우는 별도의 스레드에서 메시지를 처리하며, 여러 배우 간의 실행 컨텍스트 전환이 빈번하게 발생함.
배우는 계층적 구조를 지원하며, 부모 배우는 자식 배우의 실패를 감시하고 재시작하는 역할 수행 가능.
3. 배우 모델이 반응형 시스템에 적합한 이유 ( )
반응형 시스템의 네 가지 특성: 응답성, 탄력성, 확장성, 메시지 기반.
배우는 메시지 전달로 인해 시스템이 빠르게 응답하며, 사용자 요구에 신속히 대응 가능.
실패 시 부모 배우가 장애를 감지하고 재시작하는 구조로, 시스템의 탄력성을 높임.
메시지 기반구조는 시스템의 확장성과 유연성을 지원하며, 클라우드와 IoT 환경에서도 적합함.
수많은 코어와 빠른 저장장치, 클라우드인프라를 활용하여 높은 확장성과 성능 확보 가능.
배우는 멀티코어 환경에서 병렬 처리를 자연스럽게 지원하며, 복잡한 동기화 문제를 피할 수 있음.
비동기 메시지 전달로 인해 지연( latency)을 자연스럽게 수용하며, 분산 시스템의 장애와 네트워크 지연에 강함.
적은 서버 수로도 높은 성능과 확장성을 유지할 수 있어 비용 효율적임.
4. 배우 시스템의 구조와 확장성 ( )
현대 서버는 수백 개에서 수천 개의 코어를 지원하며, 하나의 서버에서 수백만 개의 배우를 운영 가능.
배우 시스템은 복잡한 계층 구조를 단순화하여, 컨트롤러와 도메인 모델 간 메시지 전달로 아키텍처를 간소화함.
배우는 수평적 확장에 유리하며, 수많은 배우를 통해 대규모 시스템을 구성할 수 있음.
하나의 배우는 여러 시스템 또는 마이크로서비스와 연동 가능하며, 이벤트와 메시지로 전체 시스템을 구성하는 데 적합함.
5. 도메인 주도 설계(DDD)와 배우 모델의 결합 ( )
도메인 주도 설계는 유비쿼터스 언어와 경계 컨텍스트를 중심으로 시스템을 모델링하는 방법.
경계 컨텍스트 내에서 배우는 도메인 객체 역할을 하며, 메시지 교환은 도메인 언어의 일부임.
이벤트 스토밍을 통해 복잡한 비즈니스 요구를 빠르게 모델링하고, 배우를 통해 명확한 경계와 책임을 정의 가능.
이벤트와 명령 메시지를 활용하여, 시스템의 일관성과 반응성을 높임.
배우와 메시지 기반설계는 빠른 변화와 비즈니스 요구에 유연하게 대응하는 데 유리함.
6. 이벤트 스토밍과 시스템 설계 ( )
이벤트 스토밍은 복잡한 시스템을 이해하고 설계하는 기법으로, 비즈니스 이벤트를 중심으로 모델링.
큰 그림 모델링과 설계 수준 이벤트 스토밍으로 나뉘며, 비즈니스 전문가와 개발자가 함께 참여하여 빠른 모델링 가능.
이벤트는 명령과 상태 변화의 핵심이며, 배우는 명령을 받고 이벤트를 발생시켜 시스템의 상태를 변경.
이벤트는 영속 저장소에 비동기 저장되며, 여러 시스템이 이를 구독하여 전체 시스템을 구성.
배우는 일관성 경계와 트랜잭션 경계를 제공하며, 이벤트 기반 아키텍처와 자연스럽게 결합됨.
7. 배우를 활용한 도메인 모델 구현 방법 ( )
배우는 불변 상태 객체를 유지하며, 명령 처리 후 상태를 변경하는 방식으로 설계.
Akka의 영속성(persistence) 기능을 활용하여, 이벤트를 저장하고 복구 가능.
이벤트는 시스템 간 메시지로 전달되어, 여러 마이크로서비스 또는 경계 컨텍스트 간 통신을 지원.
이벤트 기반 시스템은 전체 시스템 설계에 적합하며, 확장성과 유연성을 높임.
도메인 이벤트를 통해 시스템 전체의 일관성과 반응성을 확보할 수 있음.
8. 도메인 주도 설계와 배우 모델의 실무 적용 ( )
이벤트를 통해 시스템 전체를 모델링하며, 여러 시스템 또는 마이크로서비스 간 메시지 교환 가능.
이벤트는 높은 성능의 버스 또는 토픽에 게시되어, 여러 수신자가 구독하여 처리.
전체 시스템을 하나의 서비스가 아닌, 여러 서비스와 연동된 시스템으로 설계 가능.
이벤트 소싱과 CQRS와 결합하여, 빠른 개발과 유연한 확장 지원.
Lightbend의 자료와 책들을 통해 배우 모델과 DDD를 실무에 적용하는 방법 학습 가능.
9. IoT와 배우 모델의 미래 활용 가능성 ( )
IoT 기기는 에너지 제한이 크기 때문에, 메시지 기반비동기 통신이 적합함.
제한된 전력으로 메시지 수신보다 발행(publish)하는 방식이 효율적임.
배우 시스템을 IoT 디바이스에 적용하면, 필요할 때만 메시지를 받고, 상태 보고는 PubSub로 수행 가능.
IoT와 배우 모델 결합은 에너지 효율적이고 확장 가능한 시스템 설계에 유리하며, 사례 연구도 존재함.
앞으로 IoT와 배우 모델의 결합은 실시간 의사결정과 개인화 서비스에 중요한 역할을 할 것으로 기대됨.
10. 결론 및 참고 자료 ( )
Von Vernon은 배우 모델과 도메인 주도 설계, 반응형 시스템의 결합이 미래 소프트웨어 개발에 핵심임을 강조.
Lightbend와 다양한 책, 사례 연구, 컨퍼런스 등을 통해 배우 모델과 DDD를 실무에 적용하는 방법을 배울 수 있음.
참석자들은 관련 자료와 링크를 통해 더 깊이 학습하고, 배우 모델을 활용한 시스템 설계에 도전할 수 있음.
액터 모델이 반응형 시스템에서 도메인 주도 설계(DDD)와 함께 사용될 때 어떤 이점을 가지는가?
액터 모델은 메시지 기반, 비차단 방식으로 설계되어 반응성, 탄력성, 복원성을 지원하며, 멀티코어 환경에서 높은 처리량을 제공하고 분산 시스템의 지연 시간을 자연스럽게 처리할 수 있게 한다.
💡 액터 모델이 기존 객체 지향 모델과 다른 점은 무엇인가?
항목 | 액터 모델 | 객체 지향 모델 |
메서드 호출/메시지 전송 | 비차단(Asynchronous) 메시지 전송 | 차단(Blocking) 메서드 호출 |
예외 처리 | 수퍼비전 계층에서 처리 | 클라이언트가 처리하거나 상위 컴포넌트로 전달 |
동시성 처리 | 메시지 큐를 통해 순차 처리, 상태 공유 없음 | 스레드 간 상태 공유 및 잠금 필요 |
이 웨비나는 액터 모델과 도메인 주도 설계(DDD)를 반응형 시스템에 적용하는 방법을 설명합니다. 액터 모델은 1973년에 처음 설계되었으며, 클라우드 동시성문제를 해결하는 데 유용합니다. 액터는 메시지 기반, 논블로킹방식으로 설계되어 처리량(throughput)을 향상시키고, 장애를 graceful하게 처리하여 시스템의 resilience와 responsiveness를 유지합니다. 또한, 액터는 시스템이 elastic하게 확장 및 축소되도록 지원하여 인프라 및 하드웨어 footprint를 최소화합니다. 이 웨비나는 액터 모델이 소프트웨어 개발의 미래에 중요한 이유와 DDD와 함께 사용할 때의 이점을 강조합니다.
1. 🎯 액터 모델과 도메인 주도 설계의 결합
액터 모델은 1973년 처음 설계되어 20년 이상 된 기술로, 클라우드경쟁성과 실패 처리 능력을 향상시켜 현대 반응형 시스템에 적합하다.
현대 기업들은 액터 모델을 이용하여 분산된 반응형 시스템을 구축하며, 특히 IoT 확산에 대비해 많은 연결 기기를 관리하고 있다.
액터는 실패를 유연하게 처리하고 시스템의 민첩성과 응답성을 유지하며, 높은 동시성요구를 충족시키도록 설계되어 있다.
도메인 주도 설계와 잘 어우러지도록 설계된 액터는 시스템 확장성과 성능 최적화를 가능하게 한다.
2. 🧩 객체 지향 프로그래밍과 병렬 처리의 한계
전통적인 객체 지향 언어에서는 클라이언트가 서버 객체에 호출할 때 모든 메서드 호출이 블로킹 방식이다 .
프로세서의 성능이 1973년 이후로 크게 향상되었지만, 2003년 이후로 클록 속도 증가가 둔화되어 코어 수가 성능 향상의 핵심이 되었다 .
다중 코어 환경에서 단순 스레드 기반의 작업 분배는 경합과 블로킹 문제로 인해 쉽지 않다 .
🎯 스레딩의 어려움과 블로킹 문제
작업 큐를 여러 스레드가 읽는 방식은 경합과 교착 상태를 유발하며 스레드 간 대기가 발생한다 .
특히, 여러 스레드가 하나의 엔티티에 접근할 때 블로킹이 심화되어 병렬 성능이 저하되고, 전체 시스템이 단일 스레드처럼 동작할 위험이 존재한다 .
🚀 배우기 좋은 메시지 기반actor 모델의 소개
액터 모델은 메시지 주도, 블로킹 없음, 자연스러운 병렬성을 지원하며, 메시지 전달이 비동기적이기 때문에 작업 병렬화에 적합이다 .
액터는 단순한 객체와 유사하며, 메시지 전송 후 계속 실행을 이어가고, 수신자는 별도의 스레드에서 메시지를 처리한다 .
액터 모델은 Alan Kay의 메시지 송신 원칙에 충실하며, 메시지 교환을 통해 객체의 목적이 정의된다는 점에서 객체 지향 프로그래밍의 핵심 원리와 일맥상통한다 .
💡 결론: 액터 모델은 객체지향의 메시징 개념을 계승
액터 모델은 메시지 중심 개념으로 객체의 의미를 규정하며, 이는 Smalltalk의 메시지 송신 원리와 일치한다 .
2.1. 도메인 주도 설계(DDD)와 액터 모델을 결합한 반응형 시스템 구현
발표자는 이메일로 추가 질문에 답변할 의향이 있으며, 연락 방법을 제공한다. [28]
이 강연은 도메인 주도 설계(DDD)의 아이디어와 액터 모델의 개념을 융합한 내용임을 언급한다. [30]
'Reactive Messaging Patterns' 책은 Scala 언어와 관련된 내용을 다루고 있으며, 이와 관련된 반응형 메시징 패턴을 설명한다. [31]
발표자는 이 강의의 방향성을 소개하며, 도메인 주도 설계와 액터 모델결합의 중요성을 강조한다. [32]
2.2. 객체지향 프로그래밍에서의 블로킹 호출 문제
클라이언트가 서버 객체의 메서드를 호출할 때마다 블로킹(대기) 상태가 발생한다. [33]
여기서 클라이언트와 서버는 복잡한 컴포넌트가 아니라 단순 객체임을 의미한다. [34]
이는 클라이언트가 서버 객체의 응답을 받을 때까지 계속 대기하는 방식으로 작동한다. [33]
2.3. ️ 최신 프로세서 트렌드와 성능 한계
1973년부터 2003년까지 프로세서의 클럭 속도는 1MHz 이하에서 시작하여 꾸준히 증가했으며, 트랜지스터 수 역시 Moore의 법칙에 따라 늘어났다. [36]
그러나 2003년 이후로 클럭 속도 증가가 거의 정체되어, 더 이상 높은 속도를 기대하기 어려운 상태가 되었다. [39]
오늘날 서버 성능의 핵심은 코어 수이며, 많은 코어를 탑재하는 것이 중요하지만, 코어의 속도 향상은 지난 12-14년 동안 크지 않다. [43]
따라서, 미래 컴퓨팅의 방향은 코어 수와 병렬 처리 능력에 더 집중되고 있다고 볼 수 있다. [45]
2.4. ️ 멀티스레딩의 어려움과 경쟁 상태 발생
여러 스레드가 작업 큐에 접근할 때 락으로 인해 대기 상태가 발생하며, 이는 경쟁 조건과 병목현상을 초래한다. [46]
작업 큐에 대한 잠금으로 인해 다수의 스레드가 동시에 작업을 수행할 수 없으며, 일부는 대기하게 된다. [56]
서로 다른 스레드가 동일한 엔티티를 수정하려고 할 때 블로킹이 발생하며, 이는 멀티코어 성능 저하를 유발한다. [62]
이러한 경합과 블로킹으로 인해, 애초 기대했던 병렬처리의 이점이 사라지고, 애플리케이션이 단일 스레드와 유사한 성능 저하를 겪을 수 있다. [64]
결론적으로, 스레딩은 간단해 보이지만, 실제로는 매우 어렵고 복잡한 문제임을 보여준다. [52]
2.5. 액터 모델의 메시지 중심 특성
액터 모델은 메시지 전달 기반으로 설계되어 있으며, 비차단(Non-blocking) 방식과 높은 처리 속도를 자연스럽게 지원한다. [66]
액터는 단순 객체와 유사하며, 메시지 보내기와 받기 Mechanism이 추가된 경량화(Object와 유사한 구조)임을 강조한다. [68]
메시지 전송 시, 송신자는 메시지를 큐에 넣고 즉시 자신의 실행 흐름을 계속하며, 수신자는 미래의 어떤 스레드에서 메시지를 처리한다. [66]
다수의 액터가 작동할 경우, 상시 context switching이 발생하는 비효율성이 존재한다. [73]
산업 내 선구자인 앨런 케이는 메시징이 객체의 목적을 정의하는 핵심임을 강조하며, 이 개념이 오늘날의 객체 지향 설계 원칙에도 영향을 미쳤다고 본다. [74]
결국, 액터 모델은 앨런 케이의 객체 메시지 발신 아이디어를 적극 수용하고 있으며, 이는 제대로 된 비동기 메시지 전달 시스템의 뿌리임을 시사한다. [75]
3. 🚀 배우 모델과 객체 지향의 역사적 연관성
배우 모델의 기원은 1973년 카를 휴잇이 개발을 시작했고, 이는 당시 프로세서 속도(1MHz 이하)와 트랜지스터 수(약 45,000개)를 고려할 때 매우 선진적이었다고 볼 수 있다 .
오브젝트의 역사는 1967~68년경에 시작되었으며, 이 영향으로 앨런 케이가 개발한 Smalltalk(1971, 1972)가 배우 모델 형성에 영감을 주었다 .
휴잇은 당시의 제한된 하드웨어 환경에서도 다중 프로세서 시스템과 빠른 네트워크를 상상하며 배우 모델을 개발했고, 이는 이후 Erlang등에서 활용되었다 .
🌐 배우 모델과 반응형 시스템의 연결
배우 모델은 반응형 시스템의 네 가지 특성(반응성, 탄력성, 탄성, 메시지 기반)을 지원하는 핵심 기술이다 .
반응성은 사용자 요구에 신속히 대응하는 것으로서, 실시간 웹 요청에 25ms 이하 응답이 가능하게 만든다 .
메시지 전달을 통한 탄력성은 서버 또는 객체가 크래시 하더라도 클라이언트가 영향을 받지 않으며, 부모 배우가 장애 처리와 재시작을 담당한다 .
탄성은 시스템이 수요에 따라 성장하거나 축소할 수 있으며, 메시지 기반구조를 통해 구현된다 .
⚙️ 현대 하드웨어와 배우 모델의 적합성
현대 프로세서인 인텔의 Xeon은 88개 이상의 코어를 지원하며, 여러 프로세서를 결합하면 200개 이상의 코어를 활용 가능하다 .
배우 모델은 멀티코어 환경에서 복잡한 다중 스레딩 대신 자연스럽게 병렬 처리를 가능하게 하며, Akka와 같은 프레임워크는 이를 쉽게 활용할 수 있도록 돕는다 .
각각의 요청과 응답이 비동기적으로 처리되므로, 지연(latency) 문제를 자연스럽게 수용하며 분산 시스템에서도 신뢰성을 유지한다 .
🤝 효율적 자원 활용과 시스템 확장성
배우 모델은 적은 서버로 높은 성능을 확보할 수 있게 하며, 기존 클러스터보다 훨씬 적은 수의 서버로도 높은 확장성과 성능이 가능하다 .
메시지 전달은 무록(lock-free) 방식으로, 각 배우는 별도로 메모리를 공유하지 않으며, 동시에 여러 메시지를 받을 수 있다 .
배우 시스템은 계층적 구조를 지원하며, 슈퍼바이저를 통해 장애 복구와 안정성을 보장하는 시스템 구성이 가능하다 .
3.1. 배우 모델과 초기 객체 지향 개념의 역사
1973년에 Carl Hewitt가 배우 모델을 개발하기 시작했으며, 이는 컴퓨팅 개념의 중요한 전환점을 이룬다. [84]
객체 지향의 기초가 된 Simula는 1967년 또는 1968년경에 시작되었으며, 이후 Smalltalk(1971, 1972)가 개발되었다. [85]
Smalltalk의 아이디어는 Carl Hewitt에게 영감을 주어, 배우 모델 개발에 영향을 미쳤을 것으로 추정된다. [86]
당시 프로세서 성능은 1MHz 미만의 클록속도와 약 45,000개의 트랜지스터를 가지고 있었으며, HW 발전은 매우 제한적이었다. [87]
Hewitt의 아이디어는 당시 기술 수준보다 훨씬 앞서 있었으며, 멀티프로세서 시스템과 고속 네트워크에 대한 비전이 있었다. [89]
3.2. 액터 모델과 리액티브 시스템의 관계
액터 모델은 Erlang에서 사용되었으며, 최근에는 JVM환경에서도 강력한 액터 시스템을 구축하는 것이 중요하다고 인식된다. [91]
Jonas Bonér는 JVM상에서 견고한 액터 시스템을 실현할 수 있는 비전과 역할이 중요하다고 강조하였다. [92]
이를 통해 많은 개발자들이 JVM이라는 친숙한 플랫폼에서 액터를 활용할 수 있는 기회가 마련되었다. [94]
⚡ 리액티브 시스템의 네 가지 핵심 특성
리액티브는 반응성(Responsive), 탄력성(Resilient), 탄성(Elastic), 메시지 지향적(Message-driven) 네 가지 특성을 갖는다. [97]
메시지 지향적인 통신이 나머지 특성들을 지원하는 핵심 역할을 담당한다. [100]
🎯 반응성(Responsive)의 의미와 성능
리액티브 시스템은 사용자 요구에 신속하게 반응할 수 있으며, 사용자 요청에 25ms 이하로 응답할 수 있다. [102]
액터 모델을 통해 높은 처리량과 빠른 응답성을 실현할 수 있으며, 이는 Akka와 같은 플랫폼에서 입증되어 있다. [103]
3.3. 반응형 시스템의 회복력과 메시지 전달 기반의 안정성
반응형 시스템은 회복력이 높으며, 이는 메시지 전달 방식을 통해 지원된다. [105]
클라이언트는 서버 역할을 하는 액터에 메시지를 보내는 동안, 서버 내의 문제로 인한 예외 처리를 직접 할 필요가 없다. [107]
객체지향 언어에서는 클라이언트가 예외를 처리하거나 상위로 재전달해야 하지만, 액터 모델에서는 부모 액터가 예외 처리를 담당한다. [108]
서버 액터가 크래시 또는 예외가 발생했을 때, 부모 액터가 이를 감지하고 재시작 등 대응을 할 수 있어, 시스템이 더욱 안정적으로 유지된다. [109]
클라이언트는 요청에 대한 응답 여부만 알면 되며, 일정 시간 내에 응답 없을 경우 재요청을 할 수 있다. [112]
잘 구성된 액터 시스템은 매우 회복력 있는 구조를 가질 가능성이 크다. [114]
또한, 애플리케이션은 수요에 따라 확장 또는 축소(엘라스틱성을 갖추어) 유연하게 대응할 수 있다. [115]
이러한 특성들은 모두 메시지 전달 기반인 시스템 아키텍처에 의해 가능하다. [116]
3.4. 강력한 코어와 하드웨어 활용
현대 시스템은 높은 성능의 저장장치, 많은 메모리, IoT 및 모바일 장치 등 광범위한 디바이스를 활용할 수 있으며, 이들은 높은 확장성과 연결성을 갖추고 있다. [118]
최신 클라우드호스팅과 빠른 네트워크를 이용해 저렴한 비용으로 높은 성능을 구현할 수 있다. [119]
인텔 Xeon 프로세서는 최대 88개 코어를 지원하며, Xeon FI 기술을 통해 여러 프로세서를 결합하면 200개 이상의 코어를 하나의 서버에서 사용할 수 있다. [121]
이러한 고성능 하드웨어는 개발자에게 다중 코어 활용의 기회를 제공하지만, 동시에 멀티스레딩 환경의 복잡성을 야기한다. [120]
🧠 액터 모델이 해결하는 멀티코어 프로그래밍
액터 모델은 멀티코어 환경에서 동시성과 병렬 처리를 간단하고 직관적으로 구현할 수 있게 돕는다. [124]
이 모델은 멀티스레딩으로 인한 인지적 부담을 줄여주며, 관련 프레임워크(예: Akka)는 개발자의 복잡한 스레드 관리를 대신한다. [124]
결과적으로, 액터 모델은 멀티스레딩 환경의 어려움을 해소하며, 효율적이고 쉬운 병렬 프로그래밍을 가능하게 한다. [124]
3.5. 비동기적 요청과 응답을 위한 배우 모델의 장점
배우 모델은 모든 요청과 응답이 비동기적이기 때문에, 지연(latency) 문제를 자연스럽게 수용할 수 있다. [126]
분산 시스템에서는 네트워크 장애나 서버 다운으로 인한 지연이 발생하는 것이 자연스러우며, 시스템이 차단(blocking)되는 것은 현실적이지 않다. [126]
지연을 예상하고 설계함으로써, 즉각적 결과를 기대하지 않고 메시지에만 반응하는 방식이 가능하다. [133]
🧩 적은 서버로도 효율적 확장 가능
과거처럼 수백 개 서버를 필요로 하는 확장 방식이 아닌, 작은 서버 클러스터를 효율적으로 활용할 수 있다. [135]
배우 모델은 자원 최대 활용과, 서버 축소 후에도 높은 용량을 유지하는 데 유리하다. [137]
이를 통해 한정된 서버 수로도 충분한 성능과 확장성을 확보할 수 있다.
📩 비동기 메시징과 비공유 상태
배우 간 메시지를 보내기 위해서는 수신자의 주소를 알아야 한다, 이는 직접적 비동기 메시지 전달의 특징이다. [140]
배우들은 락 프리(lock-free)이며, 상태를 공유하지 않는다. [142]
메시지는 수신자의 우편함(mailbox)에 차곡차곡 쌓여, 하나씩 처리된다. [143]
수신 배우는 다음 메시지를 처리할 준비를 할 수 있으며, 메시지 수신 시 다른 로직으로 반응할 수도 있다. [145]
🧱 계층적 구조와 장애 처리
배우들은 시스템 내 여러 개체로서, 시스템 내 다수의 배우로 존재하며. [147]
계층적 시스템 지원으로, 감독(supervision)과 장애 격리(crash protection)가 가능하다. [149]
4. 🚀 액터 모델의 병렬 처리와 경쟁 조건 이해
액터 시스템에서는 메시지 전송과 타임아웃이 동시에 발생할 수 있으며, 이는 경쟁 조건이 될 가능성이 있다.
타임아웃 메시지와 성공 메시지는 서로의 도달 순서에 따라 클라이언트에 서로 다른 응답을 유발한다.
수백만 개의 액터를 지원하는 시스템은 가능하며, 이는 확장성을 보여준다.
🔧 액터 모델이 복잡성을 줄이고 간단하게 하는 방식
전통적인 엔드-투-엔드 아키텍처는 불필요하거나 우발적인 복잡성을 포함하며, 액터 모델은 이를 단순화할 수 있다.
외부에는 어댑터와 컨트롤러를 두고, 도메인 모델은 메시지 통지를 통해 이벤트를 발생시킨다.
🎯 도메인 주도 설계(DDD)와 액터 모델의 결합
DDD 핵심은 도메인 용어를 사용하는 유비쿼터스 언어와 경계적 맥락을 설계하는 것에 초점이 맞춰진다.
경계 맵핑은 시스템 내 여러 경계적 컨텍스트들의 관계와 통합 방식을 모델링하는 데 중요하다.
⚡ 급변하는 비즈니스 요구에 대한 대응
DDD는 빠른 비즈니스 변화와 요구에 빠르게 적응하는 데 도움을 주며, 액터와 메시지를 활용한 구현이 유리하다.
Alan Kay의 말에 따르면, 액터 모델은 객체와 메시지 중심의 설계를 가능하게 하며, 도메인 모델의 핵심 요소로 작용한다.
🕵️ 이벤트 스톰밍과 도메인 이벤트 처리
이벤트 스톰닝은 빠르게 새로운 비즈니스 아이디어를 모델링하고 적응하는 데 효과적이며, 대형 그림 모델링과 설계 수준에서 활용한다.
애그리게이트(액터 또는 엔티티)는 커맨드 요청과 이벤트 생성의 핵심 중심 역할을 한다.
이벤트는 이벤트 저널에 비동기 기록되며, 여러 방식으로 소비될 수 있다.
🧩 액터를 통한 일관성, 확장성, 복구성과정
액터 내의 불변 상태 객체를 사용하며, 상태 변경은 측효과 없는 함수로 처리되어 테스트와 이유 추론이 용이하다.
Akka persistence는 이벤트 저장과 처리에 적합하며, 도메인 이벤트는 중앙 버스를 통해 여러 서비스에 배포된다.
이러한 배포는 반응형 시스템 전체를 모델링하는 데 적합하다.
📚 활용 가능한 자료와 리소스
다양한 책과 자료에서 액터 모델과 리액티브 시스템 설계에 대해 더 깊이 학습할 수 있으며, 특히 Lightbend의 책과 온라인 세미나가 강력한 자료이다.
Reactive Summit과 같은 컨퍼런스 참여도 추천된다.
4.1. 액터 모델과 타임아웃, 성공 메시지 간의 경쟁 상태
라우터가 메시지를 보내면서 동시에 타이머를 설정하며, 이는 경합 조건(race condition)이 발생하는 상황임을 보여준다. [151]
메시지의 성공 또는 타임아웃이 언제 도달하는지에 따라, 클라이언트에게 전송되는 응답이 달라질 수 있다고 설명한다. [154]
만약 성공 메시지가 타임아웃보다 먼저 도달하면, 클라이언트에 성공 응답이 전달되고, 그렇지 않으면 타임아웃 메시지가 전송된다는 점을 강조한다. [158]
이 과정은 경합 조건이 발생하는 것이며, 이는 라우터 자체가 취약하다는 의미가 아니라고 설명한다. [155]
4.2. 액터 기반 서비스의 확장성
액터 기반 시스템은 수백만 개의 액터를 지원할 수 있으며, 몇십 개 또는 몇백 개 이상의 액터도 가능하다고 한다. [160]
액터 수는 제한이 없으며, 이론적으로 수백만 개의 액터를 처리할 수 있다고 설명한다. [161]
⚙️ 전통적인 엔드-터 아키텍처의 복잡성 문제
일반적인 포트와 어댑터 기반 아키텍처는 불필요하거나 우발적인 복잡성이 많다고 주장한다. [162]
이러한 아키텍처는 많은 이해관계자와 다양한 컴포넌트를 요구하며, 복잡한 계층 구조를 형성한다고 한다. [163]
🎯 액터 모델의 단순화 효과
액터 모델을 사용하면 복잡한 계층 구조를 축소하여 단순한 구조로 만들어 줄 수 있다고 강조한다. [164]
예를 들어, 컨트롤러와 도메인 모델이 메시지를 통해 소통하며, 도메인 이벤트를 방출하는 방식이 가능하다고 언급한다. [165]
즉, 액터 모델은 전체 시스템의 복잡성을 크게 줄이고 단순한 설계를 가능하게 한다고 한다. [166]
4.3. 도메인 주도 설계(Domain-Driven Design)의 핵심 원리
도메인 주도 설계의 근본은 유비쿼터스 언어와 경계 컨텍스트를 모델링하는 것이다. [167]
경계 컨텍스트는 의미적 경계로, 내부의 도메인 모델과 언어를 명확히 정의하며, 팀 간 이해를 돕는다. [173]
개발 커뮤니티는 도메인 주도 설계에 대한 관심과 활용도가 점차 증가하고 있다. [168]
컨텍스트 매핑은 시스템 내 여러 경계 컨텍스트 간 관계와 상호작용을 모델링하는 도구이며, 작은 컨텍스트들이 복잡한 시스템을 구성하는 데 중요하다. [175]
빠르게 변화하는 비즈니스 요구에 대응하기 위해, 도메인 주도 설계는 지식 정제와 이해를 촉진하며, 팀의 신속한 도메인 모델 구현을 가능하게 한다. [176]
🎯 Actor 모델과 도메인 주도 설계의 연계
Alan Kay의 Actor 모델은 객체와 메시지 개념을 도메인 모델에 통합하는 데 유용하며, 메시징이 중요한 특징이다. [179]
도메인 내 행위자(Actor)는 도메인 오브젝트 또는 컴포넌트로, 이들 간의 메시지 송수신이 유비쿼터스 언어의 일부를 이룬다. [180]
예를 들어, 상품(제품) Actor과 백로그 아이템(작업 목록 항목) Actor이 각각 요청 메시지와 도메인 이벤트를 주고받으며, 이는 도메인 언어의 핵심 요소이다. [181]
4.4. 이벤트 스톰핑을 활용한 신속한 비즈니스 아이디어 대응
이벤트 스톰핑은 빠른 비즈니스 아이디어의 수용과 방향 전환에 효과적이며, 여러 방법이 존재한다. 이 중 하나는 전체 그림(큰 그림) 모델링이고, 또 다른 방법은 설계 수준의 이벤트 스톰핑을 실시하는 것이다. [184]
설계 단계에서 이벤트 스톰핑을 수행하면 비즈니스 전문가와 개발자가 새 아이디어를 빠르게 모델링하고 대응하는 데 유용하다. [185]
이에 따라, 이벤트 스톰핑은 도메인 전문가와 개발팀 간의 협업을 촉진하고 신속한 설계 반영을 가능하게 한다. [186]
🧩 도메인 주도 설계(DDD)와 액터 모델을 이용한 이벤트 흐름 이해
애그리거트 또는 엔티티는 액터로 구현되며, 요청된 커맨드와 방출되는 이벤트를 이해하는 것이 핵심이다. [190]
커맨드 수신 후, 애그리거트는 이벤트를 방출하고, 이벤트는 비동기 방식으로 이벤트 저널에 저장되며 이후 다양한 방법으로 소비된다. [191]
액터로 구현된 애그리거트는 일관성의 경계(경계선) 역할을 하며, 트랜잭션 범위 내에서 일관성을 유지한다. [193]
🧩 애커의 상태 관리와 테스트 용이성을 위한 설계
액터 내에서 불변 상태 객체 또는 기록(record)을 구현하는 것이 권장된다. 예를 들어, 인콜라와 케이스 클래스 등을 활용할 수 있다. [195]
액터 내부에는 하나의 가변 변수(var)만 존재하며, 이는 상태 객체를 저장하는 데 사용된다. [197]
커맨드 처리 시, 불변 상태 객체는 사이드 이펙트 없이 함수적 방식으로 전환되며, 함수의 결과는 새로운 상태 인스턴스로 만들어지고, 이를 다시 저장한다. [198]
액터 내의 유일한 가변성은 상태를 저장하는 변수이며, 이는 테스트와 복잡한 애그리거드의 이해를 높이는 데 중요하다. [199]
4.5. 도메인 주도 설계(DDD)와 액터 모델을 활용한 리액티브 시스템 구축
이벤트를 발생시키는 것은 중요하며, 이는 Akka Persistent의 영속 배우 트레잇을 통해 지원되어 집합체(aggregate)를 생성하는 데 활용된다. [201]
한 서비스 또는 바운디드 컨텍스트에서 발생한 이벤트는 중앙 버스로 전송되며, 이 버스는 메시지 주제(topic)로 작동하여 여러 바운디드 컨텍스트 또는 마이크로서비스가 구독한다. [203]
이벤트의 배포를 통해 전체 리액티브 시스템이 형성되며, 이는 단일 서비스가 아닌 복수의 상호 연관된 서비스 시스템을 목표로 한다. [205]
도메인 이벤트를 다른 바운디드 컨텍스트 또는 마이크로서비스로 발행하는 방식은 전체 시스템 개발과 모델링에 효과적이다. [210]
특히, 리액티브 시스템 설계에 대한 자료로, 오픈 소스인 O'Reilly의 'Designing Reactive Systems with the Actor Model' 이 있다. 저자는 Jonas, Victor Clung, Hugh McKe 등이며, Lightbend에서 배포하는 관련 서적도 있다. [211]
Lightbend는 플랫폼 전문성을 제공하며, 고객의 리액티브 이니셔티브 시작을 위해 엔지니어와 협력할 수 있다. [219]
다가오는 Reactive Summit(2017년 10월 18-20일)은 리액티브 시스템에 관심 있는 전문가들이 모이는 중요한 행사로, 발표자로 참여하거나 참석할 것을 권장한다. [221]
5. 💡 액터 모델과 전통적인 요청별 스레드 아키텍처 비교
액터 모델은 비동기 메시지 전달을 기반으로 하며, 여러 요청을 동시에 처리할 수 있다 .
전통적인 아키텍처는 요청별로 하나의 스레드가 순차적으로 처리하여 차단(blocking)이 발생할 수 있다 .
Play Framework와 같은 비동기 웹 서버는 요청 처리를 비동기적으로 수행하며, 연산 중 스레드 재사용이 가능하다 .
액터는 여러 코어 및 노드를 활용하여 높은 처리량과 낮은 지연 시간을 달성한다 .
기존 싱글 스레드 또는 블로킹 방식보다 전체 시스템의 처리능력과 효율이 훨씬 높아진다 .
🎯 이벤트 스톰밍의 목적과 활용 방식
이벤트 스톰밍은 복잡한 시스템을 이해하기 위해 시작하며, 참여자들이 올바른 질문과 답변을 나누기 위해 수행된다 .
주로 이벤트에 초점을 맞추어 비즈니스 프로세스 관점을 도출하며, 이벤트와 커맨드 메시지를 식별하는 데 사용된다 .
이 기법은 이벤트 소싱과 CQRS와 밀접하게 연관되어 있으며, 시스템 모델링을 빠르게 수행하는 도구다 .
Alberto와 Jonas Boner 등의 연구를 참고하며, 실무와 워크숍에서 유용하게 활용된다 .
이벤트 스톰밍은 시스템 설계와 도메인 이해에 효과적이며, 빠른 모델링과 반영을 가능하게 한다 .
🌍 IoT 환경에서 액터 모델의 잠재적 역할
IoT 기기의 낮은 전력 소모와 제약으로 인해, pub/sub 아키텍처보다 직접 비동기 메시징이 유리하다 .
IoT 기기는 제한된 전력으로 인해 필요할 때만 메시지를 수신하는 액터 시스템을 탑재할 수 있다 .
Pub/sub는 상태 보고에 적합하며, 메시지 전달 대신 상태 전파에 활용될 수 있다 .
Lightbend의 사례 연구는 IoT 기기와 액터 시스템 활용의 가능성을 보여준다 .
이러한 방법은 IoT 디바이스의 에너지 사용 효율을 크게 향상할 수 있다.
5.1. 이메일과 자료 제공 안내
Lightbend의 친절한 동료로부터 이메일을 통해 슬라이드와 영상 링크를 받게 된다 [230]
질문이 있을 경우, oliver@ Lightbend.com으로 이메일을 보내도록 권장된다 [231]
발표는 여기서 종료되며, 이후 질의응답 시간을 갖는다 [232]
5.2. 전통적 요청 처리 방식과 액터 모델의 차이점
전통적인 Java EE 또는 Spring 기반 시스템에서는 요청이 한 요청마다 하나의 스레드에서 처리되어, 요청이 끝날 때까지 해당 스레드가 차단될 수 있다며, 이로 인해 처리량이 제한될 수 있다. [237]
반면, 액터 모델에서는 요청을 비동기 메시지로 처리하며, 요청을 처리하는 동안 스레드가 블로킹되지 않고 재사용되어 여러 요청을 동시에 처리할 수 있다. [242]
예를 들어, Play Framework 같은 비동기 프레임워크는 요청 수신 후 컨트롤러가 메시지를 도메인 모델(액터)로 전달하는 순간, 처리와 응답이 비동기적으로 진행되어 효율이 높아진다. [241]
요청 처리 과정에서 일시적인 블로킹이 발생하지 않으며, 여러 스레드가 병렬로 요청을 서비스하여 높은 처리량을 달성한다. [247]
결국, 액터 모델은 전통적 스레드 기반 요청 처리보다 보다 높은 동시성과 효율성을 제공하며, 이 차이는 시스템이 수행하는 내부 동작의 차이에서 기인한다. [256]
5.3. ️ 액터 모델이 단일 코어에서 비효율적이라는 인식에 대한 설명
액터 모델은 병렬성과 확장성을 위해 설계되었기 때문에, 단일 코어에서는 오히려 처리 지연이 발생할 수 있다. [259]
과거에는 15년 전과 같이 싱글 스레드 및 단일 코어 환경에서는 액터 모델이 이전 방법보다 오히려 더 오래 걸릴 가능성이 있다. [260]
그러나, 많은 코어와 노드에 분산하면, 액터 모델은 초고속 처리가 가능하며, 대규모 시스템 확장에 적합하다. [261]
Erlang의 창시자인 조 아르망에게 물어보면, Erlang과 액터 모델은 구형 마이크로프로세서에서도 성공적으로 활용되었다고 한다. [262]
한편, 일부 연구자들은 단일 요청 처리 시 액터 모델이 작업 전환과 맥락 전환 때문에 시간 소요가 더 클 수 있다고 언급한다. [263]
그러나, 액터 모델은 멀티스레드 환경에서의 처리량과 전체 성능이 훨씬 높기 때문에, 집합적인 성능이 개별 요청보다 크다는 점이 강조된다. [266]
즉, 액터 모델의 전체 시스템 성능은 요청 하나하나의 처리 시간보다 더 크다는 관점이 존재한다. [268]
5.4. 이벤트 스토밍의 정의와 역할
이벤트 스토밍은 복잡한 시스템 이해를 위해 올바른 사람들과 질문에 적합한 답을 찾기 위해 진행하는 방법이다. [270]
주로 이벤트에 초점을 맞추며, 비즈니스 프로세스에 대한 이해를 높이는 데 유용하다. [275]
시스템 내 발생하는 사건(이벤트)에 집중하는 것이 핵심이며, 명령(command)과 이벤트 관계를 식별하는 과정도 포함된다. [277]
이벤트 스토밍은 이벤트 소싱 및 CQRS와 밀접하게 연결되며, 특정 수준에서는 시스템 내부 구성요소를 설계하는 데 활용된다. [283]
이 방법은 복잡한 도메인에 대한 빠른 모델링과 설계를 지원하며, Alberto와 기타 연구자들이 설명한 유용한 기법이다. [286]
5.5. ️ IoT와 실시간 결정 및 개인화에서의 Actor Model 역할
IoT 기기는 저전력 특성으로 인해 지속적인 메시지 폴링이 어려워, 즉시 비동기 메시징이 적합하다. [301]
IoT 기기들은 Pub/Sub 시스템보다, 필요 시에만 메시지를 받는 직접 비동기 메시징이 효율적이다. [303]
기기는 자신의 상태를 PubSub를 통해 송신하며, 이때 전력 소모는 메시지 전송에만 집중된다. [306]
IoT 기기의 효율적 운영을 위해 Actor 시스템을 제한적으로 도입하는 방안이 고려될 수 있다. [304]
Lightbend사례 연구에서 Actor와 IoT의 통합을 통한 전력 절감과 효율 향상 사례가 소개된다. [309]
📌 액터 모델이 반응형 시스템에 적합한 이유는 무엇인가?
액터 모델은 메시지 기반, 비차단 방식으로 설계되어 반응성, 탄력성, 복원성을 지원하며 높은 처리량을 제공하기 때문이다
💡 액터 모델이 반응형 시스템의 특성을 지원하는 방식은?
반응성: 메시지 전달을 통해 사용자 요구 및 증가하는 시스템 요구에 응답
복원성: 메시지 전달을 통해 클라이언트가 서버 액터의 예외 처리를 직접 처리할 필요 없이 부모 액터가 처리
탄력성: 메시지 기반으로 현재 수요에 따라 시스템 확장 및 축소 가능
도메인 주도 설계(DDD)란 무엇이며 왜 중요할까요?
도메인 주도 설계(DDD)는 복잡한 소프트웨어를 만들 때 사용하는 접근 방식입니다.
DDD의 가장 중요한 아이디어는 비즈니스 전문가와 개발팀이 같은 용어를 사용하고 이해하는 것입니다. (이것을 유비쿼터스 언어라고 합니다.)
또한, 시스템을 여러 개의 작은 경계가 명확한 영역(바운디드 컨텍스트)으로 나눕니다.
이렇게 하면 복잡한 비즈니스 요구사항이 바뀌더라도 해당 영역만 빠르게 수정하고 대응할 수 있습니다.
DDD는 최근 점점 더 인기를 얻고 있습니다.
액터 모델과 DDD의 시너지 효과 (메시징과 유비쿼터스 언어)
앞에서 앨런 케이가 객체 지향의 가장 큰 아이디어가 메시징이라고 말했음을 기억하시죠?
이 메시징 개념이 DDD의 유비쿼터스 언어와 아주 잘 맞습니다.
DDD에서 비즈니스 개념을 모델링할 때, 액터가 그 핵심 구성 요소가 될 수 있습니다.
그리고 액터들이 주고받는 메시지 자체가 비즈니스에서 사용하는 용어들(유비쿼터스 언어)이 됩니다.
예를 들어, '주문'이라는 명령 메시지를 '제품' 액터에게 보내고, '제품 주문됨'이라는 이벤트 메시지를 받는 것처럼 말입니다.
이벤트 스토밍을 활용한 DDD 모델링
복잡한 비즈니스 도메인을 이해하고 모델링하는 좋은 방법으로 이벤트 스토밍이라는 기법이 있습니다.
이벤트 스토밍은 비즈니스 전문가와 개발자가 함께 모여 시스템에서 발생하는 중요한 일들(이벤트)을 찾아내고 정리하는 워크샵입니다.
이 과정을 통해 시스템의 흐름과 어떤 명령이 어떤 이벤트를 발생시키는지 쉽게 파악할 수 있습니다.
이는 DDD에서 중요한 개념인 애그리게이트, 커맨드, 이벤트를 식별하는 데 매우 유용합니다.
이벤트 스토밍은 비즈니스 요구사항을 빠르게 이해하고 모델에 반영하는 데 도움이 됩니다.
액터 모델 기반 DDD 구현 (애그리게이트와 이벤트 소싱)
개념/패턴 | 설명 | DDD와의 관계 | 구현 방식 (액터 모델) |
액터 모델 | 병렬 및 분산 시스템 구축에 적합한 동시성 모델 | DDD와 함께 사용 시 효과적 | 메시지 기반 통신, 상태 고립 |
도메인 주도 설계 (DDD) | 복잡한 도메인 로직을 모델링하고 구현하는 소프트웨어 개발 접근 방식 | 액터 모델과 결합하여 반응형 시스템 구축 | 애그리게이트, 이벤트 소싱, 도메인 이벤트 등 |
애그리게이트 | DDD에서 일관성을 유지해야 하는 객체들의 묶음 | 액터가 애그리게이트 구현에 적합 | • 액터는 애그리게이트의 상태를 관리 |
이벤트 소싱 | 상태 변화를 이벤트 스트림으로 저장하는 데이터 관리 패턴 | 액터 모델에서 상태 변화를 기록하는 방식 | • 액터는 상태 변화를 이벤트로 기록 |
DDD에서 애그리게이트는 일관성을 유지해야 하는 객체들의 묶음입니다.
액터는 이 애그리게이트를 구현하기에 아주 적합합니다.
액터는 자신에게 오는 명령 메시지를 처리하고, 상태 변화를 이벤트로 기록할 수 있습니다.
이렇게 상태 변화를 이벤트로 저장하는 방식을 이벤트 소싱 패턴이라고 합니다.
액터의 상태는 보통 불변 객체로 만들고, 새로운 메시지가 오면 기존 상태를 바꾸는 대신 새로운 상태 객체를 만들어 사용합니다.
마이크로서비스 아키텍처와 반응형 시스템 구축
DDD의 바운디드 컨텍스트는 마이크로서비스와 잘 연결됩니다.
각 바운디드 컨텍스트를 독립적인 마이크로서비스로 만들 수 있습니다.
서비스들은 이벤트 버스를 통해 서로 발생한 이벤트를 공유하며 통신합니다.
이렇게 이벤트 메시지를 기반으로 서비스들이 연결되면 전체가 하나의 반응형 시스템이 됩니다.
중요한 것은 개별 서비스가 아닌, 시스템 전체가 반응형이어야 한다는 것입니다.
전통적인 방식과의 비교 (스레드 대 액터)
전통적인 방식에서는 하나의 요청을 처리하기 위해 하나의 스레드가 처음부터 끝까지 모든 작업을 순서대로 처리합니다.
중간에 데이터베이스 접근이나 다른 시스템 호출이 발생하면 해당 스레드는 그 작업이 끝날 때까지 기다려야 합니다. (블로킹)
이는 마치 한 사람이 모든 일을 순서대로 처리하는 것과 같습니다.
액터 모델에서는 요청이 오면 해당 액터가 메시지를 받고 바로 다른 일을 할 수 있습니다. ( 논블로킹)
마치 여러 사람이 동시에 다른 작업을 처리하고, 결과가 오면 그때 해당 결과를 처리하는 것과 같습니다.
특징 | 전통적인 방식 (스레드/요청) | 액터 모델 |
처리 방식 | 스레드가 순차적으로 모든 작업 처리 | 메시지 기반 비동기 처리 |
블로킹 여부 | 작업 완료까지 대기 (블로킹) | 메시지 보내고 즉시 다른 작업 (논블로킹) |
자원 활용 | 스레드가 대기 상태로 자원 점유 | 대기 없이 다른 작업 처리로 자원 활용도 높음 |
처리량 (Throughput) | 상대적으로 낮음 | 여러 액터 동시 처리로 높음 |
그렇다면 액터 모델은 항상 더 빠를까요?
단일 요청 처리 시간: 단일 스레드에서 순차적으로 처리하는 경우보다 액터 모델이 약간 더 오래 걸릴 수도 있습니다.
메시지 전달, 컨텍스트 전환 등의 오버헤드가 있을 수 있기 때문입니다.
전체 시스템 처리량: 하지만 여러 요청을 동시에 처리할 때, 액터 모델은 여러 코어와 자원을 훨씬 효율적으로 사용하여 전체 처리량이 훨씬 높습니다.
마치 혼자서는 빨리 못 뛰어도, 팀 전체로는 훨씬 많은 짐을 나르는 것과 같습니다.
