개요
들어가며
이 부록에서는 소프트웨어 개발 과정에서 마주치게 되는 몇 가지 핵심 아키텍처 개념을 다룬다.
- 이 책을 제대로 이해하기 위해서는, 적어도 이 개념들에 대해 인지하고 고수준의 개괄적 이해를 가지고 있어야 한다.
- 여기서는 모놀리식(monolith), 서비스 지향 아키텍처(SOA: Service-Oriented Architecture), 그리고 **마이크로서비스(microservices)**를 소개한다.
- 더 깊이 학습하고 싶다면 참고할 수 있는 추가 자료도 함께 안내할 것이다
주제의 난이도
- 이 주제들은 매우 복잡하다.
- 이미 수많은 책과 수십 편의 프레젠테이션이 이 아키텍처들을 다루고 있다.
- 따라서, 단 몇 페이지로 너를 전문가로 만들 수는 없다.
- 그러나, 이 부록을 읽는 것만으로도 스프링(Spring)을 왜 특정한 시나리오에서 사용하는지 이해하는 데 큰 도움이 될 것이다.
전개 방식
우리는 하나의 애플리케이션 시나리오를 예시로 들어 살펴본다.
- 소프트웨어 개발의 초기 시절부터 출발하여,
- 오늘날에 이르기까지의 아키텍처적 접근법의 변화를 추적한다.
즉, 시대별로 어떻게 변해왔는지 → 왜 새로운 방식이 필요했는지를 보여줄 것이다.
A.1 모놀리식 접근법
모놀리식이란 무엇인가?
개발자가 어떤 앱을 “모놀리식(monolithic)” 혹은 “모놀리스(monolith)”라고 부를 때, 그것은 단 하나의 컴포넌트로 이루어진 앱을 뜻한다.
- 이 컴포넌트를 배포하고 실행하면, 그 안에 모든 기능이 구현되어 있다.
예를 들어 서점 관리 애플리케이션을 생각해보자.
- 사용자는 상품 관리, 청구서 관리, 배송 관리, 고객 관리를 수행한다.
- 그림 A.1에 제시된 시스템은 모놀리식이다. 왜냐하면 이 모든 기능이 하나의 동일한 프로세스에 포함되어 있기 때문이다.

- 애플리케이션은 단일 프로세스 내에서 모든 기능을 구현한다.
- 기능들은 프로세스 내부에서 서로 상호작용하며 비즈니스 흐름을 완성한다.
비즈니스 플로우란?
NOTE: *비즈니스 플로우(business flow)*란 사용자가 애플리케이션에서 기대하는 작업의 흐름이다.
예: 서점 주인이 책을 판매할 때의 흐름
- 상품 관리 기능이 재고에서 책을 예약한다.
- 청구 기능이 해당 책들에 대한 청구서를 생성한다.
- 배송 기능이 책 배송을 계획하고 고객에게 알린다.
→ 이 전체 과정이 하나의 “책 판매” 비즈니스 플로우다. 그림 A.2는 이를 시각화한 것이다.

