프론트엔드계의 MSA, MFE에 대해 알아보자

정현·2026년 5월 26일
post-thumbnail

서론

어플리케이션의 규모가 커지면서 생기는 문제를 해결하기 위해 여러 회사에서 마이크로프론트엔드 아키텍처를 도입하는데요. 저도 최근에 앱 개발을 하면서 새로운 아키텍처를 도입하기 위해 마이크로프론트엔드 공부한 내용을 정리할 겸 작성해봅니다.

프론트엔드계의 MSA

기존의 모놀리식 프론트엔드 아키텍처에서 몇가지 문제점을 해결하기 위해 등장한 것이 마이크로프론트엔드인데요.

변경사항이 그렇게 크지 않은데 다시 빌드하고 전체를 다시 배포해야하는 배포 의존성, 너무 많은 팀이 동시에 작업할 때 빈번히 발생하는 머지 충돌, 프레임워크와 버전을 모두 동일하게 맞춰야하는 기술 스택 제약, 규모가 커질 수록 빌드와 테스트 시간이 점점 증가하는 등 이러한 문제들을 해결해야 했습니다.

이때 '그럼 그냥 백엔드에서 이미 사용중인 마이크로서비스의 강점을 한 번 프론트엔드에도 적용해보자' 해서 사용한 것이 마이크로프론트엔드입니다.
그래서 마이크로프론트엔드는 어플리케이션을 독립적으로 개발하고 배포하며 운영 가능한 작은 단위로 분할하는 아키텍처라고 보시면 되겠습니다.

예시로 보자


예를들어 인강 사이트를 만든다고 가정해봅시다.
그런데 규모가 커서 개발팀이 결제, 인강 상품, 커뮤니티, 기타 UI 이렇게 구성 되어있어요.

이때 기타 UI팀은 Vue를 쓰고 싶어하고 인강팀은 React, 결제팀은 Svelte를 쓰고 싶어해요. 뭐 극단적인 예시이긴 하지만 마이크로프론트엔드는 서로 다른 기술 스택을 사용할 수 있고 팀이 각각의 어플리케이션을 담당하여 개발할 수 있어요.

그리고 이를 하나로 묶는 컨테이너 어플리케이션이 모든 마이크로프론트엔드를 통합하고 라우팅을 관리합니다.
각 팀은 자신들 멋대로(독립적으로) 개발하고 배포할 수 있으면서 실제 사용자는 하나의 어플리에키션을 보게 할 수 있는거죠.

코드 분리하면 안될까?

코드 분리 좋아요, 좋은 접근이죠. 실제로도 영역별로 코드를 잘 분리하고 팀 간 협업이 잘 이루어진다면 유사한 구조를 만들 수 있을 것 같아요. 그런데 아무리 잘해도 여전히 위에서 말한 빌드, 기술 스택 통일 등의 제약이 존재하고 무엇보다 진정한 마이크로프론트엔드는 각 단위가 독립적인 생명주기를 가질 수 있도록 하는 통합 방식이 중요해요.

코드 분리의 한계

사실 폴더 구조를 나누고 모듈을 분리하는 것은 이미 잘 구조화된 모놀리식 어플리케이션으로도 충분히 가능해요.
(명확한 폴더 구조와 모듈 분리, 팀별로 코드베이스 분리 등)

하지만 이것도 여전히 모든 어플리케이션이 한꺼번에 빌드되어야 하고 일부분을 수정해도 다시 배포해야하고 분리(기술 스택 통일, 의존성 등)가 확실하게 일어나지 않아요.

통합 방식

자 이제 왜 필요한지 조금 알아봤으니 어떻게 묶을지 고민해봅시다.
통합할때는 '언제', '어디서' 를 볼겁니다.

언제 묶을까?

개발 시점에 미리 조립 VS 사용자가 접속할 때 실시간 조립

어디서 묶을까?

서버에서 조립 VS 브라우저에서 조립 VS 둘다

빌드 타임 통합

빌드 타임 통합 방식은 개발할 땐 따로 작업하고 배포할 땐 하나로 합쳐서 내보내는 방식입니다.
독립적으로 만들고 빌드 단계에서 합쳐져서 하나의 번들로 나온다고 보시면 됩니다.

