서비스별로 DB를 꼭 분리해야하나요?
"서비스별로 DB를 꼭 분리해야하나요?"
MSA프로젝트 또는 서비스 정의 워크샾때 가장 많은 듣는 질문중의 하나다.
"우리 회사는, 우리 도메인은, 우리 업무는 데이터 연관성이 너무 많아서 DB를 분리하기 어렵습니다"
"Application Server 만 분리하고 DB는 통합해서 같이 사용하면 안되나요?"
"DB분리를 하지 않으면 Microservice라고 할 수 없나요?"
"Hybrid MSA인가 WAS만 나눌수도 있다고 하던데요"
위와 같이 질문은 다양하지만, 결론은 DB를 분리하고 싶지 않다는 것이다. 하기 싫다는 것이다.
MSA를 하라고 하니, 하긴 해야겠지만 DB까지 분리하면 너무 힘들다는것이다.
1990년대 초반(1993년에 에릭 에반스의 DDD책 출간)부터 등장한 DDD에서부터 DB에 대한 많은 이야기가 있었다.
하나씩 살펴보면서 정말 분리하는게 맞는지 생각해보자.
우선 DDD에서 이야기하는 Bounded Context, 그 전에 Context를 나눠야 하는 이유에 대해 생각해보자
책을 개념화하고 제안 -> 저자와 계약 -> 책의 저작권 및 편집 프로세스 관리 -> 그림 등 책의 레이아웃 디자인 -> 다른 언어로 책을 번역 -> 실제 인쇄/전자책 출간 -> 마케팅 -> 판매 -> 배송
이와 같이 책의 생명주기(Life Cycle)가 다양한 단계로 나뉘어 나타나는 상황에서 출판 조직이 다뤄야 하는 모델리의 어려움을 생각해보자. 책이 이와 같은 여러 컨텍스트를 거치며 진행되는 상황처럼 출판사도 이와 비슷한 단계를 따라서 처리하게 된다. 각 단계마다 책을 모델링하는 올바른 방법이 단 한 가지뿐인가? 각 단계마다 책은 다른 정의를 가진다.
만약 여러분이 이 수명주기의 전 단계를 관장하는 중앙 모델을 설꼐하려 하면 어떻게 될까? 아마 많은 혼란, 의견 불일치, 다툼이 있을 것이고 고객에게 약속한 소프트웨어는 나올 수 없을 것이다. 심지어 맞는 공통의 모델이 어쩌다 만들어졌다 해도, 모든 고객의 요구를 충족시키기 매우 어렵고 아주 가끔씩만 가능할 것이다.
이런 종류의 바람직하지 않은 혼돈을 해결하고자, 모델링을 위해 DDD를 사용하는 출판사는 각 수명주기마다 개별적인 바운디드 컨텍스트를 사용한다. 모든 바운디드 컨텍스트 하나하나는 책의 유형을 갖고 있다. 책 객체는 거의 혹은 모든 컨텍스트에 걸쳐 하나의 식별자를 공유하며, 아마도 이는 개념화 단계에서 최초로 설정됐을 것이다.
그러나 각 컨텍스트마다 책의 모델은 서로 다를 것이다.
이는 아무런 문제가 없으며, 오히려 이렇게 돼야한다. 바운디드 컨텍스트 안에 있는 팀이 책에 관한 말할 땐 해당 컨텍스트에서 요구한 의미와 정확히 같은 의미를 나타낸다. (이는 UL와도 관련되는데 이것은 따로 이야기하자)
이 조직은 다양성에 관한 자연스러운 요구를 받아들이게 된다.
...
명시적인 바운디드 컨텍스트를 활용하면 비즈니스적 요구를 정확히 반영하며 점진적으로 개선되는 소프트웨어를 주기적으로 배포할 수 있다.
- Implementing Domain-Driven Design, 반버논 > 2장 도메인, 서브도메인, 바운디드 컨텍스트 (p122 ~ 123)
모델이 영속석 데이터베이스 스키마의 생성을 주도할 때 데이터베이스 스키마는 경계의 안쪽에 위치한다.
이는 모델링 팀이 스키마를 설계하고 개발해서 유지하기 때문에 그렇다.
- Implementing Domain-Driven Design, 반버논 > 2장 도메인, 서브도메인, 바운디드 컨텍스트 (p125)
만약 어떤 개념이 여러분의 유비쿼터스 언어 안에 들어있지 않다면, 애초에 여러분의 모델에 들어오지 말아야 한다.
만약 한 개 이상의 외부 개념이 여전히 비집고 들어오려 한다면 없애버리자.
이는 아마 다른 지원 혹은 범용 서브도메인에 속하거나, 아예 어떤 모델안에도 속하지 못한다.
- Implementing Domain-Driven Design, 반버논 > 2장 도메인, 서브도메인, 바운디드 컨텍스트 (p127)
Context별로 모델을 갖어야 하고, DB 스키마는 내 Context 경계 안쪽에 위치해야하고,
내가 관리하는 서비스내의 스키마에 대해 추가/변경 등의 Control을 다른팀에서 반대한다면 내 서비스내 스키마에 둘 수 없다는 의미. 이러한 내용을 요약하면 서비스별로 DB 스키마를 명확하게 분리하고 각자 Control하는데 문제가 없어야, 간섭이 없어야한다는 의미이다. 그런데 이러한 DB를 통합하겠다면?
기존의 통합DB를 사용하는 대규모 Enterprise 구축 프로젝트를 상상해보자.
예를들어 주문, 원장, (의료정보)처방 등 전 시스템에서 참조하는 메인 테이블은 컬럼이 수십에서 백여개로 구성된다.
여러 업무에서 참조하므로 필요한 컬럼을 해당 테이블 담당자에게 요청해서 추가/변경한다.
컬럼 이름부터, Datatype, 코드값까지 요청하지만 정작 그 메인 테이블의 담당자도 모르는 컬럼이 존재하게된다.
그렇다보니 담당자라 하더라도 마음대로 바꿀수 없고, 관련된 어떤 작업이 있을때 마다 각 업무에서 요청한 컬럼의 개별 담당자에게 확인하고 협조를 요청해야한다.
얼마나 피곤했는가? 앞으로도 계속 이렇게 일해야하는가? R&R은 어떻게 된것인가?
위 출판의사의 예를보면 Context에 관계없이 통합된 BOOK테이블이 만들어지고 수십개의 컬럼이 있고 그 안에는 서로 관련없어 보이는 출판, 마케팅, 판매, 배송 등의 컬럼(또는 테이블)이 뒤 섞여있을 것이다.
굳이 그렇게 복잡하게 한곳에서 관리해야할까? 각 단계별, Context별 서비스와 DB를 분리하고 각 서비스의 Owner가 명확하게 관리하고, 필요한 데이터를 API, Event로 주고 받으며 일하는게 훨씬 명확하지 않을까?
Bounded Context(BC)를 Microservice로 생각한다면 BC의 관계는 서비스간의 동기/비동기 통신에 의해 주고 받는 관계일것이다. Partnership, Shared Kernel, Customer-Supplier 등 관계는 다양한데, 이를 Context Mapping이라는 별도의 주제에서 살펴보고, 여기서 살펴볼 것은 두 극단적인 관계이다.
첫번째는 두 서비스간의 관계가 전혀없는 독립적인 관계 Sperate Ways가 제일 좋을 것이고
두번째는 제일 좋지 않은 반드시 피해야하는 관계인 큰 진흙 공 관계이다.
분리된 방법 Sperate Ways
두 기능성 집합 사이에 유의미한 관계가 없다면, 이들은 서로가 완전히 분리돼야 한다.
큰 진흙 공 Big Ball of Mud (큰 진흙 덩어리로 생각해도 좋다)
여러 모델이 뒤 섞이고 경계는 일정하지 않은 상황에서 시스템을 구성(종종 거대한 형태)
이런 어지러운 상황 전체를 아우르는 경계
이 컨텍스트 안에 세련된 모델링을 적용해보려 애쓰지 말자.
이런 시스템이 다른 컨텍스트 안으로 제멋대로 퍼져나가려는 경향에 주의하자
- Implementing Domain-Driven Design, 반버논 > 2장 도메인, 서브도메인, 바운디드 컨텍스트 (p154 ~ 155)
Bounded Context 통합, 즉 서비스간의 관계를 맺는 방법은 RPC 원격 프로시저 호출, 레스트풀 HTTP, Event를 이용한 메시징 매커니즘 등의 방법이 있지만 다음의 방법도 있다.
물론 애플리케이션을 통합하는 데 단 세가지 방법만이 있다는 의미는 절대 아니다.
예를 들어, 파일 기반의 통합이나 공유된 데이터베이스 통합을 사용할 수도 있지만,
이런 방법은 여러분을 너무 빨리 늙어버리게 만든다.
- Implementing Domain-Driven Design, 반버논 > 13장 바운디드 컨텍스트의 통합 (p573)
DB통합은 가장 안 좋은 형태의 통합 방법으로 DB 통합만은 막아야 한다는 말도 한다. 함께 더 큰 진흙탕이 되므로, 그리고 그러한 Monolith를 더 뚱뚱하게 만들지 말고 서비스로 추가/분리하라는 말과도 상통하는 개념이다.
서비스별로 DB까지 분리하고 필요한 데이터는 API 또는 Event로 주고 받는 관계가 MSA의 장점인 독립성, 확장성, 장애격리 등을 취할 수 있는 제일 좋은 방법인 것이다. 이러한 장점 보다는 당장의 설계/개발 어려움만을 이야기한다면 다시 근본적인 질문을 하지 않을 수 없다. 왜 MSA를 도입하려는지 ...
그리고 처음 이런 질문을 많이 한다고 했다.
"우리 회사는, 우리 도메인은, 우리 업무는 데이터 연관성이 너무 많아서 DB를 분리하기 어렵습니다"
그러면 DB까지 분리해서 MSA를 잘 도입한 회사, 조직은 데이터 연관성이 적어서 쉬웠는가?
금융만 연관성이 많고 복잡하고 다른 도메인은 그렇지 않은가?
데이터 결합도는 어디에나 있는 문제이고 극복해야할 부분이지, 그렇지 않으면 핑게로밖에 들리지 않는다.
"Hybrid MSA인가 WAS만 나눌수도 있다고 하던데요"
하이브리드라는 말이 MSA에 적용 가능한지, 어디서 부터 어떻게 정의된 말인지 모르겠지만
DB를 통합하고 WAS만 나눈다면 굳이 서비스간의 통신(API, Event)이 필요하겠는가? 테이블을 직접 접근할 수 있는데
그리고 물리적인 Machine은 한곳에 두고 향후 분리를 위해 스키마만 나눠두겠다는 의견도 꽤 있다.
그럴듯해 보인다. 하지만 개발에 들어가고 생산성, 일정 등에 쫒기다 보면 SELECT 부터 서서히 Grant를 부여하게 되고
Function, View 등 다른 Object 까지 권한을 열어줘 결국 스파게티가 되는 경우를 쉽게 상상할 수 있다.
그리고 DB 라이센스나 아키텍처의 제약 사항 등으로 종국에는 DB를 통합/공유할 수 있겠지만, 처음 서비스를 식별하는 단계부터 그것을 전제로 한다면 서비스간의 R&R 등 WAS를 나눠야 하는 기준도 세우지 못하게 될 것이고, 의미없게 느껴질 것이다.
이렇게 MSA의 장점, 효과에 충실하게 서비스를 고민하고 식별/정의 후서비스별로 데이터 모델링을 해야한다. 통합 ERD가 아닌 서비스별 데이터 분리에 따른 반정규화, 정합성 등을 충분히 고려해야 하고, 분산 트랜잭션도 고민해야기 때문이다.
[참고]각 Microservice를 AP만 분리하고 DB는 통합하는 경우
https://kooangelo.tistory.com/129