micro-frontend

백승일·2022년 1월 3일
1
  • 마이크로 프론트엔드
  • 마이크로 서비스 아키텍쳐의 시작
  • 마이크로 프론트 엔드의 통합 패턴
  • 정리

마이크로 프론트 엔드

마이크로 프론트 엔드란 백엔드에서 사용하고 있는 마이크로 서비스 아키텍쳐 처럼 프론트엔드에서 관리하는 서비스를 분리해서 개발, 관리하는 패턴을 말한다.

마이크로 서비스 패턴의 시작

마이크로 서비스 아키텍쳐가 왜 부상했는지 생각해볼 필요가 있다. 해당 아키텍쳐는 백엔드 서비스를 기준으로 설명하겠다. 먼저 마이크로 서비스 아키텍쳐의 떡상 그 배후에는 서비스의 몸집이 커지는 상황, 클라우드(aws),컨테이너(docker)등 서버 서비스의 발전이 있다. 그럼 기존에 사용하던 아키텍쳐에 어떤 점을 보완하고 나온 걸까.

기존의 방식은 모놀리식(Monilithic)이라고 한다. 하나의 큰 서비스안에서 모듈별로 개발을 하고, 그 결과물을 빌드해서 하나의 패키징하는 구조이다.

이런 구조의 서비스는 구조가 단순하다. User Interface / Business Logic / DB 이런 식으로 깔끔하게 구분하여 개발이 가능하고, 하나의 서비스이기 때문에 개발 환경의 설정과 배포가 간편한 장점이 있다. 하지만 마냥 좋은 점만 있는 것은 아니다.

  1. 작은 기능의 추가, 수정 등이 일어나면 결국 전체의 서비스를 다시 빌드, 배포해야한다. 작은게 모여서 하나가 된 구조니까 말이다.
  2. 또한 모든 서비스가 하나로 합쳐지면서 그 내부 종속성 혹은 유연하지 못한 패턴을 사용하게 되면 코드 전체의 흐름을 이해하기 힘들고,
  3. 모듈들이 커지면서 빌드 시간이 길어지고,
  4. 새로운 기술을 적용할라고 보면 처음부터 해야하는 경우가 생길 수 있다.

이런 단점을 보완하고자 나온 아키텍쳐 중 하나가 Micro Service Architecture이다. 일명 MSA는 하나의 큰 서비스를 작은 단위의 서비스로 나누고, 서비스간의 종속성을 낮춰 독립적이고 느슨하게 결합시키는 아키텍쳐이다.

여기서 중요한건 독립적, 느슨한 결합 이라는 특징이다.

  1. 서비스가 독립적이라는 말은 기능의 추가, 수정이 일어나도 전체 서비스를 다시 배포하는 게 아니라 해당 서비스만 배포하면 되게 되고
  2. 독립적이기 때문에 종속성에 크게 스트레스 받지 않고 코드 전체를 이해하고 개발할 수 있으며
  3. 사이즈가 작아지니 테스트에 용이하고
  4. 서비스가 다운되도 다른 서비스 혹은 전체 서비스에 영향을 주지 않음과 동시에
  5. 독립적으로 운영되는 서비스이니까 서버를 더 붙인 다던지 리소스의 유연한 운용이 가능하다.

자 여기서 이제 5번 장점이 컨테이너와 클라우드서비스의 발전과 맞물린다.

예를 들어서 게임 정보 사이트가 있다고 생각해보자. 이 사이트의 서비스에는

  1. 로그인, 회원 가입 등 게시판 이용을 위한 사용자 로그인
  2. 게임 내 정보를 볼 수 있는 정보 서비스
  3. 게임 업데이트 정보를 정리한 업데이트 정보 관리 서비스
  4. 로그인한 회원들이 글을 쓸 수 있는 게시판 서비스

이런 사이트를 운영하는데 게임이 대규모 업데이트를 한다고 예고하고 업데이트를 진행했다. 이 사이트를 운영하든 B모씨는 업데이트 내용을 잘 정리해서 업데이트 정보 관리 서비스에 이쁘게 올려놨다. 그럼 앞으로 어떤 상황이 벌어질까.

