Software Architecture 시각적으로 이해하기
각 개념의 아키텍처를 애니메이션 다이어그램으로 살펴보세요. 카드를 클릭하면 더 깊은 내용을 확인할 수 있습니다.
Client/Server
요청을 보내는 쪽과 처리하는 쪽을 분리하는 가장 기본적인 구조
클라이언트-서버 구조는 하나의 프로그램이 처리하던 역할을 '요청'과 '처리' 두 쪽으로 나누는 방식입니다. 클라이언트는 사용자 입력을 받고 결과를 보여주는 데 집중하고, 서버는 데이터 저장과 비즈니스 규칙을 중앙에서 책임집니다. 이 분리 덕분에 클라이언트가 여럿이어도 데이터의 기준점이 하나로 유지됩니다.
Layered
서버 내부 책임을 층으로 나눠 복잡도를 낮추는 구조
Layered Architecture는 하나의 애플리케이션 안에서 코드를 책임별 층으로 나누는 구조입니다. 프레젠테이션, 애플리케이션(유스케이스), 도메인, 인프라 각 층은 자기 역할만 하고 바로 아래 층과만 소통합니다. 서버 코드가 복잡해졌을 때 처음 도달하게 되는 구조 정리 방식이고, Spring MVC의 Controller-Service-Repository 패턴이 대표적인 구현입니다.
Monolith
하나의 코드베이스와 하나의 배포 단위로 움직이는 애플리케이션
Monolith는 모든 기능을 하나의 프로세스와 하나의 배포 단위로 묶어서 운영하는 애플리케이션 구조입니다. 모듈이 여러 개 있더라도 빌드하고 나면 하나의 산출물이고, 배포할 때도 전체가 한 번에 움직입니다. 개발 초기에는 로컬 실행과 디버깅이 단순하지만, 시스템이 커질수록 변경과 릴리스가 전체 단위로 엮이게 됩니다.
Microservices
도메인 경계를 서비스 단위로 나눠 독립적으로 운영하는 구조
Microservices는 하나의 애플리케이션을 여러 독립 서비스로 자르되, 각 서비스가 자기 도메인의 로직과 데이터를 완전히 소유하도록 설계하는 아키텍처 스타일입니다. 서비스 사이는 DB를 직접 공유하지 않고 API나 이벤트로 협력하며, 팀마다 자기 서비스의 배포와 운영 주기를 독립적으로 가져갑니다. 단순히 코드베이스를 쪼개는 기술이 아니라, 조직과 시스템 경계를 함께 설계하는 방식입니다.
Gateway
여러 백엔드 앞에 두는 공통 진입점
API Gateway는 여러 서비스 앞에 두는 단일 진입점입니다. 클라이언트는 내부 서비스 구조를 몰라도 게이트웨이 하나에만 요청을 보내면 되고, 게이트웨이가 인증, 라우팅, 공통 정책을 맡아 처리한 뒤 적절한 서비스로 연결합니다. 서비스마다 중복되던 입구 관리를 한 계층에 모으는 구조입니다.
Discovery
변하는 서비스 인스턴스 위치를 이름으로 찾게 해주는 메커니즘
Service Discovery는 동적으로 변하는 서비스 인스턴스의 네트워크 위치를 런타임에 이름 하나로 찾아내는 내부 주소 해결 메커니즘입니다. 호출하는 쪽은 IP나 포트를 직접 알거나 관리하지 않아도 되며, 레지스트리가 현재 살아 있는 인스턴스 목록을 관리해 줍니다. 컨테이너와 오토스케일링이 보편화된 환경에서 이름과 실제 위치를 분리하지 않으면 내부 호출 자체가 운영 변화를 버티지 못합니다.
EDA
직접 호출 대신 사건의 발생을 중심으로 연결하는 구조
Event-Driven Architecture는 서비스가 서로를 직접 호출하는 대신, '어떤 상태 변화가 일어났다'는 사실을 이벤트로 발행하고 관심 있는 서비스가 각자 반응하게 만드는 설계 방식입니다. 생산자는 소비자가 누구인지 알 필요가 없고, 소비자는 자신의 처리 속도에 맞게 독립적으로 반응합니다. 호출 그래프의 중심을 특정 서비스 주소가 아닌 발생한 사실로 바꾸는 것이 이 구조의 핵심입니다.
Queue
생산자와 소비자 사이의 속도 차이를 흡수하는 작업 버퍼
Message Queue는 생산자가 보낸 작업 메시지를 소비자가 준비됐을 때 순서대로 꺼내 처리하도록 중간에 잡아 두는 비동기 작업 버퍼입니다. 생산 속도와 처리 속도가 달라도 어느 쪽도 상대를 직접 기다리지 않아도 되고, 소비자가 잠시 다운됐다 복구되더라도 큐에 쌓인 메시지를 이어서 처리할 수 있습니다.
Pub/Sub
하나의 사건을 여러 구독자에게 fan-out하는 메시징 구조
Publish/Subscribe는 발행자가 토픽에 메시지를 올리면 그 토픽을 구독한 모든 구독자가 각자 독립적으로 메시지를 받아 처리하는 메시징 패턴입니다. 발행자는 누가 듣는지 알지 못하고, 구독자는 발행자를 직접 참조하지 않습니다. 이 분리 덕분에 새 구독자가 추가되어도 발행자 코드는 변경되지 않습니다.
Caching
반복 조회를 빠르게 만들기 위해 가까운 곳에 복사본을 두는 기법
Caching은 반복적으로 요청되는 데이터를 원본 저장소 대신 더 가까운 위치에 복사해 두고, 이후 요청이 원본까지 가지 않아도 되게 만드는 읽기 최적화 기법입니다. 원본 데이터를 바꾸지 않고 읽기 경로만 단축하기 때문에, 얼마나 오래 복사본을 믿을지와 언제 원본과 다시 맞출지를 함께 결정해야 합니다.
CQRS
읽기와 쓰기의 모델을 분리해 서로 다른 요구를 따로 최적화하는 구조
CQRS(Command Query Responsibility Segregation)는 데이터를 바꾸는 경로와 읽어 오는 경로를 서로 다른 모델로 분리하는 아키텍처 패턴입니다. 쓰기 쪽은 도메인 규칙과 정합성 검증에 맞게, 읽기 쪽은 화면이나 API가 필요한 형태로 각각 따로 유지합니다. 같은 데이터라도 '저장하는 질문'과 '보여주는 질문'이 다르면 모델도 달라야 한다는 전제에서 출발하며, 복잡한 도메인 시스템에서 쓰기 규칙과 읽기 성능이 서로를 잡아당기는 충돌을 풀어냅니다.
Saga
여러 로컬 트랜잭션을 순서와 보상으로 이어 붙이는 분산 흐름 패턴
Saga는 여러 서비스에 걸친 비즈니스 흐름을 단일 전역 트랜잭션 없이 이어 가는 분산 트랜잭션 패턴입니다. 각 서비스의 로컬 트랜잭션을 순서대로 실행하되, 중간에 실패하면 이미 완료된 단계를 되돌리는 보상 트랜잭션(compensating transaction)을 명시적으로 실행합니다. 성공 경로뿐 아니라 실패와 보상 경로까지 하나의 흐름으로 설계하는 것이 핵심이며, 마이크로서비스처럼 서비스별로 데이터를 소유하는 환경에서 분산 일관성을 현실적으로 다루는 방법으로 자리를 잡았습니다.
Breaker
실패하는 원격 호출을 잠시 끊어 연쇄 장애를 막는 패턴
Circuit Breaker는 원격 호출 경로에 삽입되어, 실패가 임계치를 넘으면 호출 자체를 잠시 차단하는 보호 패턴입니다. 응답을 기다리며 리소스를 붙잡는 대신 빠르게 실패하거나 대체 응답을 돌려줌으로써, 하나의 의존성 장애가 호출하는 쪽 서비스 전체를 끌어내리는 연쇄 장애를 막습니다. 분산 시스템에서 부분 장애를 격리하는 핵심 수단으로, 재시도 정책, 타임아웃, 관측 체계와 함께 운영됩니다.
Idempotency
같은 요청이 여러 번 와도 결과를 한 번처럼 유지하는 성질
Idempotency는 같은 요청이 두 번, 세 번 실행되더라도 최종 상태가 한 번 실행한 것과 동일하게 유지되는 속성입니다. 네트워크 재시도, 메시지 큐 재전달, 사용자의 중복 제출처럼 '정확히 한 번 실행'을 보장할 수 없는 환경에서, 중복 실행을 안전하게 흡수하는 안전망 역할을 합니다. 분산 시스템과 메시지 기반 아키텍처에서 재시도를 마음 놓고 쓸 수 있게 해주는 전제 조건이기도 합니다.
Observability
시스템 내부 상태를 외부 신호로 드러내 원인을 추적하게 하는 능력
Observability는 시스템 내부에서 무슨 일이 벌어지고 있는지를 바깥에서 추론할 수 있게 하는 관측 기반입니다. 에러가 발생했다는 사실 하나를 넘어서, 어느 서비스의 어느 구간이 느려졌고 그 실패가 어디서 시작해 어떻게 퍼졌는지까지 추적할 수 있는 신호를 시스템이 구조적으로 남기게 합니다. 분산 시스템에서 운영 판단의 근거를 만드는 기반이며, 로그, 메트릭, 트레이스 세 가지 신호가 함께 작동할 때 의미 있는 관측이 가능합니다.