소프트웨어 아키텍처 101 - CHAPTER 13 서비스 기반 아키텍처 스타일
서비스 기반 아키텍처(service-based architecture)는 마이크로서비스 아키텍처 스타일의 일종으로, 아키텍처가 유연해서 가장 실용적인 아키텍처 스타일 중 하나입니다.
13.1 토폴로지
서비스 기반 아키텍처의 기본 토폴로지는 각각 따로 배포된 유저 인터페이스와 원격 서비스, 그리고 모놀리스 데이터베이스로 이루어진 대규모 분산 레이어 구조입니다[그림 13-1].
이 아키텍처 스타일에서 서비스는 큼지막한 단위로 분리하여 별도로 배포하는 ‘애플리케이션의 일부’입니다(보통 도메인 서비스(domain service)라고 함).
서비스 기반 아키텍처의 도메인 서비스는 각각 단일 인스턴스로 배포하지만, 확장성, 내고장성, 처리량 요구사항에 따라 인스턴스를 여럿 둘 수도 있습니다.
서비스는 원격 액세스 프로토콜로 유저 인터페이스 외부에서 접속할 수 있습니다.
서비스 기반 아키텍처는 중앙 공유 데이터베이스를 사용한다는 특징이 중요합니다.
13.2 토폴로지 변형
앞서 보았던 [그림 13-1]의 단일 모놀리식 유저 인터페이스는 다시 여러 유저 인터페이스 도메인으로 나눌 수 있고, 한술 더 떠 각 도메인 서비스에 맞게 나눌 수도 있습니다[그림 13-2].
또 단일 모놀리식 데이터베이스 역시 개별 데이터베이스로 분리할 수 있고 (마이크로서비스 비슷하게) 각 도메인 서비스 전용 데이터베이스들로 쪼갤 수도 있습니다.
끝으로 [그림 13-4]처럼 리버스 프록시(reverse proxy) 또는 게이트웨이로 구성된 API 레이어를 유저 인터페이스와 서비스 사이에 구성할 수도 있습니다. 도메인 서비스의 기능을 외부 시스템에 표출하거나 (메트릭, 보안, 감사 요구사항, 서비스 디스커버리 등) 공통 관심사를 통합해서 유저 인터페이스 밖으로 떼어낼 경우에도 유용한 방법입니다.
13.3 서비스 설계 및 세분도
서비스 기반 아키텍처의 도메인 서비스는 보통 단위가 크기 때문에 도메인 서비스를 API 퍼사드 레이어, 비즈니스 레이어, 퍼시스턴스 레이어로 구성된 레이어드 아키텍처 스타일로 설계하는 것이 일반적입니다. 모듈러 모놀리스 아키텍처 스타일처럼 서브도메인을 이용해서 각 도메인 서비스를 분할하는 방법도 많이 쓰입니다[그림 13-5].
서비스를 어떻게 설계하든 도메인 서비스는 유저 인터페이스에서 비즈니스 기능을 호출하기 위해 접속할 일종의 API 액세스 퍼사드(access facade)를 필요로 합니다. API 액세스 퍼사드는 유저 인터페이스를 통해 유입된 비즈니스 요청을 오케스트레이트(orchstrate, 조정, 조율)하는 역할을 합니다.
도메인 서비스는 세분도가 큰 까닭에 단일 도메인 서비스에서 데이터 무결성을 보장하기 위해 커밋/롤백이 수반되는 여느 ACID(원자성, 일관성, 격리성, 지속성) 데이터베이스 트랜잭션을 사용하지만, 마이크로서비스처럼 분산도가 높은 아키텍처는 서비스를 더 잘게 나누어 BASE 트랜잭션(기본적 가용성(basic availability), 소프트 상태(soft sate), 최종 일관성(eventual consistency))이라고 알려진 분산 트랜잭션 기법을 사용합니다. 이 기법은 그 기반이 최종 일관성이므로 서비스 기반 아키텍처의 ACID 트랜잭션 레벨의 데이터 무결성은 지원하지 않습니다.
도메인 서비스는 단위가 커서 데이터 무결성과 일관성 측면에서 유리하지만 그에 못지 않은 트레이드오프도 있습니다. 서비스 기반 아키텍처에서 기능을 변경할 일이 생기면 전체 서비스를 테스트해야 하지만, 마이크로 서비스 아키텍처에서는 서비스 하나만 변경 영향도가 있을 것입니다. 또한 서비스 기반 아키텍처는 코드가 점점 더 많이 배포될수록 뭔가 문제를 일으킬 소지가 커지지만, 마이크로서비스 아키텍처는 각 서비스가 한 가지 역할만 수행하므로 변경을 해도 다른 기능이 망가질 일이 거의 없습니다.
13.4 데이터베이스 분할
서비스 기반 아키텍처의 서비스는 (반드시 그래야 하는 건 아니지만) 주어진 애플리케이션 콘텍스트에서 서비스 수(4~12개)가 적은 편이라서 보통 단일 모놀리식 데이터베이스를 공유합니다. 그러나 이러한 데이터베이스 커플링은 테이블 스키마 변경 시 문제가 될 수 있습니다. 테이블 스키마를 올바르게 변경하지 않을 경우 모든 서비스에 악영향을 미치기 때문에 데이터베이스 변경은 여러모로 노력과 조정이 필요한 값비싼 작업입니다.
엔티티 객체가 공유하는 단일 라이브러리를 생성하는 프랙티스는 서비스 기반 아키텍처 관점에서 가장 비효율적인 구현 방법입니다. 테이블 구조를 조금이라도 변경할 일이 발생하면 해당 엔티티 객체가 포함된 단일 공유 라이브러리도 같이 변경을 해야 하는데, 변경된 테이블의 사용 여부와 상관 없이 전체 서비스를 일제히 변경 후 재배포할 수밖에 없습니다.
데이터베이스 변경 영향도와 리스크를 낮추는 한 가지 방법은, 데이터베이스를 논리적으로 분할하고 이러한 논리 분할을 연합 공유 라이브러리(federated shared library)를 통해 명시하는 것입니다.
테이블(과 해당 엔티티 객체) 변경 영향도를 낮추는 한 가지 방법은, 공통 엔티티 객체를 버전 관리 시스템에서 락킹하고 수정 권한을 오직 데이터베이스 팀에게만 부여하는 것 입니다. 이렇게 해야 변경을 통제할 수 있고 모든 서비스의 공용 테이블을 변경하는 작업의 중요성이 부각됩니다.
13.5 아키텍처 예시
13.6 아키텍처 특성 등급
서비스 기반 아키텍처는 도메인 분할된 아키텍처입니다. 즉, (프레젠테이션 로직 또는 퍼시스턴스 로직처럼) 기술 관심사보다 도메인을 위주로 구성된 아키텍처입니다.
이 아키텍처 스타일을 응용해서 애플리케이션을 개별 배포되는 여러 도메인 서비스로 나누면 신속한 변경이 가능하고(민첩성), 도메인 범위가 한정되므로 테스트 커버리지(test covarage)가 향상되며(시험성), 덩치 큰 모놀리스보다 덜 위험하게, 더 자주 배포할 수 있습니다(배포성). 이 세가지 특성 덕분에 시장 출시를 앞당겨 신기능을 더 빨리 출시하고 신속하게 버그를 조치할 수 있습니다.
도메인 서비스는 보통 굵직굵직하게(coarse-grained) 나누지만 서비스 기반 아키텍처의 서비스는 자기 완비형이고 데이터베이스와 코드를 공유하는 까닭에 서비스 간 통신이 거의 없습니다. 따라서 어느 도메인 서비스가 잘못돼도 다른 서비스는 아무 영향도 받지 않습니다.
이 아키텍처 스타일은 단순성과 전체 비용 측면에서 마이크로서비스, 이벤트 기반 아키텍처, 공간 기반 아키텍처 등 비교적 비용이 많이 들고 복잡한 분산 아키텍처와는 차별화됩니다.
서비스 기반 아키텍처는 도메인 서비스를 굵직굵직하게 나누기 때문에 다른 분산 아키텍처에 비해 신뢰성이 우수합니다. 대규모 서비스는 서비스 간 네트워크 트래픽이 적고 대역폭을 덜 사용하며, 분산 트랜젝션이 많지 않기 때문에 전반적으로 네트워크 측면에서 신뢰성이 좋습니다.
13.7 언제 이 아키텍처 스타일을 사용하는가
서비스 기반 아키텍처는 도메인 주도 설계와 궁합이 잘 맞습니다. 서비스를 큰 단위로 나누고 그 범위를 도메인으로 한정하기 때문에 각 도메인은 개별 배포된 도메인 서비스에 딱 맞아떨어지는 거죠.
서비스 기반 아키텍처의 도메인 서비스는 큼지막한 단위로 구성되므로 다른 분산 아키텍처에 비해 ACID 트랜젝션이 더 잘 보존됩니다.
서비스 기반 아키텍처는 복잡하게 뒤얽히거나 세분도의 함정에 빠져 허우적거리지 않고도 아키텍처 모듈성을 괜찮은 수준으로 달성할 수 있습니다. 서비스가 더 잘게 쪼게지면 비즈니스 트랜잭션을 완성하기 위해 서비스를 서로 단단히 묶어주는 오케스트레이션과 코레오그래피가 필요합니다. 그러나 서비스 기반 아키텍처의 서비스는 더 큰 단위로 나눠지는 편이라서 다른 분산 아키텍처만큼 정교한 조율은 필요하지 않습니다.
요약
13.1 토폴로지
- 서비스 기반 아키텍처는 유저 인터페이스, 원격 서비스, 모놀리스 데이터베이스로 구성된 대규모 분산 레이어 구조.
- 서비스는 큼직하게 분리되어 단일 인스턴스로 배포되지만 확장성에 따라 여러 인스턴스를 가질 수 있음.
- 원격 액세스 프로토콜을 사용하여 외부에서 서비스에 접근 가능.
13.2 토폴로지 변형
- 단일 모놀리식 유저 인터페이스와 데이터베이스를 여러 도메인 서비스로 나누는 방식.
- 리버스 프록시 또는 게이트웨이 API 레이어를 추가하여 기능을 외부에 표출하거나 공통 관심사를 분리 가능.
13.3 서비스 설계 및 세분도
- 도메인 서비스는 API 퍼사드, 비즈니스 레이어, 퍼시스턴스 레이어로 구성된 레이어드 아키텍처로 설계.
- 단일 도메인 서비스에서 ACID 트랜잭션을 보장하지만, 마이크로서비스 아키텍처와 달리 더 큰 단위의 트랜잭션 처리.
13.4 데이터베이스 분할
- 서비스 기반 아키텍처는 보통 단일 모놀리식 데이터베이스를 공유.
- 데이터베이스 변경은 서비스 전체에 영향을 미칠 수 있어 논리적으로 분할하거나, 데이터베이스 팀에게 수정 권한을 부여하여 통제.
13.5 아키텍처 예시
13.6 아키텍처 특성 등급
- 도메인 서비스로 구성된 아키텍처는 신속한 변경, 높은 테스트 커버리지, 빈번한 배포가 가능.
- 마이크로서비스와 비교해 통신 비용이 적고 신뢰성이 높음.
13.7 언제 이 아키텍처 스타일을 사용하는가
- 도메인 주도 설계와 궁합이 잘 맞음.
- ACID 트랜잭션을 유지하면서도 모듈성을 잘 달성할 수 있음.
- 더 세분화된 아키텍처에서는 오케스트레이션과 코레오그래피가 필요하지만, 서비스 기반 아키텍처는 덜 복잡함.