모놀리스 - 좋은가요 나쁜가요? | Mark Heath
Mark Heath님의 Monoliths - Good or Bad? 글을 번역하였습니다.
지난 몇 달 동안 저는 소셜 미디어에서 '모놀리스'를 선호하는 마이크로서비스에 반대하는 사람들의 강력한 의견을 발견했습니다. 이는 놀라운 일이 아닙니다. 거의 모든 새로운 아키텍처 패턴(프로그래밍 프레임워크뿐만 아니라)은 과대 약속과 과소 제공을 하는 경향이 있습니다.
또한 잘 알려진 마이크로서비스 옹호자들조차도 마이크로서비스가 해결한 만큼 많은 문제를 야기할 수 있다는 점을 지적하며 "꼭 필요한 경우에만 마이크로서비스를 사용하라"고 권장합니다.
이 (다소 장황한) 글에서는 '모놀리스'가 실제로 무엇을 의미하는지에 대한 제 생각을 공유하고 이러한 접근 방식의 장점과 약점이 무엇인지 살펴보고자 합니다.
물론 최근 몇 년 동안 마이크로서비스와 모놀리스에 대해 꽤 많은 시간을 할애해 왔지만, 여전히 제가 이 두 가지에 대해 '전문가'라고 생각하지는 않는다는 점은 말할 필요도 없습니다. 제 상황과 경험은 여러분과 상당히 다를 수 있으므로 댓글을 통해 여러분의 관점을 듣고 싶습니다.
모놀리스란 무엇인가요?
"모놀리스"라는 단어는 단순히 "하나의 커다란 수직 돌덩어리"를 의미하므로 소프트웨어 아키텍처 또는 코드베이스를 설명할 때 이 단어를 사용하면 (1) 애플리케이션이 매우 크고 (최소 10만 줄 이상의 코드를 의미하며, 확실히 100만 줄 이상일 것입니다) (2) 여러 서비스 또는 마이크로서비스로 구성된 "분산" 애플리케이션이 아니라는 뜻이 됩니다. 대신 단일 프로세스로 실행됩니다.
물론 이것은 다소 느슨한 정의이지만 '모놀리식' 아키텍처의 몇 가지 일반적인 특성을 고려하고 각각의 장점과 단점을 모두 파악하고자 합니다.
하나의 리포지토리
우선, 모놀리스에서는 모든 소스 코드가 하나의 리포지토리에 저장됩니다.
장점: 복제할 것이 하나뿐이고 물건을 찾기가 훨씬 쉬워진다는 장점이 있습니다. 고객에게 할인을 제공하는 로직이 있다면 하나의 리포지토리 어딘가에 있다는 것을 알고 있습니다.
단점: 단점은 이것이 "인지 과부하"의 원인이 될 수 있다는 것입니다. 새로운 개발자가 리포지토리를 복제하면 코드의 양에 압도되어 어디에 집중해야 할지 모를 수 있습니다. 또 다른 문제는 많은 개발자 또는 팀이 서로 다른 기능을 동시에 작업하는 경우, 작업과 관련이 없는 수많은 브랜치와 풀 리퀘스트가 생길 수 있다는 것입니다. 그리고 한 개발자가 어떤 식으로든 리포지토리를 망가뜨리는 실수를 저지르면 한 팀뿐만 아니라 모든 개발자에게 영향을 미칩니다.
하나의 IDE
둘째, 모놀리스를 사용하면 일반적으로 전체 코드베이스를 하나의 IDE(예: Visual Studio 또는 VS Code)에 로드합니다.
장점: 내장된 IDE 도구로 모든 것을 찾을 수 있다는 장점이 있습니다. 예를 들어 특정 메서드의 모든 호출자를 찾고 싶습니다. 또한 분산 시스템에서보다 훨씬 쉽게 디버깅할 수 있습니다. 모든 코드 줄을 쉽게 살펴볼 수 있습니다.
단점: 단점은 많은 IDE가 대규모 코드베이스에서 심각한 성능 문제를 일으켜 빌드 시간이 느려지고 기업의 바이러스 검사기로 인해 속도가 더 느려질 수 있다는 것입니다. 또 다른 문제는 설계한 모듈성을 유지하기 위해 극도로 주의를 기울여야 한다는 것입니다. 모든 코드가 단일 IDE에 있으면 코드베이스의 한 부분이 참조해서는 안 되는 것을 직접 참조하는 것이 너무 쉬워서, 긴밀하게 연결된 코드가 엉망이 되어 되돌리기 위해 많은 노력이 필요하게 됩니다.
하나의 서버에서 실행되는 하나의 실행 파일
셋째, 모놀리스는 일반적으로 하나의 서버에서 실행되는 하나의 실행 파일로 컴파일됩니다.
장점: 여기에도 몇 가지 장점이 있습니다. 우선, 모듈 간의 모든 통신이 인메모리에서 이루어지므로 분산 애플리케이션에서 발생하는 빈번한 네트워크 호출에 비해 성능이 뛰어납니다. 또한 관찰해야 할 서버가 하나뿐이고 문제 해결을 위해 살펴봐야 할 로그 세트가 하나뿐이므로 관찰 가시성 측면에서 훨씬 더 쉬운 작업을 수행할 수 있습니다.
단점: 그러나 이 접근 방식에는 몇 가지 큰 단점이 있습니다. 가장 명백한 단점은 단일 서버를 사용하는 유일한 옵션은 점점 더 강력한 서버로 "확장"하는 것인데, 이는 비용이 많이 들고 한계에 도달한다는 것입니다. 따라서 "모놀리스"를 사용하더라도 하나의 앱의 여러 인스턴스를 실행하고 분산 시스템의 문제 중 적어도 일부를 처리해야 할 것입니다.
모든 코드를 단일 실행 파일에 넣는 것의 또 다른 큰 단점은 코드베이스의 일부가 불안정할 수 있다는 것입니다. 프로세스를 중단시키거나 엄청난 양의 메모리를 차지할 수 있는 모호한 레거시 파일 형식을 처리해야 할 수도 있습니다. 모놀리스 접근 방식에서는 어느 한 곳에서 오류가 발생하면 애플리케이션 전체가 다운될 가능성이 있습니다.
하나의 언어 및 기술 스택
넷째, 하나의 언어와 기술 스택으로 모놀리스가 작성됩니다.
장점: 여기서 가장 큰 장점은 일관성이 있고 모두가 해당 언어와 프레임워크를 알고 있기 때문에 전체가 효과적일 수 있다는 것입니다.
단점: 하지만 모놀리스의 가장 큰 단점 중 하나가 될 수 있습니다. 얼마 지나지 않아 원래 사용하던 프레임워크가 구식이 됩니다. 저는 커리어를 쌓는 동안 한 프레임워크나 SDK에서 다른 프레임워크로 코드베이스를 포팅해야 했던 횟수를 셀 수 없을 정도로 많았는데, 모놀리스는 보통 한 번에 모든 전환을 수행해야 하기 때문에 거의 불가능할 수 있습니다. 쉽게 이전되지 않는 한두 가지 특이한 레거시 기능만 있어도 전체 마이그레이션이 중단될 수 있습니다.
제 경험에 따르면 모놀리스는 거의 항상 레거시 기술에 갇히지만, 마이크로서비스는 업그레이드(또는 완전히 다시 작성하는 것 - 모놀리스에서는 거의 불가능한 일)가 훨씬 더 실현 가능성이 높습니다.
하나의 데이터베이스
다섯째, 모놀리스에서는 모든 데이터를 하나의 데이터베이스에 저장하는 것이 일반적입니다.
장점: 여기에는 몇 가지 분명한 이점이 있습니다. SQL Server와 같은 관계형이라면 상상할 수 있는 모든 쿼리가 가능하며, 모든 테이블에 걸쳐 조인할 수 있습니다. 또한 최적화, 복원력, 백업 및 보안 문제를 한 곳에서 집중할 수 있다는 의미이기도 합니다.
단점: 단점은 무엇일까요? 모든 데이터가 동일하지는 않습니다. 어떤 테이블은 주로 추가만 하고 쿼리는 거의 하지 않는 반면, 어떤 테이블은 업데이트는 거의 하지 않지만 쿼리는 자주 합니다. 어떤 엔티티는 ID로만 조회되는 반면, 어떤 엔티티는 매우 복잡한 정렬과 필터링이 필요합니다. 일부 데이터는 비즈니스에 매우 중요하므로 고가의 지리적 이중화를 통해 백업해야 하는 반면, 다른 데이터는 훨씬 저렴한 저장소에 보관할 수 있습니다.
모놀리스의 또 다른 과제는 데이터의 '소유권' 개념입니다. 모든 사람이 모든 것을 소유하는 상황에서는 개발자가 자신의 필요에 맞게 스키마를 자유롭게 수정할 수 있지만 다른 기능의 성능 문제가 발생할 수 있습니다.
하나의 배포
여섯째, 모놀리스는 하나로 배포됩니다. 업그레이드하면 전체 애플리케이션이 최신 버전으로 교체됩니다.
장점: 가장 큰 장점은 단순성입니다. 단 한 가지만 배포되므로 서로 다른 서비스의 모든 버전이 서로 호환되는지 여부에 대해 복잡하게 생각할 필요가 없습니다.
단점: 그러나 이는 마이크로서비스로 전환하는 또 다른 주요 요인입니다. 모놀리스 배포는 느리고 수동적인 경향이 있습니다. 이 때문에 위험하다고 인식되어 1년에 몇 번의 업그레이드만 허용될 수 있으며, 많은 개발자가 많은 업데이트를 함께 롤링할 수 있습니다. 즉, 기능이 구현된 후 실제 프로덕션에 적용되기까지 몇 달이 걸릴 수 있습니다. 결국 릴리스 전에 모놀리스를 안정화하기 위해 '코드 동결'과 같은 추악한 패턴이 발생하게 됩니다.
마이크로서비스의 가장 큰 매력 중 하나는 더 자주, 더 소규모로 배포할 수 있어 완성된 작업을 훨씬 더 빠르게 출시할 수 있다는 점입니다. 물론 모놀리스 자체에 빠른 릴리즈를 방해하는 요소는 없지만, 현실적으로 모놀리스에서 실제로 이를 달성하는 경우는 드뭅니다.
또 다른 고려 사항은 "가동 중지 시간 제로" 배포의 필요성입니다. 단일 상태 저장 프로세스로 실행되는 모놀리스가 있고 업그레이드가 데이터베이스 스키마 변경을 비롯한 많은 변경 사항을 롤업하는 경우, 가동 중지 시간 제로를 달성하는 것은 매우 어려운 일이며, 업그레이드 시 다운타임이 몇 시간으로 측정되는 모놀리스를 사용하는 경우가 많습니다.
한 팀이 모든 것을 소유
모놀리스의 마지막 특징은 하나의 대규모 팀이 전체에 대한 소유권을 공유한다는 것입니다. 100명의 개발자가 5~10명으로 구성된 소규모 팀으로 나뉘어 있어도 코드베이스의 어떤 부분도 변경할 수 있으므로 누구도 권한을 벗어날 수 없습니다.
장점: 다른 팀이 작업을 완료할 때까지 기다릴 필요가 없다는 장점이 있습니다. 기능에 프론트엔드, 백엔드 및 데이터베이스 스키마 변경이 필요한 경우 모든 것을 변경할 수 있습니다.
단점: 단점은 코드가 경쟁하는 아키텍처 접근 방식과 같은 것에 대한 여러 추상화가 얽혀 엉망이 될 수 있다는 것입니다. 전체 코드베이스를 이해하는 데 드는 인지적 오버헤드가 너무 커서 개발자가 원래의 아키텍처 의도를 고려하지 않고 문제에 대한 자체적인 해결책을 고안하는 경우가 많습니다.
물론 모놀리스에서 반드시 그럴 필요는 없습니다. 코드베이스를 잘 모듈화할 수 있으며, 각 모듈의 전문가 또는 '소유자'가 해당 부분에 대한 변경 사항을 코드 검토하고 개발자가 기존 설계에 반하지 않고 작업하도록 안내할 수 있는 것이 이상적입니다. 하지만 "모두에게 자유를 주는" 접근 방식은 일반적으로 기술 부채를 축적하는 결과를 초래합니다.
마이크로서비스가 더 나은가요?
마이크로서비스는 이러한 여러 단점을 해결하는 한 가지 방법이지만 유일한 방법은 아닙니다. 또한 마이크로서비스에는 자체적으로 많은 잠재적인 단점이 있으므로 이를 인지하고 이에 대한 계획을 세워야 합니다.
제 생각에 마이크로서비스는 위에 나열된 단점 중 하나 이상이 너무 고통스러워서 모놀리스의 장점을 기꺼이 포기할 수 있을 때만 매력적입니다. 마이크로서비스는 프로젝트의 상황에 따라 결정해야 하며, 모든 프로젝트에 적합한 솔루션은 없습니다.
업계에서는 모놀리스로 더 쉽게 성공하기 위한 혁신보다 마이크로서비스로 더 쉽게 성공하기 위한 혁신이 훨씬 더 많이 일어나고 있는 것 같습니다. 안타까운 일이라고 생각합니다. 우리는 이 문제를 양쪽 끝에서 해결해야 합니다.
모놀리스는 실제로 존재하나요?
마지막으로, 모놀리스에 대한 저의 설명이 실제로 존재할 가능성이 그렇게 높지 않다고 주장할 수도 있습니다. 거의 모든 대규모 엔터프라이즈 애플리케이션은 어느 정도 '분산'되어 있습니다.
예를 들어, 최소한 데이터베이스는 다른 서버에서 별도의 프로세스로 실행되고 있을 가능성이 높습니다. 메시지 브로커나 클라우드 파일 스토리지가 관련되어 있을 수도 있습니다. 보안 모범 사례를 따르고 있다면 별도의 ID 서버가 있을 가능성이 높습니다.
그리고 모놀리스의 단일 인스턴스를 실행하고 있지 않을 수도 있습니다. 확장성을 위해 여러 인스턴스를 실행하거나 여러 지역에서 서로 다른 인스턴스를 실행하는 것은 일반적이지 않습니다.
비동기 메시지 처리기나 예약된 작업이 있다면 실행 중인 웹 서버와 별도의 프로세스에서 실행되고 있을 가능성도 있습니다.
따라서 모놀리스는 분산된 부분이 적은 반면, 마이크로서비스는 분산된 부분이 많을 수 있는 슬라이딩 스케일에 가깝습니다. 하지만 모놀리스에 몇 개의 보조 마이크로서비스가 추가되거나 함께 작동하는 상당히 큰 규모의 "마이크로서비스"가 적은 수의 모놀리스가 있는 중간 지점의 가능성도 분명히 존재합니다.
제가 작업한 많은 시스템이 바로 이 중간 지점에 놓여 있습니다. 이 상황에서는 두 가지 접근 방식 모두의 고통을 겪지 않고 두 가지 접근 방식의 장점을 모두 누릴 수 있기를 바랍니다.