테마 선택

📚 지식 노트

AI·하드웨어·주변기기·게임·컴퓨터 시스템·이론 컴퓨터 과학·수학·개발과 운영·보안·응용 분야에 대해 알아 두면 좋은 내용을 정리한 노트다. 위에서 분야를 고르고 아래에서 노트를 고른다.

아키텍처 스타일

계층형부터 마이크로서비스까지 대표적인 아키텍처 스타일이 무엇을 얻고 무엇을 내주는지 비교한다.

목차 (7)
  1. 스타일의 두 갈래: 한 덩어리인가, 네트워크로 나뉘었나
  2. 단일 배포 스타일
  3. 분산 컴퓨팅의 오류
  4. 서비스 스타일: 서비스 기반, SOA, 마이크로서비스
  5. 이벤트 기반과 공간 기반
  6. 비교: 이 노트의 판단
  7. 어떻게 고르나

스타일의 두 갈래: 한 덩어리인가, 네트워크로 나뉘었나

아키텍처 스타일은 시스템의 큰 모양에 붙은 이름이다. "계층형"이라고 말하면 듣는 사람은 계층이 몇 개 있고 위에서 아래로 부른다는 것, 그래서 무엇이 쉽고 무엇이 어려운지까지 한 번에 떠올린다. 스타일은 처음부터 고르는 정답이 아니라 이런 말의 압축이다. 이 노트는 리처즈·포드의 Fundamentals of Software Architecture가 다루는 스타일 목록을 따라가되, 각 스타일의 장단점은 공개 자료와 이 노트의 판단으로 쓴다.

아키텍처 스타일의 두 갈래. 단일 배포 스타일에는 계층형, 파이프라인, 마이크로커널, 모듈러 모놀리스가 있고, 분산 스타일에는 서비스 기반, 이벤트 기반, 공간 기반, 오케스트레이션 SOA, 마이크로서비스가 있다아키텍처 스타일단일 배포배포 단위 하나, 함수 호출계층형파이프라인마이크로커널모듈러 모놀리스분산배포 단위 여럿, 네트워크 호출서비스 기반이벤트 기반공간 기반오케스트레이션 SOA마이크로서비스갈림길은 "부르는 쪽과 불리는 쪽 사이에 네트워크가 있는가"다
가장 큰 갈림길은 배포 단위의 수다. 단일 배포 스타일은 부품끼리 함수 호출로 말하고, 분산 스타일은 네트워크로 말한다.

단일 배포(모놀리식) 스타일은 시스템 전체가 하나로 빌드되고 배포된다. 부품 사이 호출은 함수 호출이라 빠르고 실패하지 않으며, 트랜잭션 하나로 여러 테이블을 함께 바꿀 수 있다. 분산 스타일은 여러 배포 단위가 네트워크로 말한다. 부분별로 따로 늘리고 배포할 수 있지만, 그 대가로 네트워크가 가진 모든 문제를 떠안는다. 어느 쪽이 낫다기보다, 어떤 아키텍처 특성이 필요한지에 따라 고른다(아키텍처 특성과 결정 노트).

단일 배포 스타일

