MSA Pattern #1 모놀리식 지옥에서 벗어나라
마이크로서비스 패턴(크리스 리처드슨, 길벗, 2020)을 읽고 공부한 내용을 정리한 글입니다.
모놀리식 아키텍쳐의 장점
- 간단한 개발: IDE 등 개발 툴이 단일 어플리케이션 개발에 중점
- 어플리케이션 변경의 용이성: 코드, DB 스키마를 변경해서 빌드/배포하기 편함
- 쉬운 테스트: REST API를 호출하고, 셀레늄으로 UI를 시험하는 E2E 테스트를 작성하기 쉬움
- 쉬운 배포: 서버에 접속해 톰캣 설치 경로에 WAR를 새로 넣어주기만 하면 됨
- 쉬운 확장: 로드밸런서 뒤에 어플리케이션 인스턴스를 여러개 실행할 수 있음
모놀리식 아키텍쳐의 한계
- 규모가 커지면 복잡도가 증가한다.
- 개발 생산성 하락: 어플리케이션이 커지면 개발자의 IDE 속도가 하락하고, 빌드가 오래 걸리며, 어플리케이션을 켜거나 테스트를 돌리는데도 시간이 오래 걸린다.
- 커밋, 배포가 복잡함: 여러 개발자가 같은 코드 베이스에 커밋을 하니, 자유롭게 릴리즈할 수 없을 떄가 많고, 브랜치 기반으로 개발을 하더라도, 머지 단계가 복잡해진다는 단점
- 어려운 확장: 모듈마다 리소스 요구 사항이 달라 확장하기 어려운 구조가 됨. 기능 별로 메모리가 중요한지, CPU 성능이 중요한지 등 리소스 요구 사항이 모두 달라 요구 사항을 충족시키기 어려움
- 신뢰성 부족: 덩치가 커지면 철저하게 테스트하기 어려움. 테스트 부족으로 인한 프로덕션 버그 발생 가능성 증가
마이크로서비스의 장점
- 크고 복잡한 어플리케이션을 지속적으로 전달/배포 가능
- 테스트성: 마이크로서비스는 상대적으로 크기가 작아서 자동화 테스트를 작성하기 쉽고 더 빨리 실행되며, 어플리케이션 버그도 적은 편
- 배포성: 마이크로서비스는 독립적으로 배포할 수 있어서 프로덕션에 변경분을 반영하기 수월함
- 자율성, 느슨한 결합: 팀별로 독립적으로 서비스를 개발, 배포, 확장할 수 있으므로 개발 속도가 빨라짐
- 각 서비스의 규모가 작아서 관리 용이
- 각 서비스의 규모가 작아, IDE도 느려지지 않고, 개발 생산성도 향상
- 각 서비스를 독립적으로 배포/확장 가능
- 리소스 요건이 다른 컴포넌트를 각각 배포할 수 있다는 장점
- 결함 격리 가능
- 특정 서비스에서 문제가 발생하더라도 다른 서비스는 정상 가동
- 새로운 기술을 실험하고 도입하기 쉬움
- 서비스에 가장 알맞은 언어와 프레임워크를 자유롭게 선택할 수 있음
마이크로서비스의 단점
- 분산 시스템은 복잡해서 개발, 테스트, 배포가 어려움
- 서비스 간 통신에 필수적인 IPC는 단순 메소드 호출보다 복잡함
- 특정 서비스의 다운으로 인한 실패 처리의 필요
- 서비스마다 DB가 따로 존재하기 때문에 다중 DB에 접속해 조회하고 트랜잭션을 구현하는 일은 난이도가 높음 → SAGA 기술을 이용해 서비스 간 데이터 일관성을 유지
- 단순 쿼리로는 여러 서비스에 있는 데이터를 조회할 수 없어 API를 조합하거나 CQRS 뷰로 쿼리
- 운영 복잡도가 증가하므로, 프로덕션에서 관리할 요소가 많아짐
- 자동화 배포 툴 - 넷플릭스 스핀네이커 등
- 컨테이너 오케스트레이션 도구 - 쿠버네티스, 도커 스웜 등
- 여러 서비스에 걸친 기능을 배포할 때 조심해야 함
- 서비스 간 디펜던시에 따라 서비스 배포 계획을 빈틈없이 수립해야 함
- 마이크로서비스 아키텍쳐 도입 시점을 결정하기 어려움
마이크로서비스의 패턴
마이크로서비스를 위한 상용 패턴의 구조는 3가지로 나뉨
- 강제 조항(forces)
- 결과 맥락(resulting context)
- 연관 패턴(related patterns)
강제 조항
문제 해결을 위해 반드시 처리해야만 하는 내용을 뜻함
단, 내용들이 서로 상충할 수 있게 모든 조항을 충족할 수 없을 수 있으므로, 우선순위를 설정할 것
예시) 코드는 이해하기 쉬워야 하면서, 성능도 우수해야 함 → 어떤 이슈를 우선적으로 해결할 것인지?
결과 맥락
패턴 적용 결과를 분석하는 일을 뜻함
- 장점: (해결된 강제 조항 등) 패턴의 좋은점
- 단점: (미해결 강제 조항 등) 패턴의 나쁜점
- 이슈: 패턴 적용 시 발생한 새로운 문제점
연관 패턴
- 선행자(predecessor): 이 패턴을 필요하게 만든 선행 패턴. MSA 패턴은 모놀리식을 제외한 나머지 패턴들의 선행자
- 후행자(successor): 이 패턴으로 야기된 이슈를 해결하는 패턴. 마이크로서비스 아키텍쳐 패턴을 적용하려면 서비스 디스커버리 패턴, 서킷 브레이커 패턴 등 후행자 패턴을 함께 적용해야 함
- 대안(alternative): 이 패턴의 대체 솔루션을 제공하는 패턴. 가령 모놀리식 아키텍쳐 패턴과 마이크로서비스 아키텍쳐 패턴은 서로 대신할 수 있는 아키텍쳐링 수단.
- 일반화(generalization): 문제를 해결하는 일반적인 솔루션에 해당하는 패턴
- 세분화(specialization): 특정 패턴을 더 세부적으로 나타낸 형태
마이크로서비스 아키텍쳐
- 인프라 패턴: 개발 영역 밖의 인프라 문제를 해결
- 어플리케이션 인프라: 개발에도 영향을 미치는 인프라 문제를 해결
- 어플리케이션 패턴: 개발자가 맞닥뜨리는 문제를 해결
어플리케이션을 여러 서비스로 분해하는 패턴
통신 패턴
마이크로서비스 아키텍쳐의 어플리케이션은 분산 시스템이기 때문에 프로세스 간 통신(IPC)이 중요하다. 그러므로 서비스 상호 간, 그리고 외부 세계와 어떻게 통신하면 좋을지 아키텍쳐/설계 관점에서 의사 결정이 필요함
통신 패턴은 다섯 개의 그룹으로 정리할 수 있음
- 통신 스타일: 어떤 종류의 IPC를 사용하는가?
- 디스커버리: 서비스 클라이언트는 서비스 인스턴스의 IP 주소를 어떻게 가져오는가?
- 신뢰성: 서비스 불능 시 서비스 간 통신의 신뢰성은 어떻게 보장되는가?
- 트랜잭셔널 메시징: 비즈니스 데이터를 업데이트하는 DB 트랜잭
- 외부API: 어플리케이션 클라이언트는 서비스와 어떻게 통신하는가?
트랜잭션 관리를 위한 데이터 일관성 패턴
- 서비스마다 DB가 있으면 트랜잭션 문제가 생김
- 사가 패턴을 이용해 데이터 일관성을 유지해야 함
데이터 쿼리 패턴
- 서비스마다 DB가 존재하므로 데이터를 조인하는 쿼리도 문제
- 서비스 데이터는 오직 그 서비스의 API를 통해서만 접근할 수 있기 때문에 DB에 분산 쿼리를 사용할 수 없음
- 따라서 API 조합 패턴이나 CQRS 등을 활용함
- API 조합 패턴: 하나 이상의 서비스를 호출해서 결과를 조합
- CQRS(Command Query Responsibility Segregation): 하나 이상의 데이터 레플리카를 유지해서 쉽게 쿼리하는 방식
서비스 배포 패턴
- 마이크로서비스 어플리케이션은 다양한 언어와 프레임워크로 구현된 수십~수백 개의 서비스로 이루어져 있기 때문에 배포 작업이 훨씬 복잡함
관측성 패턴
어플리케이션의 런타임 동작을 이해하고 요청 실패, 높은 지연 시간 등 문제를 진단/조치하는 일
마이크로 서비스 아키텍쳐는 요청 결과가 클라이언트에 반환되기까지 어떤 서비스를 어떻게 오갈지 알 수 없음. 따라서 로그 파일 하나만으로는 원인을 파악할 수 없음. 문제의 원인을 찾고 진단하기 매우 복잡함.
- 헬스 체크 API: 서비스 가동 상태를 반환하면 엔드포인트를 노출
- 로그 수집: 서비스 내역을 기록하고 중앙 로깅 서버에 로그를 출력하여 검색/경고 기능을 제공
- 분산 추적: 외부 요청마다 ID를 부여하여 서비스를 통과하는 과정을 추적
- 예외 추적: 예외가 발생하면 예최 추적 서비스에 보고. 서비스는 중복된 예외를 걸러내고 개발자에게 경고를 보내거나 상태를 추적
- 어플리케이션 지표: 카운터, 게이지 등의 지표를 측정하여 지표 서버에 표출
- 감사 로깅: 사용자가 한 일을 기록
서비스 테스트 자동화 패턴
마이크로 서비스 아키텍쳐는 단위 서비스의 크기가 비교적 작아 테스트하기 쉬우ㅏㄴ, 서로 다은 여러 서비스가 조화롭게 잘 작동되는지 테스트해야 함
- 컨슈머 주도 계약 테스트: 클라이언트가 의도한 대로 서비스가 동작하는지 확인
- 컨슈머 사이드 계약 테스트: 클라이언트와 서비스가 상호 통신 가능한지 확인
- 서비스 컴포넌트 테스트: 각 서비스 별로 테스트