대기업들이 시장에 MSA라는 독을 풀었다

대기업들이 시장에 MSA라는 독을 풀었다

대부분의 기업들에게 MSA는 신기루와 같다. MSA에서 모듈형 모놀리식 아키텍처로의 전환 이유.

요즘 여러 채용 공고를 보면 기업 규모도 작은데 맹목적으로 MSA, 쿠버네티스 등의 키워드를 남발하는 경향이 있습니다. MSA는 몇몇 대기업에게는 매우 유용한 방법론일 수 있지만, 스타트업이나 중소기업들이 그저 대기업을 흉내내기 위해 쉽게 따라하는 것은 절대적으로 지양해야 합니다.

저는 현재 시리즈 B 규모의 스타트업에 근무하고 있으며, MSA를 모듈형 모놀리식 아키텍처로 전환하는 작업을 진행하고 있습니다. 제가 입사 후 가장 큰 문제로 제기했던 것은 서버 비용인데, 당시 MSA로 인해 서버비가 매달 약 4,000만원 가량 발생하고 있었으며, 많은 마이크로서비스가 통폐합된 현재는 한달에 약 2,000만원 가량의 서버 비용이 발생하고 있는 상황입니다. 자금 흐름이 중요한 스타트업에 이 정도의 서버 비용이 얼마나 큰 부담이 될지는 대부분 아시리라 생각합니다. 그리고 아직도 비용을 절감할 포인트는 굉장히 많이 남아있는 상황입니다.

서버비 외의 다른 문제들도 많은데, 간단한 테스트를 위해 로컬 환경에 항상 다수의 마이크로서비스를 실행해야만 하는 큰 번거로움이 있으며, 각 마이크로서비스 간 의존성으로 인한 시스템 복잡도도 굉장한 수준입니다. 서비스가 많은 만큼 배포도 굉장히 복잡합니다. 서버에서 많은 서비스들이 실행되고 있으나 트래픽이 많지 않아 서버의 컴퓨팅 리소스를 100% 효율적으로 사용하지 못하고 낭비하고 있기도 하며, 에러가 발생하면 각 마이크로서비스를 넘나들며 디버깅을 해야만 하는 일이 생기기도 합니다.

관리 포인트가 이렇게 많아지니 근무중인 개발자가 적은 스타트업에서는 개발자들에게 굉장한 부담을 주고 있기도 합니다.

나열된 이 모든 낭비되는 비용들은 이전 라운드에 근무하던 CTO가 합당한 근거 없이 무리하게 MSA를 도입한 바람에 발생한 문제들입니다. 시리즈 B에 진입하며 새로 입사하신(저를 포함한) 모든 개발자분들은 MSA가 문제라는데에 모두 공감하셨고 MSA를 모듈형 모놀리식 아키텍처로 전환하는데 동의하게 됐습니다.

이 잘못된 단 한번의 결정으로 인해 회사는 회복하기 힘든 굉장한 손해를 입었으며, 근 1년간 이 손해를 메꾸기 위한 작업들이 진행중이고, 이 작업은 아직도 끝이 보이지 않습니다. 마지막으로, 무리하게 MSA를 도입했던 CTO는 이에 대한 책임은 하나도 지지 않고 퇴사하며 자신의 커리어에 MSA 전환 경험 한 줄을 적어갔습니다.

MSA로의 전환에 성공하고 MSA를 찬양하는 기업들에는 공통점이 있습니다. DB가 SPOF(Single Point of Failure)가 되었다는 점입니다. 이러한 기업들은 트래픽과 데이터가 상상할 수 없을 정도로 많기 때문에 DB 장애가 자주 발생하고, 이 장애가 모든 서비스로 전파되어 MSA 전환을 생존 과제로 여겼으며, 결국 성공했습니다. 그래서 MSA로 전환에 성공한 기업들의 성공 이야기에는 DB를 분리하는 작업이 핵심적으로 언급됩니다.