단일 배포 스타일 네 가지. 계층형은 화면, 업무 규칙, 영속성, 데이터베이스 계층을 위에서 아래로 부른다. 파이프라인은 읽기, 변환, 거르기, 쓰기 단계로 데이터가 한 방향으로 흐른다. 마이크로커널은 작은 핵심 시스템에 플러그인을 붙인다. 모듈러 모놀리스는 배포 단위 하나 안에서 도메인 모듈마다 자기 스키마를 가진다계층형파이프라인마이크로커널모듈러 모놀리스화면업무 규칙영속성데이터베이스요청은 위에서아래로 한 층씩읽기변환거르기쓰기데이터가 한 방향으로 흐른다(예: 유닉스 파이프, ETL)플러그인플러그인플러그인핵심 시스템배포 단위 하나주문자기 스키마회원자기 스키마배송자기 스키마
단일 배포 스타일 네 가지의 뼈대. 모두 배포 단위는 하나지만, 코드를 나누는 기준이 다르다.
  • 계층형(layered): 화면, 업무 규칙, 영속성, 데이터베이스처럼 기술 역할로 계층을 나누고 위에서 아래로만 부른다. 가장 익숙하고 시작하기 쉽다. 각 계층이 바로 아래만 부르게 막아 두면(닫힌 계층) 한 계층을 바꿔도 위로 번지지 않는다. 약점은 업무 변경이 모든 계층을 가로지른다는 것과, 많은 요청이 하는 일 없이 계층을 그냥 통과만 하게 되기 쉽다는 것이다.
  • 파이프라인(pipeline, pipes and filters): 데이터를 한 방향으로 흘리며 단계마다 한 가지 변환만 한다. 유닉스의 cat log | grep ERROR | sort가 원형이고, ETL과 로그 처리가 흔한 예다. 단계를 끼우고 빼기 쉽지만, 사용자와 주고받는 대화형 기능에는 맞지 않는다.
  • 마이크로커널(microkernel, 플러그인 아키텍처): 작은 핵심 시스템에 기능을 플러그인으로 붙인다. 코드 편집기와 브라우저의 확장 기능, 보험 상품마다 다른 계산 규칙을 끼우는 업무 시스템이 이 모양이다. 핵심이 플러그인 계약을 얼마나 잘 정했는지가 전부다.
  • 모듈러 모놀리스(modular monolith): 배포는 하나지만 안을 도메인 모듈로 나누고, 모듈은 공개된 인터페이스로만 서로 부르며 자기 테이블만 만진다. 쇼피파이가 거대한 레일스 앱을 서비스로 쪼개는 대신 이 길을 고른 이야기가 Deconstructing the Monolith에 있다. 경계가 잘 지켜지면 나중에 모듈 하나를 서비스로 떼어 내기도 쉽다.

단일 배포의 공통 약점은 퀀텀이 하나라는 점이다(모듈성과 결합 노트). 일부만 바빠도 전체를 늘려야 하고, 한 곳의 메모리 누수가 전체를 멈추며, 작은 수정도 전체를 다시 배포한다. 코드가 커질수록 빌드와 테스트도 느려진다.

분산 컴퓨팅의 오류

분산 스타일로 가기 전에 알아 둘 목록이 있다. 1990년대 선 마이크로시스템즈에서 정리된 분산 컴퓨팅의 여덟 가지 오류다. 빌 조이와 데이브 라이언이 먼저 넷을 꼽았고, 피터 도이치가 1994년에 일곱으로 정리했으며, 제임스 고슬링이 마지막 하나를 더했다(위키백과 정리). 처음 분산 시스템을 만드는 사람이 무심코 믿는 것들이다.

분산 컴퓨팅의 여덟 가지 오류와 대비책. 네트워크는 믿을 만하다, 지연은 0이다, 대역폭은 무한하다, 네트워크는 안전하다, 토폴로지는 바뀌지 않는다, 관리자는 한 명이다, 전송 비용은 0이다, 네트워크는 균질하다는 믿음은 모두 틀렸고, 각각 시간 제한과 재시도, 호출 묶기, 필요한 필드만 보내기, 내부 인증, 서비스 탐색, 변경 조율, 비용 계산, 차이 대비가 필요하다틀린 믿음 → 그래서 설계에 넣을 것1. 네트워크는 믿을 만하다→ 시간 제한, 재시도, 멱등성2. 지연은 0이다→ 호출 수를 줄이고 묶어 보낸다3. 대역폭은 무한하다→ 필요한 필드만 주고받는다4. 네트워크는 안전하다→ 내부 통신도 인증하고 암호화5. 토폴로지는 바뀌지 않는다→ 고정 주소 대신 서비스 탐색6. 관리자는 한 명이다→ 여러 팀의 변경과 설정을 조율7. 전송 비용은 0이다→ 직렬화·네트워크 비용을 계산8. 네트워크는 균질하다→ 장비·프로토콜 차이에 대비
여덟 가지 틀린 믿음과, 믿지 않으려면 설계에 넣어야 할 것. 함수 호출에는 없던 비용이 네트워크 호출마다 붙는다.

