결론 먼저
서비스 분리는 비즈니스 도메인에 따라 수행하는 것이 적합하다. 이는 각 서비스가 특정 도메인에 집중할 수 있게 해주며, 서비스 간 의존성을 낮추는 장점이 있다. 대신, 이런 결정을 통해 기술적 복잡도와 서비스 간의 인터페이스 관리의 어려움을 포기하게 된다.
맥락
이 글은 모놀리스를 마이크로서비스로 분해하거나 기존 서비스를 더 작게 쪼갤 때 "어떤 기준으로 자를 것인가" 를 정해야 하는 상황을 가정한다. 트래픽 규모, 팀 규모, SLO 같은 구체 수치는 시스템마다 다르므로 이 글에서는 결정 축만 정리하고, 가중치는 각자의 맥락에서 조정한다.
비교한 대안들
- 기능 기반 분리: 기능 모듈에 따라 서비스를 나누는 방식.
- 팀 구조 기반 분리: 각 팀의 구조에 따라 서비스를 운영하기 위한 분리.
- 기술 스택 기반 분리: 기술 스택이나 사용 언어에 따라 서비스 분리.
N축 비교
| 축 | 기능 기반 분리 | 팀 구조 기반 분리 | 기술 스택 기반 분리 |
|---|---|---|---|
| 장애 격리 | 보통 | 높음 | 보통 |
| 배포 주기 | 빈번함 | 보통 | 빈번함 |
| 운영 부담 | 높음 | 보통 | 낮음 |
| 복잡도 | 높음 | 보통 | 높음 |
| 비용 | 보통 | 높은 비용 | 낮은 비용 |
| 변경 비용 | 중간 | 중간 | 중간 |
| 디버그 난이도 | 높음 | 보통 | 높음 |
채택한 이유
비즈니스 도메인에 따라 서비스를 분리하면 장애 격리와 각 서비스의 배포 주기를 효율적으로 관리할 수 있다. 특히, 장애가 발생하더라도 해당 도메인에 집중한 서비스만 영향을 받기 때문에 시스템의 전체적인 안정성을 높이는 데 주안점을 두었다.
살아남는 위험
- 서비스 간의 의존성이 생길 경우, 변경 시 예기치 않은 이슈가 발생할 수 있다. 완화책으로, 서비스 간의 계약을 명확히 하고 지속적인 테스트를 통해 검증해나가야 한다.
- 도메인 분리에 따른 기술적 복잡성이 증가할 수 있다. 이 부분은 충분한 문서화와 팀 내 교육으로 경감시킬 수 있다.
- 초기 구축에 많은 시간과 비용이 소요될 수 있다. 이를 해결하기 위해 프로토타입을 통해 간단한 모델을 먼저 구현해 테스트할 수 있다.
되돌리는 조건
서비스 분리에 따른 피드백을 반드시 수집하고, 서비스간 의존성 문제가 발생하거나 장애가 빈번해질 경우 즉시 점검해야 한다. 또한, 일정 기간 내에 서비스가 명확한 비즈니스 가치를 제공하지 못하면 이 결정은 다시 고려되어야 한다.
추상에서 실제로 — 내 AI 음성 상담 시스템을 도메인으로 자른 사례
위까지는 "무슨 기준으로 자를 것인가"의 결정 축만 정리했다. 여기서부터는 그 기준을 내가 실제로 운영하는 1:1 AI 음성 상담 시스템에 적용했을 때 무엇이 달라졌는지를 before/after로 남긴다. 추상 원칙은 사례로 검증되지 않으면 그냥 말이다.
도메인 경계를 어디에 그었나 — 시간축이 다른 곳
이 시스템에는 성질이 완전히 다른 두 덩어리가 있었다.
┌──────────────────────────┐ ┌──────────────────────────┐
│ 미디어 평면 │ │ 비즈니스 평면 │
│ (media plane) │ │ (business plane) │
├──────────────────────────┤ ├──────────────────────────┤
│ RTP forward, ICE 협상 │ │ 세션 메타(누가·언제) │
│ codec, Dumb Pipe SFU(RGS) │ │ 권한, billing, 통계 집계 │
│ │ │ APS/PCS │
├──────────────────────────┤ ├──────────────────────────┤
│ 단위: ms │ │ 단위: 초 ~ 분 │
│ 에러 = 즉시 통화 실패 │ │ 에러 = 후속 처리 지연 │
│ (동기적) │ │ (eventual 허용) │
└──────────────────────────┘ └──────────────────────────┘
└─── 네트워크 경계로 분리 ───┘
경계를 그은 자리는 "시간축의 단위가 바뀌는 곳"이었다. 미디어는 ms 단위로 지연이 사용자 경험에 직결되고, 비즈니스는 통계가 1초 늦어도 사용자가 모른다. 이 둘을 한 프로세스에 두면 더 빡빡한 쪽(ms)의 SLA에 느슨한 쪽까지 묶여버린다. 즉 도메인 경계 = SLA·장애 동기성·변경의 결이 함께 바뀌는 단층선이다.
Before / After
Before — 한 프로세스에 두 책임을 다 넣었을 때 (데모 초기)
- 비즈니스 로직 한 줄(예: billing 규칙)을 고치려고 배포하면 미디어 프로세스까지 재시작 → 진행 중인 상담 통화가 끊긴다.
- 비즈니스 평면 e2e 테스트가 도는 동안 미디어 코드가 굳어 있다.
- 한쪽 panic이 다른 쪽까지 죽인다. 코드량이 작을 때는 안 보이던 이 비용이 며칠 굴리는 사이 누적됐다.
After — 미디어/비즈니스를 두 서비스로 분리한 뒤
- billing·통계 변경이 미디어 경로를 건드리지 않는다 → 통화 중 무중단 배포.
- SFU를 "패킷을 디코딩하지 않는다"는 한 줄 원칙의 Dumb Pipe로 고정(RGS)하니, 미디어 평면은 변경 빈도 자체가 낮아져 안정 구간이 됐다.
- 한쪽 장애가 네트워크 경계에서 멈춘다. "어제 통화 음성이 떨렸다"는 신고가 들어와도 의심 범위가 미디어 평면으로 좁혀진다.
확장된 트레이드오프 표 — 왜 "도메인 기반"이 이겼나
원문 표는 기능/팀구조/기술스택 세 가지만 비교했다. 채택한 도메인 기반을 같은 축에 올려 보면 차이가 분명하다.
| 축 | 기능 기반 | 팀 구조 기반 | 기술 스택 기반 | 도메인 기반(채택) |
|---|---|---|---|---|
| 장애 격리 | 보통 | 높음 | 보통 | 높음 — SLA 단층선과 일치 |
| 배포 주기 결합 | 중 | 중 | 높음 | 낮음 — 미디어/비즈니스 독립 |
| SLA 결합 | 중 | 중 | 높음 | 낮음 — ms와 분이 분리됨 |
| 관찰성 | 보통 | 보통 | 낮음 | 높음 — 평면별 신호 분리 |
| 디버그 범위 | 넓음 | 보통 | 넓음 | 좁음 — 증상→평면 매핑 |
| 변경의 결 | 섞임 | 섞임 | 언어로 섞임 | 가지런 — codec vs 규칙 분리 |
도메인 기반이 강한 이유는 단 하나로 압축된다: 장애·SLA·변경 빈도가 갈리는 선과 서비스 경계가 같은 자리에 놓이기 때문이다.
잘못 자르면 — 기술 스택으로 가른 반례
반대 사례도 직접 겪었다. C·C++·C#·Java가 혼재한 레거시를 MSA로 옮길 때, "언어/기술 스택"을 경계로 삼아 DLL·Jar를 도커로 감싸 gRPC로 잇는 방식을 검토했다. 결론은 비효율이었다: 래핑 오버헤드·디버깅 복잡도·운영 부담이 전환 이점을 상쇄했다. 그래서 기술이 아니라 도메인 단위로 다시 보고, 레거시는 담당 팀에 이관 + 신규 도메인만 Go로 새로 구현하는 전략으로 틀었다. 교훈: 경계를 "언어가 다른 곳"이 아니라 "도메인이 다른 곳"에 그어야 한다.
되돌리는 조건 — 측정 가능한 신호로
원문의 "되돌리는 조건"을 운영에서 실제로 보는 신호로 구체화한다. 아래가 보이면 경계가 틀렸다는 뜻이다.
- 한 유스케이스 처리에 cross-service 호출이 계속 늘어난다 → 과분할(경계를 너무 잘게 그음). 두 서비스를 다시 합치는 걸 검토.
- 두 서비스를 늘 함께 배포해야 한다 → 경계가 가짜다. 진짜 독립 도메인이 아니다.
- 분리했는데도 한쪽 장애가 다른 쪽으로 전파된다 → 경계 누수(공유 DB·동기 호출). 계약과 비동기화로 막는다.
- 서비스가 일정 기간 명확한 비즈니스 가치를 못 낸다 → 도메인으로 설 만큼 크지 않았다. 상위 도메인으로 흡수.
함께 읽기
- 미디어/비즈니스 평면을 두 서비스로 쪼갠 4축 비교 (이 글의 사례 출처)
- 1:1 음성 상담에서 SFU를 Dumb Pipe로 둔 이유 (미디어 평면 경계의 근거)
- MSA 전환 전략 — 레거시 공존 vs 팀 이관 + Go 신규 (기술 스택 경계의 반례)
참고 개념: DDD의 Bounded Context(도메인 경계), Sam Newman 『Building Microservices』의 "서비스는 비즈니스 능력(business capability) 단위로 자른다" 원칙. 이 글의 결론은 그 원칙을 내 시스템의 시간축·SLA 단층선으로 재해석한 결과다.
답글 남기기