웹 애플리케이션 서버는 DB가 ACID를 보장해주기 때문에 대량의 외부 요청이 입력되어도 스케일아웃을 통해 CPU와 I/O 부하를 아주 쉽게 분산시킬 수 있습니다. 하지만 DB는 컴퓨터 부품 중 가장 느린 하드 디스크와 직접적으로 상호작용하며 읽기와 쓰기 작업을 수행하기 때문에 작업 속도가 굉장히 느리며, 데이터의 정합성을 보장해줘야하는 막중한 책임을 갖기 때문에 스케일아웃을 통한 부하 분산이 너무 어렵습니다. 예를 들어, 스케일아웃을 해 A와 B라는 두 개의 DB가 존재한다면, A라는 DB에 데이터를 쓰는 즉시 A와 B 두 DB의 데이터가 상이해집니다. 이러한 문제를 해결하기 위해 A와 B 두 DB의 데이터를 항상 동기화해줘야하는 기술적인 과제가 발생하며, 이 과제는 해결하기가 굉장히 어렵습니다. 이렇게 DB를 스케일아웃하면 읽기와 쓰기 시 각 DB 간 데이터의 정합성을 맞추기가 어려워지므로 DB에서 스케일아웃은 효율적이지 않습니다. 이러한 이유로 DB에서는 스케일업을 통한 해결을 주로 시도합니다. 메모리는 전기 신호를 통해 모든 작업을 빛의 속도로 처리할 수 있지만, HDD는 디스크 암이 대상 섹터가 위치한 실린더로 이동하고 디스크 헤드가 섹터의 위치에 도달해야 데이터를 읽거나 쓸 수 있기 때문에 빛의 속도에 비해 너무 느리게 동작합니다. 이런 디스크 I/O 시간은 웹 애플리케이션의 API 지연 시간에 추가되며, 디스크 I/O로 인한 지연은 대체로 ms~s 이상의 아주 큰 시간입니다. SSD를 사용하면 메모리만큼은 아니더라도 그에 준하게 빨라질 수 있지만 대용량 스토리지를 전부 SSD로 대체하는 것은 비용이 많이 들기 때문에 아직도 많은 기업에서는 HDD를 사용하고 있습니다. 이렇게 느린 디스크 I/O를 최소화하기 위해 메모리를 증설하고 메모리에 데이터를 적극적으로 캐싱해 디스크 I/O를 최소화합니다.

추가로 DB의 성능이 충분하지 않을 경우, 테이블을 컴팩트하게, 정규화 이론에 따라 재설계하고, 인덱스를 설계하고 쿼리를 튜닝하는 등의 작업도 시도 할 수 있습니다. (이러한 작업들이 아주 잘 된다면 대체로 DB로 인한 성능 문제를 겪지 않을 겁니다.) 예를 들어, 1억 개의 레코드가 있는 테이블에서 8바이트 크기의 컬럼 하나를 제거하는것만으로 스토리지 용량이 약 1GB 절약될 수 있습니다. 또한, 레플리케이션과 테이블 파티셔닝을 효율적으로 적용하여 읽기 요청을 여러 슬레이브 노드에 분산시키면 각 슬레이브 노드가 특정 테이블에만 액세스할 수도 있으므로 OS 캐시도 효과적으로 활용될 수 있습니다. 조금 더 자세히 설명하자면, 한 슬레이브 노드가 A 테이블을 스캔하고 A 테이블의 데이터를 메모리에 캐싱한 상태에서 B 테이블에 대한 액세스 요청이 들어올 경우 B 테이블의 데이터도 메모리에 캐싱하려 할 수 있습니다. 이때, 메모리 부족으로 페이지 스왑이 발생한다면 메모리에서 A 테이블의 데이터를 비우고 B 테이블의 데이터를 캐싱하게 됩니다. 이렇게 되면 다음 읽기시 페이지 폴트가 발생할 확률이 높아지고 결국 여러 이유로 인해 디스크 I/O가 빈번하게 발생하게 됩니다. 그러나 해당 슬레이브 노드가 계속해서 A 테이블만 액세스한다면, 처음 액세스 이후로는 이미 필요한 데이터가 메모리에 캐싱되어 있을 확률이 높기 때문에 디스크 I/O가 최소화됩니다.

하지만 위의 모든 작업을 수행해도 여전히 DB 장애가 발생한다면, 그 기업은 아주 높은 확률로 이미 많은 사용자와 트래픽, 데이터를 다루는 큰 기업일 것입니다. 당연히 개발자도 많을겁니다. 이런 상황에서야 비로소 MSA로의 전환을 고려할 수 있는 최소한의 요건을 충족한다고 볼 수 있습니다. 또한, MSA 전환으로 인해 레디스, 몽고DB, 엘라스틱서치 등과 같이 각 서비스에 특화된 효율적인 DB를 사용할 수 있게 될수도 있습니다. 시간이 지난 후에 분리된 DB가 다시 커진다면 이러한 작업을 반복해 여러 개의 마이크로서비스로 다시 분리할 수 있을 겁니다. (전 세계적으로 유명한 MAANG 기업들의 사례를 상기해보면 그들의 마이크로서비스는 전 세계에 네트워크처럼 퍼져있습니다.)