예컨대 화면 하나를 그리려고 서비스 열 개를 차례로 부르면, 호출마다 몇 밀리초씩 붙어 함수 호출 때와는 비교할 수 없이 느려진다. 그중 하나라도 응답이 없으면 화면 전체가 멈추지 않도록 시간 제한과 재시도를 걸어야 하고, 재시도하려면 같은 요청을 두 번 받아도 괜찮게(멱등) 만들어야 한다. 아르논 로템갈오즈의 해설 Fallacies of Distributed Computing Explained가 각 오류가 실제로 어떤 사고로 이어지는지 예를 든다. 시간 제한, 재시도, 서킷 브레이커 같은 부품 자체는 설계의 부품 노트에 있다.

서비스 스타일: 서비스 기반, SOA, 마이크로서비스

세 가지 서비스 스타일. 서비스 기반은 화면 아래에 주문, 회원, 배송 같은 굵은 서비스 몇 개가 있고 데이터베이스 하나를 함께 쓴다. 오케스트레이션 SOA는 업무 서비스와 공용 서비스 사이에 통합 버스와 오케스트레이션 엔진이 있다. 마이크로서비스는 API 게이트웨이 뒤의 작은 서비스마다 자기 데이터베이스를 가진다서비스 기반굵은 서비스 몇 개데이터베이스는 대개 하나오케스트레이션 SOA중앙 엔진이 흐름을 쥐고재사용을 위해 공용 서비스로마이크로서비스작은 서비스마다자기 데이터를 가진다화면주문회원배송공유 DB업무 서비스통합 버스·오케스트레이션기업 공용 서비스공유 DBAPI 게이트웨이주문DB회원DB배송DB결제DB
세 가지 서비스 스타일. 서비스의 굵기, 흐름을 누가 쥐는가, 데이터를 나누는가가 다르다.
  • 서비스 기반(service-based): 도메인별로 굵게 나눈 서비스 몇 개(보통 열 개 안팎)가 데이터베이스를 함께 쓴다. 분산의 이점(따로 배포, 장애 격리)을 일부 얻으면서 트랜잭션과 데이터는 단일 배포처럼 다룰 수 있어, 모놀리스에서 처음 나눌 때 현실적인 중간 지점이다.
  • 오케스트레이션 SOA: 2000년대 기업 환경에서 유행한 서비스 지향 아키텍처다. 재사용을 최우선으로 해서 업무 서비스, 기업 공용 서비스 같은 기술적 층으로 나누고, 그 사이를 엔터프라이즈 서비스 버스(ESB)와 오케스트레이션 엔진이 잇는다. 재사용을 위해 공용 서비스를 모두가 부르다 보니 결합이 심해졌고, 중앙 엔진이 모든 흐름을 쥐어 작은 변경도 여러 팀의 조율이 필요했다. 지금은 주로 피해야 할 교훈으로 이야기된다.
  • 마이크로서비스: 업무 경계(도메인 주도 설계의 경계 맥락)마다 작은 서비스를 두고, 서비스마다 자기 데이터를 가지며, 따로 배포한다. 제임스 루이스와 마틴 파울러가 2014년 글 Microservices에서 그 특징을 정리했다. SOA와 반대로 재사용보다 독립을 고른다. 코드를 조금 중복하더라도 서비스끼리 엮이지 않게 한다. 대가는 분산 트랜잭션, 데이터 일관성, 관측, 배포 자동화 같은 운영 부담이다. 패턴 목록은 microservices.io에 잘 모여 있다.

파울러는 MonolithFirst에서 처음부터 마이크로서비스로 시작해 성공한 사례는 드물고, 모놀리스로 시작해 경계를 확인한 뒤 나누는 편이 안전하다고 썼다. 경계를 잘못 그은 마이크로서비스는 고치기가 모놀리스보다 훨씬 어렵기 때문이다. 어떻게 나누고 데이터를 어떻게 쪼개는지는 분해와 분산 데이터 노트에서 다룬다.

이벤트 기반과 공간 기반

이벤트 기반(event-driven) 아키텍처에서는 서비스가 서로를 부르지 않고, "주문됨" 같은 일어난 사실(이벤트)을 내보내고 관심 있는 쪽이 반응한다. 이벤트를 내는 쪽은 누가 듣는지 모르므로 결합이 느슨하고, 반응하는 쪽을 더하기 쉽다. 파울러의 What do you mean by "Event-Driven"?은 이 말이 실제로는 서로 다른 네 패턴(이벤트 알림, 상태를 실은 이벤트, 이벤트 소싱, CQRS)을 가리킨다고 짚는다. 흐름을 어떻게 짜느냐에 따라 두 토폴로지로 나뉜다.