물론 이런 사이트를 운영하는게 B모 씨 뿐은 아니겠지만 만약 독점으로 운영하고 있다고 한다면?

바로 페이지 터지는 거다. 왜냐 B모씨의 모놀리식 패턴으로 만들어진 서비스는 클라우드 서버에 배포되서 운영되는데, 아니 사람들이 대규모 업데이트라고 몰린 것이다. 그러면 이제 놀란 B모씨는 물 들어 올 때 노 젓자는 마음으로 서버를 증설한다.

몇 개의 서버컴을 aws ec2를 이용해서 결제하고 전체 서비스를 각각 올린다. 그런데 한 1주일이 지나고 게임 뽕이 빠진 사람들이 사이트 접속을 안하니 트래픽 발생이 사건 발생의 20분의 1로 줄었다. 그러면 다시 전체 서비스가 올라간 ec2를 꺼야한다.

여기서 생각 해볼 점은 ”전체 서비스가 올라간다” 는 점이다. 사용하는 용량이 크면 돈을 더 많이 내는 클라우드 성격상 전체 서비스를 올린 B모씨는 필요한 서비스만 확장하는 것 보다 더 많은 돈을 aws에게 뜯겼을 것이다. 하지만 B모씨가 더 열심히 공부해서 MSA를 알았다면, 이런 일이 발생했을 때, 2번 정보 서비스, 3번 업데이트 정보 관리 서비스가 배포된 서버만 증설하면 됐을 것이다. 결국 돈이 문제다.

이렇게 클라우드, 컨테이너의 발전으로 서비스를 분리해서 운영할 때 발생하는 이점이 점점 커지고 있기 때문에 위에서 보는 4번 장점이 더 두드러질 수 있다.

이렇게 만 보면 완전 무안단물 같은 MSA인데 모든 것엔 장,단이 있기 마련이다. MSA의 단점으로는

  1. 독립적 이기 때문에 모듈(모놀리식)의 장점인 재사용성이 떨어진다.
  2. 서비스가 독립적이라 중복 데이터가 발생할 수 있다.
  3. 각기 다른 팀이 독립적 서비스를 운영하게 되면 개발 환경 맞추는 것도 일이다.
  4. 하나의 서비스가 여러개로 분리됐기 때문에 관리하기가 좀 귀찮아진다.

하지만 이런 단점들은 이제 조심조심해서 서로 잘 소통하고 하면 추웅분히 해결할 수 있지 않을 까 싶다.

마이크로 프론트 엔드의 통합 패턴

마이크로 서비스는 결국 작은 서비스를 독립적으로 만들면서 이득을 취한다. 그럼 이제 독립적인 것들을 어떻게 하나의 큰 서비스에서 운영할 것인가가 관건이 된다.

방법1. ssr식 통합

각 서버별로 html을 요청해서 최종 응답서버가 결과물들을 하나로 합쳐서 내려주는 방식이다.

<html>
	<head></head>
	<body>
		<h1>공통 템플릿</h1>
	</body>
</html>

Nginx를 이용하여 이 html을 주고 URL에 따라서 Nginx경로를 바꿔준다.

server{
	listen 8080;
	root /usr/template/nginx/html
	index index.html

	# Redirect / to /browse
	
	location /browse{
		set $PAGE 'browse'
	}
	location /update{
		set $PAGE 'update'
	}
	location /info{
		set $PAGE 'info'
	}
}

방법2. 빌드타임 통합

Micro Frontend를 npm같은 패키지로 배포하고 컨테이너가 되는 앱이 그걸 라이브러리 종속성으로 포함하는 방식. 근데 잘 생각해보면 이러나 모놀리식이나 거기서 거기다. 뭐 하나 변경하고 적용하려면 다시 빌드 배포 해야하니까 말이다.