- 사용자가 책을 판매하려 한다.
- 클라이언트 앱이 백엔드에 요청을 보낸다.
- 백엔드의 각 책임(상품, 청구, 배송)이 흐름 속에서 제 역할을 한다.
- 기능들은 서로 통신하며 전체 플로우를 완성한다.
- 마지막에 클라이언트 앱은 주문 상태를 응답받는다.
NOTE: 그림 A.2에서는 이해를 돕기 위해 컴포넌트 간의 통신을 단순화했다. 실제 클래스 설계는 다를 수 있다.
왜 초기에는 모놀리식을 썼는가?
처음에는 모든 애플리케이션이 모놀리식 방식으로 개발되었다.
- 그리고 이 접근법은 초창기 애플리케이션 개발에서 훌륭하게 동작했다.
1990년대에는 인터넷이 아직 몇 대의 컴퓨터만 연결한 네트워크에 불과했다.
- 하지만 불과 몇 년 만에 수십억 대의 장치를 연결하는 거대한 네트워크로 성장했다.
- 오늘날 기술은 더 이상 기술자들만을 위한 것이 아니라, 모두를 위한 것이다.
이 변화는 시스템이 처리해야 할 사용자 수와 데이터의 폭발적 증가를 의미했다.
- 30년 전만 해도, 길가에서 택시를 호출하거나, 횡단보도를 기다리면서 메시지를 보내는 일은 상상조차 할 수 없었다.
- 이런 변화는 애플리케이션이 더 많은 리소스를 필요로 하게 만들었다.
- 하지만 단일 프로세스만 사용하는 방식은 리소스 관리가 점점 더 어려워졌다.
수요 증가와 보안 요구
- 사용자 수와 데이터량만 변한 것이 아니다.
- 사람들은 이제 원격으로 거의 모든 일을 앱으로 처리한다.
예:
- 좋아하는 카페에서 카푸치노를 마시며 은행 계좌 관리까지 가능하다.
- 그러나 이런 편리함은 동시에 보안 위험을 증가시킨다.
- 따라서, 이런 서비스를 제공하는 시스템은 보안성과 신뢰성을 갖춰야 한다.
변화에 따른 대응
이 모든 변화는 애플리케이션이 만들어지고 개발되는 방식에도 영향을 끼쳤다.
단순히 사용자 수 증가만 놓고 보더라도:
- 앱이 더 많은 요청을 처리하려면 어떻게 해야 할까?
- 하나의 방법은 동일한 앱을 여러 시스템에서 실행하는 것이다.
이렇게 하면 여러 인스턴스가 요청을 나누어 처리할 수 있다.
→ 이를 수평 확장(horizontal scaling)이라고 한다.

- 동일한 애플리케이션 인스턴스를 여러 번 실행하면,
- 더 많은 리소스를 활용해 더 많은 요청을 처리할 수 있다.
(단순화된 선형 성장 가정)
- 하나의 인스턴스가 5만 개 동시 요청을 처리할 수 있다면,
- 세 개의 인스턴스를 실행하면 15만 개 동시 요청을 처리할 수 있다.
모놀리식의 단점
앱은 일반적으로 지속적으로 진화한다.
- 모놀리식 앱에서는 아주 작은 변경을 해도 전체를 다시 배포해야 한다.
- 반면, 마이크로서비스 아키텍처에서는 변경한 서비스만 다시 배포하면 된다.
- 이는 시스템 관점에서도 큰 이점이다.
모놀리식을 쓰는 게 문제인가?
그렇다고 해서 모놀리식을 쓰는 게 항상 잘못된 것은 아니다.
- 어떤 시나리오에서는 모놀리식이 최선의 선택일 수도 있다.
- 이 책에서는 모놀리식이 적합하지 않은 경우도 다루지만,
“모놀리식 = 잘못된 방식”이라는 오해를 갖지는 말아야 한다.
흔한 오해
많은 사람들이 모놀리식 앱은 유지보수가 어렵다고 불평한다.
그러나 진실은 이렇다:
- 문제가 되는 것은 “모놀리식 구조” 자체가 아니라,
- 지저분한 코드 때문일 가능성이 크다.
- 책임을 섞거나, 추상화를 제대로 쓰지 않은 설계도 유지보수를 어렵게 만든다.
즉, 모놀리식 앱이 반드시 지저분할 필요는 없다.
결론
- 소프트웨어가 발전하면서, 모놀리식 접근법이 더 이상 맞지 않는 경우도 생겼다.
- 그런 상황에서 우리는 대안(예: SOA, 마이크로서비스)을 찾아야 한다.
A.2 서비스 지향 아키텍처 사용하기
SOA를 다루는 이유
이 절에서는 서비스 지향 아키텍처(SOA)를 다룬다.
- 1.1절에서 다룬 서점 앱 사례를 다시 가져와, 모놀리식 접근법의 한계를 증명한다.
- 특정 상황에서는 앱을 설계할 때 다른 스타일을 써야 한다는 점을 보여준다.
- SOA가 어떻게 그 문제를 해결하는지 배우는 동시에, 이 새로운 접근법이 앱 개발에 추가하는 복잡성도 살펴본다.
책 판매 앱 예시 (기능 4개)
앱은 다음 네 가지 주요 기능을 포함한다.
- 상품 관리 (products)
- 배송 관리 (deliveries)
- 청구 관리 (billing)
- 고객 관리 (customers)
현실의 애플리케이션에서는 모든 기능이 동일하게 리소스를 소비하지 않는다.
- 어떤 기능은 더 복잡하거나, 더 자주 사용되기 때문에 리소스를 더 많이 요구한다.
문제는, 모놀리식 앱에서는 부분적인 확장이 불가능하다는 점이다.
- 앱 전체를 확장하거나, 아예 확장하지 않거나 둘 중 하나다.
- 하지만 실제로는 리소스를 더 필요로 하는 기능만 확장하는 것이 효율적이다. (그림 A.4)