이제 도커와 쿠버네티스에 대해 생각해보겠습니다. 도커는 대표적인 컨테이너 기술로, 프로세스를 컨테이너로 감싸고 독립적인 환경에서 동작하는 것처럼 격리해 한정된 컴퓨팅 리소스를 사용할 수 있도록 제한해줍니다. 원래 도커가 탄생하게 된 계기는 이식성이었습니다. 내 로컬에서는 되는데 배포만 하면 안되네? 라는 문제가 있었던 것이죠. 근데 이 문제는 JVM 기반의 언어들에 대해서는 해당사항이 없습니다. 그렇다면 도커를 사용함으로써 얻을 수 있는 다른 효과는 프로세스들이 한정된 컴퓨팅 리소스를 사용하도록 강제하는 것인데요, 그러나 이러한 효과를 충분히 누리기 위해서는 서버에 여러 개의 프로세스가 떠 있어야 한다는 요구사항이 있어야 합니다. 그리고 이러한 요구사항이 생길만한 대표적인 사례는 MSA라고 볼 수 있습니다. 하나의 서버에서 여러 개의 프로세스를 운영해야 하는 경우입니다. 하지만, 모놀리식 아키텍처로 개발하고 서버에 단일 프로세스를 유지하는 것이 컴퓨팅 리소스를 최대한 활용하는 효율적인 방법일 수 있습니다. 왜냐하면, 서버에 필요 이상으로 많은 프로세스가 실행된다면 CPU 스케쥴링과 컨텍스트 스위칭으로 인한 오버헤드가 극대화될 수 있기 때문입니다. 게다가 단일 프로세스였다면 메모리 내 함수 호출로 끝났을 작업들이 IPC를 통해 이뤄져야 하므로 이 또한 추가적인 오버헤드를 유발합니다. 이러한 이유들로 컨테이너 기술은 데이터가 많지 않고 서비스가 작은 대부분의 기업에서는 필요하지 않을겁니다. (도커가 로컬 개발 환경 구축에 유용하다는 주장에는 이견의 여지가 없다고 생각합니다.)

쿠버네티스는 왜 사용할까요? 예를 들어, 하나의 프로세스를 두 개로 분리하여 서버에 A와 B라는 두 개의 프로세스를 컨테이너로 띄웠다고 가정해봅시다. A 프로세스에 트래픽이 집중되어 자신에게 주어진 컴퓨팅 리소스가 부족해진다면, 서버 관리자는 B 프로세스에서 일부 리소스를 뺏어와 A 프로세스에 할당해야 합니다. 이러한 작업을 수동으로 수행하는 것은 번거로울 뿐만 아니라 복잡합니다. 이런 이유로 쿠버네티스라는 기술이 등장했습니다. 쿠버네티스는 컨테이너 오케스트레이션을 제공하여 자동으로 리소스 관리와 프로세스 간의 상호 작용을 관리합니다. 이를 통해 프로세스 간 리소스 조정이 자동화되어 효율적으로 운영됩니다. 그러나 쿠버네티스 역시 컨테이너를 사용하지 않으면 필요가 없는 기술입니다. 결과적으로 MSA로의 전환이 전혀 필요하지 않은 대부분의 기업에서는 도커와 쿠버네티스는 유의미한 효과를 가져다주기 힘들겁니다. 나중에 회사가 커졌을 때, 정말 필요할 때 학습하고 도입해도 늦지 않습니다.

MSA를 도입하는 결정을 내리기 전에 기업의 현재 상황과 요구사항을 신중하게 고려하고, MSA가 정말로 필요한지 신중하게 검토해야 합니다. 데이터베이스와 서버의 성능 개선을 통해 문제를 해결할 수 있는지, 기업의 규모와 트래픽이 반드시 MSA로 전환해야 하는 수준인지 등을 고려해야 합니다. 필요한 경우에는 MSA를 도입하되, 그 결정은 신중하게 내려야 합니다.


© 2022. All rights reserved.