이벤트 기반 아키텍처의 두 토폴로지. 브로커 방식은 주문 서비스가 주문됨 이벤트를 채널에 내면 재고, 결제, 알림이 각자 반응하고, 중앙에서 흐름을 아는 곳은 없다. 중재자 방식은 중재자가 주문됨 이벤트를 받아 재고, 결제, 알림 순서로 일을 시키고 결과를 받아 다음 단계를 정한다브로커 토폴로지주문주문됨채널재고결제알림각자 반응하고, 흐름 전체를 아는 곳이 없다중재자 토폴로지주문됨 ↓중재자주문 흐름① 재고② 결제③ 알림순서와 오류 처리를 한곳에서 정한다브로커는 느슨하고 빠르지만 흐름이 안 보이고, 중재자는 흐름이 보이지만 중재자에 묶인다
브로커와 중재자. 같은 주문 흐름을 브로커는 각자의 반응으로, 중재자는 한곳의 지휘로 처리한다. 이 둘은 분해 노트의 코레오그래피·오케스트레이션과 같은 선택이다.

브로커 방식은 확장과 응답성이 좋지만, 전체 흐름이 코드 어디에도 한곳에 적혀 있지 않아 "주문이 왜 배송까지 안 갔지?"를 추적하기 어렵다. 오류가 나도 누가 되돌릴지 정하기 어렵다. 중재자 방식은 흐름과 오류 처리가 한곳에 보이는 대신 중재자가 병목과 결합의 중심이 된다. 큐와 스트림 자체는 배치와 스트림 처리 노트에 있다.

공간 기반(space-based) 아키텍처는 극단적인 트래픽 급증을 노린다. 공연 예매 시작이나 한정 판매처럼 평소의 수백 배가 순간에 몰리면, 아무리 앱 서버를 늘려도 결국 데이터베이스가 병목이 된다. 그래서 데이터베이스를 요청 경로에서 빼 버린다. 처리 장치마다 메모리 데이터 격자를 두고 서로 복제하며, 데이터베이스 쓰기는 큐를 거쳐 나중에 비동기로 한다. 이름은 여러 프로세스가 함께 쓰는 공유 메모리 공간(튜플 공간)이라는 옛 개념에서 왔다.

공간 기반 아키텍처. 요청은 처리 장치 여러 대로 나뉘고, 처리 장치마다 메모리 데이터 격자를 두어 서로 복제한다. 데이터베이스 쓰기는 데이터 펌프와 기록기를 거쳐 요청 경로 밖에서 비동기로 일어난다요청처리 장치데이터 격자처리 장치데이터 격자처리 장치데이터 격자복제데이터펌프기록기DB비동기로 나중에 쓴다요청은 메모리에서 끝나고, 데이터베이스는 요청 경로 밖에 있다
공간 기반 아키텍처. 처리 장치를 늘리면 메모리 격자도 함께 늘어나므로 데이터베이스가 병목이 되지 않는다. 대신 복제 지연과 메모리 크기, 데이터베이스와의 어긋남을 감당해야 한다.

비교: 이 노트의 판단

아래 표와 그림은 이 노트가 공개 자료와 경험칙으로 매긴 거친 판단이다. 같은 스타일도 구현에 따라 크게 달라지므로 점수가 아니라 대화의 출발점으로 쓴다.