그러면 생각해보자, 감싸는 껍데기(컨테이너)를 건들이지 않고 내부 업데이트를 시켜야하는 상황에 직면한 것이다. 곧 빌드 통합이 아닌 런타임에 통합이 되어야한다.

방법3. iframe방식 통합

껍데기는 안건들이고 내부 콘텐츠를 바꿀 수 있는 방법이라 하면 그냥 그 서비스 페이지 불러와서 보여주는 건 어떨 까. iframe이라는 좋은 게 있는데.

그렇다 이게 제일 쉽긴하다. iframe내부 콘텐츠는 외부 콘텐츠 css,글로벌 변수 와는 독립적이게 된다. 하지만 우리는 또 다른 점을 생각해봐야하는데, iframe을 사용하게 되면 SEO라던지 라우팅, deep linking같은 부분에서 손해를 보게 된다. 또 iframe 태그안에 갇히기 때문에 스타일링이 제한적일 수 있다.

방법4. javascript를 통한 런타임 통합

현실적으로 사용하는 방식으로 각 마이크로 앱은 script태그로 페이지에 통합된다. 컨테이터 앱은 마이크로 앱을 script 태그로 다운 받고, 공통으로 약속된 랜더 메소드를 실행한다.

<html>
	<head></head>
	<body>
		<h1>공통 템플릿</h1>
		<div id='micro-front-end'></div>
		<script src='https://도메인.login.com/bundle.js'/>
		<script src='https://도메인.info.com/bundle.js'/>
		<script src='https://도메인.update.com/bundle.js'/>
		<script>
			const microFERoute = {
				'/':window.renderLogin,
				'/info':window.renderInfo,
				'/update':window.renderUpdate,
			} // 해당 전역 함수는 위에서 불러온 번들에 있는 것들

			const containerRender = microRERoute[window.location.pathname];
	
			containerRender('micro-front-end'); 
			// 랜더링할 js를 경로에 따라 선택 후 랜더링할 엘리먼트의 id를 준다.
		</script>
	</body>
</html>

추가적으로 web-component를 이용할 수도 있다.

FE통합시 주의 사항

js를 통한 통합처럼 하나의 html안에서 불러와서 사용하는 방식을 사용하면 고려할 사항이 몇 가지 있다.

  • 스타일링
    • BEM같은 엄격한 규칙 사용
    • SASS같은 전처리기를 통해 독립성 유지
    • CSS-in-JS로 독립성 유지
    • shadow DOM을 이용하여 엘리먼트 캡슐화 하기
  • component library
    • 마이크로 앱들간 UI의 일관성을 위해 공통 컴포넌트 라이브러리를 개발하여 재서용성을 확보한다.
  • 앱간 커뮤니케이션
    • 가능한 적은 소통
    • 메시지 혹은 이벤트를 이용한 통신이 바람직하고, 공통 상태를 갖는 건 비추
  • 백엔드
    • MFE에서 BFF(backend for frontend)패턴으로 프론트엔드 전용 API를 갖는데, 각 API는 프론트 엔드의 요구사항만을 충족한다.
    • BFF로 나누어진 백엔드는 각각의 DB를 가질 수 있다.
    • 로그인 인증같이 공통으로 사용되는 정보는 서비스를 통합하는 컨테이너가 갖는다.

정리

사내에서 백엔드 부분은 MSA를 적용해야한다는 말이 나왔을 때, 난 프론트니까 상관없겠지 라는 생각을 했지만 이젠..아니야 였다. 프론트에서의 서비스가 점점 다양하고 비대해지면 유지, 보수를 위해 MFE를 적용해야 누가 언젠가 할지 모를 프로젝트의 추가 수정 등의 유지보수를 하기 편할것이고, 그 누군가가 내가 될 가능성이 크기 때문에 더 좋은 방향으로 변화되어야 한다는 걸 느낀다.

참조

https://gruuuuu.github.io/cloud/architecture-microservice/

https://blog.wanzargen.me/38

https://martinfowler.com/articles/micro-frontends.html#TheExampleInDetail

profile
뉴비 개발자

0개의 댓글