이벤트 기반 아키텍처에서 Observer 패턴과 Publish-Subscribe 패턴은 모두 느슨한 결합을 통해 객체 간의 통신을 구현하는 데 사용됩니다. 하지만 이 둘은 아키텍처적 차이와 확장성, 그리고 구현 복잡성에서 중요한 차이를 가집니다. 대규모 분산 시스템에서 이 두 패턴 중 어느 것을 선택해야 하며, 그 선택이 시스템의 확장성, 성능, 그리고 장애 허용성에 어떤 영향을 미치는지 심층적으로 비교 설명해주세요.
힌트 · Observer는 발행자와 구독자가 직접 통신하지만, Publish-Subscribe는 중간 브로커를 통해 통신합니다. 대규모 시스템에서는 중간 브로커의 유무가 확장성과 장애 허용성에 큰 영향을 미칩니다.
모범답안
이벤트 기반 아키텍처에서 Observer 패턴과 Publish-Subscribe 패턴은 느슨한 결합을 제공하지만, 대규모 분산 시스템에서는 Publish-Subscribe 패턴이 훨씬 유리합니다.
Observer 패턴은 발행자와 구독자가 직접 연결되어 있어, 발행자가 변경될 때 모든 구독자에게 즉시 알림이 전달됩니다. 이는 시스템 규모가 커지면 발행자와 구독자 간의 의존성이 높아져 확장성과 유지보수성이 떨어집니다. 또한, 발행자가 실패하면 구독자에게도 영향을 미칠 수 있어 장애 허용성이 낮습니다.
반면, Publish-Subscribe 패턴은 메시지 브로커(예: Kafka, RabbitMQ)를 통해 발행자와 구독자를 분리합니다. 발행자는 메시지를 브로커에 발행하고, 구독자는 관심 있는 토픽을 구독하여 메시지를 비동기적으로 수신합니다. 이 중간 브로커 덕분에 발행자와 구독자는 서로를 알 필요가 없어 결합도가 매우 낮습니다.
이러한 구조는 다음과 같은 이점을 제공합니다.
- 확장성: 발행자와 구독자를 독립적으로 확장할 수 있습니다. 새로운 구독자를 추가하거나 기존 구독자를 늘려도 발행자에게 영향을 주지 않으며, 발행자 또한 독립적으로 확장 가능합니다. 메시지 브로커 자체도 클러스터링을 통해 확장성을 확보할 수 있습니다.
- 성능: 비동기 통신을 통해 발행자는 메시지를 발행하고 즉시 다른 작업을 수행할 수 있습니다. 구독자 역시 자신의 속도에 맞춰 메시지를 처리하므로 전체 시스템의 처리량이 향상됩니다.
- 장애 허용성: 메시지 브로커는 메시지를 큐에 저장하므로, 발행자나 구독자 중 하나가 일시적으로 실패하더라도 데이터 손실 없이 메시지를 전달할 수 있습니다. 브로커 자체의 고가용성 구성으로 시스템 전체의 안정성을 높일 수 있습니다.
따라서 대규모 분산 시스템에서는 Publish-Subscribe 패턴이 시스템의 유연성, 확장성, 그리고 안정성을 극대화하는 데 필수적입니다.
읽었다면, 이제 직접 답해볼 차례예요
패스잇 앱에서 이 질문에 말로 답하면 AI가 꼬리질문까지 이어가며 1:1 코칭합니다.
함께 보는 디자인 패턴 면접 질문
- Adapter 패턴과 Facade 패턴은 모두 기존 시스템이나 라이브러리와의 상호작용을 돕는 구조 패턴입니다. 두 패턴의 목적과 사용 시점을 비교하여 설명하고, 각각의 실질적인 적용 사례를 들어주세요.
- Proxy 패턴은 실제 객체에 대한 접근을 제어하거나 기능을 추가할 목적으로 사용됩니다. Proxy 패턴의 동작 원리를 설명하고, Virtual Proxy, Remote Proxy, Protective Proxy의 차이점을 구체적인 예시와 함께 설명해 주세요.
- Decorator 패턴과 Proxy 패턴은 구조적으로 유사해 보이지만, 목적과 적용 방식에서 명확한 차이가 있습니다. 복잡한 시스템에서 특정 객체에 대한 횡단 관심사(cross-cutting concerns)를 적용하거나 접근 제어를 구현해야 할 때, 두 패턴 중 어떤 것을 선택해야 하며, 각각의 성능 및 유지보수 측면에서의 장단점은 무엇인지 구체적인 시나리오를 들어 설명해주세요.
- Singleton 패턴은 전역적으로 유일한 인스턴스를 보장하는 데 유용하지만, 테스트 용이성 저해, 다중 스레드 환경에서의 문제, 그리고 과도한 사용 시 의존성 주입을 어렵게 만드는 등 여러 단점이 지적됩니다. 이러한 Singleton 패턴의 문제점을 극복하고, 테스트 용이성과 유연성을 높이면서도 전역적인 유일성을 보장해야 하는 상황에서 Dependency Injection (DI) 또는 Monostate 패턴과 같은 대안을 어떻게 적용할 수 있는지 구체적인 코드 설계 관점에서 설명해주세요.
- 오래된 레거시 시스템은 종종 'God Object'나 'Feature Envy'와 같은 안티 패턴으로 인해 유지보수가 어렵고 확장성이 떨어집니다. 이러한 레거시 코드베이스를 점진적으로 리팩토링하여 디자인 패턴을 적용하고자 할 때, 어떤 전략과 패턴을 사용하여 기존 기능을 손상시키지 않으면서 코드 품질을 향상시킬 수 있을지 구체적인 단계와 적용 가능한 패턴(예: Strategy, Facade, Adapter)을 제시하여 설명해주세요.
- 디자인 패턴은 코드의 구조와 유지보수성을 향상시키지만, 일부 패턴은 잘못 적용되거나 특정 상황에서 성능 오버헤드를 유발할 수 있습니다. 예를 들어, Chain of Responsibility, Decorator, Visitor 패턴 등은 런타임 시 추가적인 객체 생성이나 메서드 호출로 인해 성능 저하를 일으킬 가능성이 있습니다. 이러한 패턴들이 성능에 미칠 수 있는 부정적인 영향을 분석하고, 성능 최적화를 고려하여 패턴을 설계하거나 대안을 선택하는 방법에 대해 설명해주세요.