그러면 어떻게 하는지 한번 봅시다.

의존성으로 관리

그냥 각각의 어플리케이션들을 npm 패키지로 만들어서 메인 어플레이케이션에 의존성을 추가하면 빌드할 때 번들러가 다른 어플리케이션 내용을 쭉 가져와 하나로 합쳐줄겁니다.

{
  "dependencies": {
    "@app/aplication1": "^2.2.0",
    "@app/aplication2": "^1.9.0",
    "@app/aplication3": "^1.1.0"
  }
}

모노레포 기반

위에보다 정교한 방법으로는 Nx, Turborepo 같은 모노레포 도구를 활용하는 방법이 있습니다.
각 어플리케이션을 독립 패키지로 두고 메인 어플리케이션에서 이것들을 일반 npm 패키지 가져다 쓰듯이 쓰면 최종 빌드 시 모든 코드가 하나의 번들로 통합될겁니다.

빌드 타임 통합의 장단점

장점은 코드 일관성이 확보된다는 점, 초기 로딩 성능이 좋다, 타입이 안정적이다 정도가 있습니다.
단점은 결국 빌드 시간은 단축시키는데 실패한다는 점, 모든 어플리케이션이 라이브러리 버전을 통일시켜야 한다는 점이 있습니다.

그럼 실시간이다

런타임 통합은 각 어플리케이션을 독립적으로 배포하고 사용자가 접속하면 실시간으로 조립하는 방식입니다.
이렇게 하면 어떤 팀에서 갑자기 새로운 기능을 추가해도 큰 영향을 받지 않는다는 장점이 있습니다.

Module Federation

이건 Webpack 5의 기술인데 호스트 어플리케이션과 리모트 어플리케이션을 기준으로 통합합니다.

호스트 어플리에키션은 기존에 메인 어플리케이션처럼 말 그대로 다른 마이크로프론트엔드들을 불러와서 통합하는 친구입니다. 그리고 리모드 어플리케이션은 자신의 기능을 외부에 노출하여 다른 어플리케이션에서도 사용할 수 있도록 만드는 독립적인 마이크로프론트엔드입니다.

장점으로는 각 팀이 원하는대로 기술을 사용할 수 있고 코드가 충돌될 일이 없으며 장애 마저도 격리됩니다.

예를 들어 상품팀에서 인기 상품을 보여주는 새로운 기능을 도입헀다고 해봅시다.
그런데 갑자기 인기 상품 기능에 장애가 발생하여 기능을 사용할 수 없게 되었을때 다른 어플리케이션에는 영향을 주지 않고 다른 어플리케이션은 그대로 잘 동작하여 서비스를 유지할 수 있습니다.
그래서 여러 팀이 병렬적으로 개발하고 새로운 기능을 바로바로 출시해보기도 좋습니다.

싱글톤

하지만 라이브러리 버전 충돌이 일어나면 귀찮아진다는 단점이 있어요. 예를 들어 호스트에서는 리액트 17을 사용중인데 리모트에서 18을 사용하면 두 버전이 충돌하겠죠? 추가로 전역 상태 관리나 리액트 훅 등에서도 문제가 발생 할 수 있어서 이를 해결하기 위한 '싱글톤'이 있습니다.

싱글톤 설정은 여러 어플리케이션 간에 하나의 라이브러리만 공유하도록 강제할 수 있는데 이를 통해 각 어플리케이션이 실제로는 서로 다른 버전을 사용하더라도 런타임에서는 하나의 버전만 로드하여 충돌을 방지할 수 있어요.

Next쓰면 이렇게도 가능

Next.js를 쓴다면 Multi-zone 아키텍처도 고를 수 있는 선택지에 추가됩니다.

module.exports = {
  async rewrites() {
    return [
      {
        source: "/test/:path*",
        destination: "http://localhost:3001/:path*",
      },
    ];
  },
};

사용자가 /test 경로에 접속하면 그 앱으로 라우팅 될겁니다.