- 일부 기능은 다른 기능보다 훨씬 자주 사용된다.
- 따라서 더 많은 리소스를 소비하며, 이 기능들만 확장이 필요하다.
모놀리식을 나누기
그렇다면, 상품 관리 기능만 확장하고 다른 기능은 그대로 둘 수 있는 방법이 있을까?
👉 가능하다.
- 모놀리스를 여러 개의 서비스로 분리한다.
- 즉, 앱의 아키텍처를 모놀리식에서 서비스 지향 아키텍처(SOA)로 바꾼다.
SOA에서는:
- 하나의 프로세스에 모든 기능을 담는 대신,
- 각 기능을 독립된 프로세스로 구현한다.
- 이렇게 하면 리소스를 더 필요로 하는 기능만 선택적으로 확장할 수 있다. (그림 A.5)

- SOA에서는 각 기능이 독립적인 프로세스다.
- 따라서 리소스가 필요한 기능만 확장할 수 있다.
SOA의 장점
SOA의 이점은 단순히 확장성에만 있지 않다.
- 책임의 분리
- 청구는 청구 전용 앱, 배송은 배송 전용 앱처럼 역할이 명확하다.
- 구현체들이 더 느슨하게 결합되고, 응집력 있게 유지된다.
- 유지보수성이 높아진다.
- 팀 관리 용이
- 모놀리식에서는 여러 팀이 모두 같은 앱을 만지기 때문에 조율이 복잡하다.
- SOA에서는 시스템이 여러 앱으로 구성되므로, 각 팀에 특정 서비스를 배정할 수 있다.
- 이로써 팀 간의 조율 부담이 줄어든다. (그림 A.6)

- 모놀리식: 하나의 앱에 여러 팀이 동시에 작업 → 높은 조율 필요
- SOA: 여러 앱으로 나눔 → 각 팀은 다른 앱을 맡아 작업 → 조율 최소화
SOA의 복잡성
겉보기에는 SOA가 이점만 있는 것처럼 보인다.
- 그렇다면 왜 모든 앱을 애초에 이렇게 만들지 않았을까?
- 왜 여전히 모놀리식이 유효한 경우가 있다고 말하는 걸까?
그 이유는, SOA를 사용하면 새로운 복잡성이 도입되기 때문이다.
SOA가 만드는 새로운 문제 영역
SOA에서는 다음과 같은 영역에서 문제가 발생할 수 있다.
- 서비스 간 통신 (Communication among the services)
- 보안 (Security)
- 데이터 영속성 (Data persistence)
- 배포 (Deployment)
A.2.1 서비스 간 통신이 만드는 복잡성
비즈니스 로직 흐름과 통신
서비스 지향 아키텍처(SOA)에서도 각 기능들은 여전히 비즈니스 로직 흐름을 구현하기 위해 서로 통신해야 한다.
- 모놀리식 접근법에서는 모든 기능이 하나의 앱 안에 있었으므로, 단순히 메서드 호출만으로 두 기능을 연결할 수 있었다.
- 하지만 이제는 각 기능이 서로 다른 프로세스로 분리되었기 때문에, 통신이 훨씬 더 복잡해진다.
네트워크의 신뢰성 문제
이제 기능들은 네트워크를 통해 통신한다.
여기서 반드시 기억해야 할 원칙이 있다:
👉 네트워크는 완전히 신뢰할 수 없다.
많은 개발자들이 “만약 통신이 끊어진다면 어떻게 될까?”를 고려하지 않고 개발하는 함정에 빠진다.
- 모놀리식 접근법과는 달리,
- SOA에서는 서비스 간의 어떤 호출도 언제든 실패할 수 있다.
이 문제를 해결하기 위해, 개발자들은 다음과 같은 기법이나 패턴을 사용한다.
- 재시도 호출(retry calls)
- 서킷 브레이커(circuit breakers)
- 캐시(caches)

