모노리스 -> 마이크로서비스로 넘어가면서 찢어진 두 개이상의 시스템을 어떻게 통합할까? 라는 관점에서 "이벤트" 기반을 도입해보았다.
반대로 MSA를 모노리스로 옮기는 과정도 경험해 보았다.
시장에는 아키텍처 이야기를 다루는 책이 많지 않다. 하지만 MSA는 조금 예외다. 서점에 책이 너무 많다.
하지만 보편적인 서버 아키텍처, 모노리스에 대한 책은 잘 없다. MSA책 안에 몇 장이 나올 뿐.
모노리스에 있는 이야기를 들려주는 강의!
우린 마이크로서비스에서 모노리틱으로 갈아탔다.
이유는 크게 2가지였다.
기술부채 - 보통 MSA의 지향점이 모노리틱의 기술부채를 없애기 위함이라고 말한다. 하지만, 반대로 기술부채를 해결하기 위해서 모노리틱으로 넘어왔다.
시스템과 조직의 관점
기술부채
공유된 데이터 원본에 대한 문제가 있다.
하나의 DB가 아닌, 테이블을 여러 개의 서비스가 사용하는 상황을 의미한다.
스키마 조작 코드가 여러 서비스에 분산이 된다. 어떤 코드를 변경했을 때 다른 코드를 챙기지 못해서 장애 유발도 가능.(이런 부분 때문에 프로젝트 상에서 도메인 주도 개발, 헥사고날 아키텍처(포트앤어댑터) 등의 잘 짜여진 구조에서 DTO+Repository 모듈을 아예 따로 만들고 이를 여러 모듈에서 공유하는 것이 아닐까? - 이렇게 변경해보도록 하자)
결국 중복과 안정되지 않은 코드.
결국 시간이 지나면 한 가지 기능을 수행할 때 코드가 분산된다. 기능의 구현이 복잡해진다.
로직과 코드가 분산되어 있다보니 서로가 서로를 번갈아 호출하며 해결하는 경우가 발생한다.
이렇게 되면 요구사항이 들어왔을 때, 빠르게 반영하지 못한다. -> 여러 서비스를 왔다갔다 진행해야 한다. 개발기간이 늘어나고, 테스트기간이 길어진다.
그렇게 되고, 서비스 반영을 할때 2군데 이상의 서비스에 손을 대는 경우가 발생한다(이번의 문제였다고 생각한다. MQ에서 변수가 Integer -> Long으로 바뀜으로 인해, 문제가 발생했는데 이 경우 결국 정말 "동시에" 배포가 되지 않으면 문제가 해소가 되지 않을텐데. 좋은 방법이 있을까? 필드를 추가하는 것은 SerializableID가 존재하니까 문제가 되지 않을 것이다.)
이때 타이밍이 중요하다.
너와 나, 우린 원래 하나였다. 원래 하나였는데, 억지로 찢어 놓을 것일 수도 있는 것이다.
조직과 시스템의 운영 관점
처음에 개발팀의 인원이 많지 않았다. 소수였다. 그런데 3배에 가까운 서비스가 있었다.
이 경우 앞의 기술부채를 가속화 시킨다.
문제는 내가 A, B, C를 다 건드릴수 있다는 점이다.
요구사항이 왔을 때 비즈니스를 수용하기 위해 만든거다. 요구사항이 왔을 때 일정의 압박과 비즈니스 요구사항이 동시에 왔다면?
개발자는 결국 어디에 놓았을 때 가장 빨리 동작하게 될지를 고민하게 된다.
그 곳에 그냥 요구사항을 갖다놓게 된다.
결국 기술부채를 가속화 시킨다.
그래서 결국 모노리틱으로 돌아갔다.
기술부채를 개선하고 올바른 MSA로 개선하는 것도 방법이다.
하지만 일주일에 몇 번이고 장애 직전까지 몰리는 경우가 존재했다.
불안정한 서비스. 끌어안고 올바른 구조로 개선할때까지 얼마나 걸릴지 가늠이 안된다.
하지만 돌아가는 것은 생각보다 빨리 갈 수 있을 것이라고 결정이 들었다.
필요하다면 다시 나누자
모노티릭으로 되돌아가는 여정... ( 초 간단 버전 )
여러 저장소(Repo)에 나뉘어져 있었다.
여러 저장소를 합치기 위해서 가능한 충돌이 덜 날 수 있는 구조로 프로젝트 정리를 했다. (이게 아키텍처 개선의 힘이 되지않을까?)
그 후 저장소를 통합한다.
이때 2가지 선택지가 있었다.
Git Repo merge
아예 새롭게 복사 붙여넣기로 진행하기
Git 저장소 Merge를 결정.
과거의 히스토리는 소중하다. 빌드시스템을 합치는 과정도 이 단계에서 설정. 의존성 설정 등
패키지 구조를 정리한다.
마지막 작업은 서비스 통합
하나의 서비스로 통합할 때, 스프링 프레임워크의 구조를 활용했다.
Spring은 여러개의 Application Context를 계층구조로 가질 수 있다. 스프링부트도 동일.스프링 Context 계층 구조