next 기본 기능만으로 구현할 수 있어 간단하지만 이동 시 페이지 전체가 새로 로드되는 하드 탐색이 발생한다는 단점이 있습니다.

어떤 기준으로 고르면 좋을까?

그렇다면 빌드타임 통합과 런타임 통합 중 무엇을 고르면 이득을 볼 수 있을까요?

방식은 정말 정답이 없겠지만 조금 작은 팀이거나 초기 로딩 속도가 중요하다면 빌드타임에 팀이 좀 많고 각 앱의 배포를 분리하고 싶은 경우 런타임을 고려해보면 좋을 것 같습니다.

통합 위치

통합 방식을 결정했으니 이제 통합 위치를 선택해야합니다.
'이 통합을 어디서 할 것인지' 를 결정해야하는데 크게 3가지 방식으로 볼 수 있습니다. 사실 CSR과 SSR은 기본 개념과 거의 유사합니다.

서버 사이드 렌더링

SSR은 사용자가 페이지 요청을 하면 서버에서 각 마이크로프론트엔드 앱을 하나씩 가져와 조립한 다음 완성된 HTML을 브라우저로 보내는 방식입니다.

이 방식은 초기 로딩이 빠르고 SEO 최적화하기 좋습니다.
하지만 모든 조립이 서버에서 일어나다보니 굳이 불필요한 서버 부하가 발생할 수 있다는 단점이 있습니다.

클라이언트 사이드 렌더링

CSR은 브라우저에서 필요한 앱을 동적으로 로드하고 조립합니다.
위에서 말한 Module Federation 같은 것들이 런타임에 모듈을 동적으로 활용할 수 있게 도와줍니다.

이 방식은 동적이고 인터랙티브한 UX를 제공할 수 있다는 장점이 있지만 반대로 초기 로딩이 느리고 SEO 최적화 하기 귀찮아진다는 단점이 있습니다.

엣지 컴퓨팅

사실 CSR과 SSR은 기본 개념과 거의 유사합니다.
엣지 컴퓨팅은 독립적인 앱들을 엣지 네트워크에서 조합하여 사용자에게 페이지를 전달하는 방법입니다.

Cloudflare Workers 같은 플랫폼에서 지원하고, 전 세계에 분산된 서버 네트워크를 활용해 사용자와 가까운 지점에서 코드를 실행할 수 있게 해줍니다.

이 방식의 장점은 전 세계 어디서든 빠른 응답 속도를 제공할 수 있다는 점입니다. 서버 부하가 분산되고 클라이언트에 덜 의존적이게 바꿀 수 있습니다.

하지만 엣지 컴퓨팅 인프라가 필요하고 상대적으로 높은 인프라 비용이 발생할 수 있습니다.





위에 3가지 중 각 장단점에 따라 본인에게 맞는 방식을 선택하면 좋을 것 같습니다.

마무리

마이크로프론트엔드 개념과 구조를 간단하게 봤는데 이건 분명 규모가 큰 프론트엔드 애플리케이션을 위해 나왔고 복잡한 것을 효과적으로 관리하고 팀을 분리할 수 있는 좋은 아키텍처입니다. 독립적인 기술 스택, 배포, 의존성 최소화 등 다양한 장점이 있죠.

그런데 결국 이렇게 분리해도 새로운 복잡성이 추가되고 조직이 기술적 이해도가 높아야 한다는 한계점도 명확합니다. 솔직히 이론적인면만 봤을때는 이게 맞나 싶기도 하고 '코드 중복, 일관적인 UX, 리소스 증가' 등 잠깐 생각해봐도 떠오르는 문제들도 있어서 도입할 때는 현재 프로젝트가 어떤 부분에서 문제이고 어떤 문제를 해결해주는지 그리고 그저 '남들이 도입하니깐' 이라는 생각이 아닌 팀의 역량과 규모 등을 종합적으로 고려하여 도입하는 것이 중요할 것 같습니다.




긴 글 읽어주셔서 감사합니다.

profile
노력으로 재능을 이길 수 없다면, 노력으로 재능을 만드는 개발자 서정현입니다

0개의 댓글