- 서비스 간 통신은 시스템에 복잡성을 추가한다.
- 두 서비스 간 통신을 어떻게 구현할 것인지 결정해야 한다.
- 또한 통신이 실패했을 때 어떤 일이 일어날 수 있는지 이해하고, 그로 인한 문제를 어떻게 해결할지도 고려해야 한다.
다양한 통신 방식
서비스 간 통신을 설정하는 방법은 매우 다양하다.
- REST 서비스
- GraphQL
- SOAP
- gRPC
- JMS 메시지 브로커
- Kafka
- 기타 등등
어떤 방식이 최선인가?
정답은 하나가 아니다.
- 상황에 따라, 위의 방법 중 하나 또는 여러 개를 적절히 쓰면 된다.
- 실제로 이 주제에 대해서는, “특정 시나리오에 어떤 방식이 가장 적합한가”를 두고 책이나 커뮤니티에서 끝없는 논쟁과 토론이 이어지고 있다.
A.2.2 시스템 보안에 추가되는 복잡성
보안 문제의 등장
기능들을 별도의 서비스로 분리하면서, 우리는 보안 설정에서 새로운 복잡성을 끌어들인다.
- 서비스들은 이제 네트워크를 통해 메시지를 주고받는다.
- 이 과정에서 정보가 노출될 위험이 생긴다.
민감한 데이터의 보호
어떤 경우에는 교환되는 데이터의 일부는 절대 노출되면 안 된다.
- 예:
- 비밀번호(passwords)
- 신용/직불카드 정보(banking card details)
- 개인 데이터(personal data)
→ 이런 경우에는 데이터를 전송하기 전에 반드시 암호화(encryption) 해야 한다.
무결성(Integrity) 문제
심지어 데이터가 노출되는 것이 크게 중요하지 않더라도, 대부분의 경우 우리는 데이터가 전송 중에 변경되지 않도록 보호해야 한다.
- 모놀리식에서는 같은 프로세스 안에서 실행되므로 이런 위험이 없었다.
- 그러나 SOA에서는 서비스 간의 통신이 네트워크를 거치므로,
→ 중간에서 변조될 위험이 존재한다.

A.2.3 데이터 영속성으로 인한 복잡성
데이터 저장의 필요성
대부분의 애플리케이션은 데이터를 저장할 방법이 필요하다.
- 가장 흔한 방식은 데이터베이스(DB)를 사용하는 것이다.
모놀리식에서의 데이터 저장
모놀리식 접근법에서는 일반적으로 하나의 애플리케이션 + 하나의 데이터베이스 구조였다.
- 그림 A.9에서 보듯, 이 구조는 흔히 3계층 아키텍처(three-tier architecture)라고 불린다.
- 클라이언트 (Client)
- 백엔드 (Backend)
- 데이터베이스 (Database)
→ 단순하고, 쉽게 시각화할 수 있으며, 이해하기도 쉬웠다.

SOA에서의 데이터 저장
SOA에서는 여러 개의 서비스가 존재하고, 각각이 데이터를 저장해야 한다.
→ 따라서 선택지가 늘어난다.
- 모든 서비스가 하나의 데이터베이스를 공유할 것인가?
- 아니면 각 서비스가 자신만의 데이터베이스를 가질 것인가?
→ 그림 A.10은 이 두 가지 옵션을 시각화한다.