스타일배포 단위데이터잘하는 것내주는 것
계층형하나DB 하나단순함, 낮은 비용, 익숙함규모와 변경이 커지면 경직된다
파이프라인하나단계 사이로 흘림단계별 재사용, 일괄 처리대화형 기능, 부분 확장
마이크로커널하나핵심 + 플러그인별기능을 끼우고 빼기핵심 계약을 바꾸기 어렵다
모듈러 모놀리스하나모듈별 스키마도메인 경계, 나중에 나누기 쉬움경계를 지키는 규율이 필요, 확장은 통째로
서비스 기반몇 개대개 공유분산 이점과 단순함의 균형공유 DB가 결합 지점으로 남는다
이벤트 기반여럿서비스별응답성, 확장, 반응하는 쪽 추가흐름 추적, 오류 처리, 일관성
공간 기반여럿메모리 격자 + 비동기 DB극단적 급증과 탄력성복잡하고 비싸며 데이터가 어긋날 수 있다
오케스트레이션 SOA여럿대개 공유기업 공용 기능 재사용강한 결합, 중앙 엔진 병목, 느린 변경
마이크로서비스아주 많음서비스별독립 배포, 부분 확장, 장애 격리운영 부담, 분산 트랜잭션, 네트워크 비용
아키텍처 스타일 지도. 가로축은 분산과 운영의 복잡도, 세로축은 부분별로 따로 바꾸고 늘리는 능력이다. 계층형, 파이프라인, 마이크로커널, 모듈러 모놀리스는 왼쪽 아래, 서비스 기반은 가운데, 이벤트 기반, 공간 기반, 마이크로서비스는 오른쪽 위에 있고, 오케스트레이션 SOA는 복잡하지만 따로 바꾸는 능력은 낮은 오른쪽 아래에 있다. 위치는 이 노트의 판단이다부분별로 따로 바꾸고 늘리는 능력 ↑분산·운영 복잡도 →낮음높음계층형파이프라인마이크로커널모듈러 모놀리스서비스 기반오케스트레이션 SOA이벤트 기반공간 기반마이크로서비스단일 배포분산위치는 이 노트의 판단이다
같은 판단을 두 축에 놓은 지도. 오른쪽으로 갈수록 운영이 어려워지므로, 위로 올라가는 이득이 필요할 때만 오른쪽으로 간다. 오케스트레이션 SOA는 비용에 비해 독립성을 얻지 못한 경우다.

어떻게 고르나

스타일 고르기도 트레이드오프 분석이다. 출발점은 유행이 아니라 이 시스템이 꼭 잘해야 하는 특성 서너 개, 그리고 그 특성이 시스템 전체에 같은지 부분마다 다른지다. 전체가 같은 특성을 가져도 되면 퀀텀 하나로 충분하므로 단일 배포가 가장 싸다. 부분마다 확장 규모, 가용성, 배포 주기가 크게 다르면 그때 퀀텀을 나눌 이유가 생긴다.

스타일을 고르는 질문 사다리. 부분마다 필요한 특성이 크게 다르지 않으면 모듈러 모놀리스로 시작한다. 다르지만 분산 운영을 감당하기 어려우면 서비스 기반을 고른다. 감당할 수 있고 업무가 사건에 반응하는 흐름이면 이벤트 기반, 요청-응답 흐름이면 마이크로서비스를 고려한다부분마다 필요한 특성이 크게 다른가?(확장 규모, 가용성, 배포 주기)아니오모듈러 모놀리스로 시작도메인으로 나눠 두기예여러 팀이 따로 배포하고 분산 운영을감당하나? (관측, 자동 배포, 장애 대응)아니오서비스 기반굵은 서비스 몇 개 + 공유 DB예업무가 요청-응답 흐름 중심인가?(아니면 사건에 반응하는 흐름인가)아니오이벤트 기반급증이 극단적이면 공간 기반예마이크로서비스작은 서비스마다 자기 데이터, 독립 배포어느 답이든 나중에 다시 묻는다
질문을 하나씩 내려가며 '아니오'에서 멈춘다. 더 분산된 스타일은 더 많은 '예'를 요구한다. 실제로는 한 시스템 안에서 스타일을 섞는 경우도 많다.

기술 외의 조건도 크게 작용한다. 팀이 하나라면 마이크로서비스의 이점(팀별 독립 배포)을 누릴 사람이 없다. 관측 도구, 자동 배포, 장애 대응 체계가 없다면 분산 시스템은 장애를 찾는 데만 며칠이 걸린다. 데이터가 강하게 엮여 있고 즉시 일관성이 꼭 필요하면 분산의 비용이 커진다. 그리고 어떤 스타일을 고르든, 고른 이유와 그때의 불확실성을 ADR로 남겨 두고, 조건이 바뀌면 다시 묻는다.