공유 DB vs 개별 DB
- 공유 DB
- 많은 사람들은 공유 DB가 좋지 않은 관행(bad practice)이라고 본다.
- 저자의 경험에 따르면, 모놀리스를 여러 서비스로 나눌 때 공유 DB를 사용하면 배포 악몽(deployment nightmare)이 될 수 있다.
- 개별 DB
- 그러나 서비스별로 개별 DB를 두는 것도 문제다.
- 예를 들어, 트랜잭션을 다룰 때, 하나의 DB라면 데이터 일관성을 보장하기가 쉽다.
- 하지만 여러 개의 독립 DB를 쓰면, 모든 서비스 간에 데이터가 일관되게 유지되는 것을 보장하기가 훨씬 어렵다.
A.2.4 시스템 배포로 인한 복잡성
배포 복잡성의 증가
아마도 가장 쉽게 눈에 보이는 도전 과제는, 시스템 배포(deployment)가 훨씬 복잡해진다는 점이다.
- 이제 서비스가 여러 개로 늘어났고,
- 앞 절에서 본 것처럼 데이터베이스도 여러 개일 수 있다.
- 여기에 보안 설정까지 고려해야 한다면,
→ 시스템 배포는 모놀리식보다 훨씬 복잡해진다.
“모놀리식 = 나쁘다”는 인식에 대하여
이쯤에서 자연스럽게 이런 의문이 들 수 있다:
“SOA도 이렇게 복잡한데, 왜 모놀리식 아키텍처는 부정적인 뉘앙스로 여겨질까?”
실제로 어떤 시스템에서는, SOA보다 모놀리식이 더 적합하다.
부정적 인식의 실제 이유
저자의 견해에 따르면, 모놀리식이 부정적으로 여겨지는 이유는 단순하다:
👉 “구식 시스템(old systems)”과 동일시되기 때문이다.
- 대부분의 구식 시스템은 클린 코드(clean coding)나 설계 원칙(design principles)이 고려되기 전에 구현되었다.
- 오늘날 우리는 유지보수 가능한 코드를 작성하기 위해 반드시 이 원칙들을 적용한다.
- 하지만 옛날 시스템에는 그런 개념이 없었기 때문에, 지금 보면 지저분해 보이는 경우가 많다.
이 때문에 개발자들이 과거 시스템을 유지하다가 문제가 생기면,
- 당시 구현한 사람들을 탓하는 경우도 있다.
- 그러나 진실은 그들이 잘못한 게 아니다.
- 그 당시에는 그것이 최선의 도구와 관행이었기 때문이다.
코드 품질과 아키텍처는 별개다
오늘날 많은 개발자들이 지저분하고 관리하기 힘든 코드 = 모놀리식이라고 연상한다.
그러나 이것은 오해다.
- 모놀리식 앱도 모듈화(Modular)될 수 있고, 코드도 깔끔하게 작성할 수 있다.
- 반대로, **서비스 지향 앱(SOA)**도 얼마든지 지저분하고 설계가 나쁜 코드가 될 수 있다.
A.3 마이크로서비스에서 서버리스까지
마이크로서비스란?
이 절에서는 마이크로서비스(Microservices)를 다룬다.
이 책 곳곳에서 언급되는 개념이므로, 최소한 그것이 무엇을 의미하는지는 알아야 한다.
- 마이크로서비스는 SOA(Service-Oriented Architecture)의 특정 구현 방식이다.
- 일반적으로 마이크로서비스는 단일 책임(One Responsibility)을 가지도록 설계된다.
- 또한 자신만의 데이터 영속 계층(persistence capability)을 가지며, 데이터베이스를 공유하지 않는다.
배포 방식의 변화
시간이 지나면서 애플리케이션을 배포하는 방식도 크게 변했다.
- 소프트웨어 아키텍처는 단순히 앱의 기능성에만 관련된 것이 아니다.
- 현명한 소프트웨어 아키텍트는 아키텍처를 팀이 일하는 방식과 시스템이 배포되는 방식에 맞게 조정할 줄 안다.
DevOps와 클라우드
너도 들어봤을 것이다: DevOps 운동(DevOps movement).
- 이는 단순히 소프트웨어 배포 방식뿐 아니라, 소프트웨어 개발 방식까지 아우른다.
- 오늘날 우리는 앱을 클라우드 환경에 배포한다.
- 가상 머신(Virtual Machines)
- 컨테이너(Containerized environments)
이러한 방식은 일반적으로 앱을 더 작게 쪼갤 필요성을 가져왔다.
서비스 크기의 논쟁
자연스럽게 이런 의문이 따라왔다:
“서비스는 얼마나 작아야 하는가?”
- 이 질문은 수많은 책, 기사, 토론에서 논쟁의 대상이 되었다.
- 마이크로서비스가 점점 작아지는 경향은 멈추지 않았다.
서버리스(Serverless)의 등장
서비스의 최소화는 결국 서버리스(Serverless)라는 개념까지 나아갔다.
- 이제는 몇 줄의 코드만으로 짧은 기능을 구현하고, 그것을 환경에 배포할 수 있다.
- 이런 함수는 특정 이벤트가 발생하면 실행된다.
- 예: HTTP 요청, 타이머, 메시지 이벤트 등
이러한 작은 구현을 우리는 서버리스 함수(Serverless function)라고 부른다.
서버리스의 의미
“서버리스”라는 말이 서버가 전혀 존재하지 않는다는 뜻은 아니다.
- 여전히 그 함수는 서버에서 실행된다.
- 다만, 개발자 입장에서는 서버 관련 모든 관리가 숨겨져 있다.
- 우리는 오직 비즈니스 로직 코드와 그것을 실행시키는 이벤트 트리거에만 신경 쓰면 된다.
- 겉으로 보기에는 서버가 없는 것처럼 보일 뿐이다.
A.4 추가 학습 자료 (Further Reading)
주제의 깊이
소프트웨어 아키텍처와 그 진화는 놀랍도록 흥미롭고 동시에 복잡한 주제다.
- 이 주제를 완전히 다루기에는, 책이 아무리 많아도 부족할 것이다.
- 이 책에서 내가 아키텍처 개념들을 다룬 이유는, 이후에 참조할 개념들을 네가 이해할 수 있도록 돕기 위함이다.
그러나 네가 더 깊이 들어가고 싶다면, 다음은 내가 책장에 꽂아둔 도서 목록이다.
- 이 책들은 내가 읽기를 권하는 순서대로 나열했다.
추천 도서 목록
- Microservices in Action
- 저자: Morgan Bruce, Paulo A. Pereira
- 출판: Manning, 2018
- 설명: 마이크로서비스 학습을 시작할 때 가장 좋은 입문서다.
이 책에는 마이크로서비스의 기초 개념들이 유용한 예제와 함께 잘 설명되어 있다.
- Microservices Patterns
- 저자: Chris Richardson
- 출판: Manning, 2018
- 설명: Microservices in Action을 충분히 읽은 뒤 이어서 읽기를 권한다.
실제 프로덕션 수준의 애플리케이션을 마이크로서비스로 개발하는 실용적 접근을 제시한다.
- Spring Microservices in Action
- 저자: John Carnell, Illary Huaylupo Sánchez
- 출판: Manning, 2020
- 설명: 스프링(Spring)을 활용해 마이크로서비스를 구축하는 방법을 이해하도록 돕는다.
- Microservices Security in Action
- 저자: Prabath Siriwardena, Nuwan Dias
- 출판: Manning, 2020
- 설명: 마이크로서비스 아키텍처에서 보안이 어떻게 적용되는지를 깊이 있게 다룬다.
- 보안은 어떤 시스템에서도 핵심 요소다.
- 반드시 개발 초기 단계부터 고려해야 한다.
- 이 책은 보안을 기초부터 설명하며, 마이크로서비스 보안에서 인지해야 할 요소들을 잘 보여준다.
- Monolith to Microservices
- 저자: Sam Newman
- 출판: O’Reilly Media, 2020
- 설명: 모놀리식 아키텍처를 마이크로서비스로 전환하는 패턴들을 다룬다.
또한, 반드시 마이크로서비스로 가야 하는지, 언제 그것이 옳은 선택인지를 함께 논의한다.
'책 > 스프링교과서' 카테고리의 다른 글
| [부록 C] HTTP에 대한 빠른 소개 (0) | 2025.10.03 |
|---|---|
| [부록 B] 컨텍스트 설정에 XML 사용하기 (0) | 2025.10.03 |
| [15] 스프링 앱 테스트하기 (0) | 2025.10.01 |
| [14] Spring Data를 이용한 데이터 영속성 구현 (1) | 2025.10.01 |
| [13] 스프링 앱에서 트랜잭션 사용 (0) | 2025.09.30 |