MSA 탄생 배경

클라우드 인프라 등장

전형적인 시스템 인프라 구축 과정을 살펴보면 서버를 도입하고 네트워크를 구축한 뒤 각 서버마다 운영체제를 설치하고 서비스에 필요한 소프트웨어를 설치하는 과정으로 진행되고, 전 과정을 완료하기까지 적게는 며칠에서 몇 주, 길게는 몇 달이 걸리기도 한다. 이처럼 애플리케이션을 개발하는 위한 인프라 환경을 준비하는 작업은 간단하지 않다. 어떤 기업은 인프라 전담 조직을 두기도 한다. 이러한 활동을 개발조직이 직접 담당하지 않고 인프라 조직에 요청한다면 의사소통 시간이 더해지므로 오래 시간이 걸리게 된다.

인프라구축

이러한 문제는 클라우드 인프라 등장으로 해결됐다. 서비스 개발에 필요한 인프라를 준비하는데 오랜 시간이 들지 않는다. 적당한 클라우드 플랫폼 벤더를 선택해 필요한 시점에 몇번의 클릭으로 손쉽게 개발 시스템 인프라를 만들 수 있다.

대표적인 플랫폼으로는 AWS, Azure, GCP 등이 있다.

클라우드 인프라에 어울리는 애플리케이션 조건

클라우드 인프라를 사용하면 사용량에 따라 비용을 유연하게 조정할 수 있다. 예를들어 쇼핑몰의 경우 타임세일 기간동안 사용자 트래픽을 예상해 시스템 용량을 증설하고, 기간이 지나면 원래대로 줄이고자 한다. 1주일 동안 용량이 증가해 있는 동안만 추가로 비용을 지불하고 싶은 것이다. 클라우드에서 이러한 유연한 용량 증감을 손쉽게 설정할 수 있다.

클라우드는 여러개 서버 장비가 모여 논리적으로 하나처럼 관리된다. 애플리케이션이 탑재되는 클라우드 인프라는 사용한 단위 만큼 비용을 지불하므로 애플리케이션 블록이 작으면 작을 수록 효율적이다. 특히 사용량이 증가할 운영 시점이라면 서비스 비용을 유연하게 관리할 수 있다.

스케일 업 스케일 아웃

사용량 증가에 따른 성능 및 가용성을 높이는 방법은 스케일 업(Scale-up)과 스케일 아웃(Scale-out)이 있다.

  • 스케일 업은 기존 시스템 자체에 물리적 용량을 증가시켜 성능을 높이는 방법이다.
  • 스케일 아웃은 기존시스템과 용량이 같은 다수의 장비를 병행하여 추가해서 가용성을 높이는 방법이다.

Drawing1

특정 서비스만 탄력성 있게 확장(스케일 아웃)

1주일간의 쇼핑몰 세일 기간중 바쁜 쪽은 세일 이벤트를 수행하는 부분이다. 나머지는 사용자가 몰리지 않아 한가해질 수 있다. 근데 이 모든 서비스의 시스템 용량을 증설하고 사용량이 몰리면 이 모든 것을 복제할 필요가 있을까? 당연히 낭비다. 세일 이벤트를 담당하는 조각만 용량이 증설되고 복제되어 트래픽에 대비하면 된다.

이를 해결하려면 전체가 한 덩어리로 묶여 있는 애플리케이션을 레고 블록처럼 분리하면 된다. 타임 세일 기간에 세일 이벤트 블록만 증설하면된다. 즉 시스템을 작은 단위의 독립적인 서비스 연계로 구성해야 한다. 쇼핑몰 운영자는 세일 기간 다음과 같은 시나리오를 상상해 볼 수 있다.

  • 첫 번째 단계에서 운영자는 타임세일 서비스만 분리돼 있으므로 타임세일 서비스의 용량만 고려해서 증설한다. (스케일 업)
  • 두 번째 단계에서 독립된 타임세일 서비스의 사용량을 고려해서 트래픽이 증가하면 타임세일 서비스 인스턴스만 복제되도록 설정한다.
  • 전체 시스템이 사용할 메모리 크기가 16GB였다면 타임세일 서비스에 필요한 용량은 3~4GB 정도에 불과하다. 이전 시나리오에서는 전체 시스템에 할당된 16GB의 메모리 크기를 32GB로 증설한 후 32GB가 여러개로 복제된 비용을 지불했는데 이제는 타임 세일 서비스에 필요한 3GB를 8GB로 증설하고 8GB가 여러개로 복제된 비용만 지불한다.

클라우드 프렌들리와 클라우드 네이티브

전체 시스템을 하나의덩어리로 만들어 클라우드 인프라에 올려도 비지니스를 제공하는데는 문제가 없다. 그러나 특정 기능만 확장하거나 배포할 수 없는 비효율을 감수해야 한다. 클라우드 플랫폼 중 하나인 클라우드 파운드리(Cloud Foundry)를 서비스하는 피보탈(Pivotal)에서는 이처럼 큰 덩어리로 클라우드 환경에 올라갈 수 있게만 한 애플리케이션을 클라우드 호친화 애플리케이션이라 하고, 독립적으로 분리되어 배포될 수 있는 조각으로 구성된 애플리케이션을 클라우드 인프라에 가장 어울리고 효과적이라는 의미로 클라우드 네이티브 애플리케이션이라고 부른다.

마이크로 서비스란

모노리스와 비교

전통적인 모노리스(Monolith) 구조 부터 보자. 모노리스는 하나의 단위로 개발되는 일체식 애플리케이션이다. 보통 3티어라 불리는 사용자 인터페이스, 데이터베이스, 서버 쪽 애플리케이션의 3개로 구성된다.

monolith

서버측 애플리케이션이 일체, 즉 논리적인 단일체로서 아무리 작은 변화에도 새로운 버전으로 전체를 빌드해서 배포해야 한다. 그리고 일체식 애플리케이션은 단일 프로세스에서 실행된다. 따라서 확장이 필요할 경우 특정 기능만 확장할 수 없고 반드시 전체 애플리케이션을 동시에 확장해야 한다. 보통 로드 밸런서를 앞에 두고 여러 인스턴스 위에 큰 덩어리를 복제해 수평으로 확장한다.

이런 상황에서 변경이 발생하면 모노리스 시스템의 단점이 극대화된다. 여러 개의 모노리스가 수평으로 확장된 상태이므로 여러 개의 모노리스 시스템 모두를 전부 다시 빌드하고 배포해야한다. 또한 확장 시 애플리케이션이 병렬로 확장되어 사용량 증가에 대응할 수 있지만 데이터베이스는 통합되어 하나이므로 탄력적으로 대응할 수 없다. 따라서 사전에 성능을 감당하기 위해 스케일 업을 통해 용량을 증설해야한다.

반면 마이크로 서비스는 서버 측이 여러 개의 조각으로 구성돼 각 서비스가 별개의 인스턴스로 로딩된다. 즉 여러 서비스 인스턴스가 모여 하나의 비지니스 애플리케이션을 구성한다. 또한 각기 저장소가 다르므로 업무 단위로 모듈 경계가 명확하게 구분된다. 따라서 확장 시에는 특정 기능별로 독립적으로 확장할 수 있고, 특정 서비스를 변경할 필요가 있다면 해당 서비스만 빌드해서 배포하면 된다. 또 각 서비스가 독립적이어서 서로 다른 개발 언어로 개발하는 것도 가능하므로 서비스의 소유권을 분리해 서로 다른 팀이 개발 및 운영할 수 있다.

SOA와 마이크로서비스

SOA 발전 과정

  • 기능을 하향식 분해해서 설계해 나가는 구조적 방법론
  • 객체 단위로 모듈화 하기 위한 객체지향 방법론
  • 모듈화의 단위가 기능별로 재사용할 수 있는 좀 더 큰 컴포넌트가 되는 CBD(Component Based Development)
  • 컴포넌트를 모어 비지니스적으로 의미 있고 완결적인 서비스 단위로 모듈화하는 SOA(Service Oriented Architecture)로 이어지는 발전 과정을 거친다.

CBD와 SOA도 넓게 보면 단위 컴포넌트나 서비스를 구성해서 시스템을 만드는 개념이고 MSA와 매우 유사하다. 그렇다면 SOA와 어떤 개념적 차이가 있을까?

넓게 보면 여러 개의 응집된 비지니스 서비스의 집합으로 시스템을 개발한다는 점에서 SOA와 MSA는 개념적으로 큰 차이가 없다. 그러나 SOA는 구체적이지 않고 이론적이며, 비지니스 성공 사례가 많지 않다. MSA는 클라우드 인프라 기술의 발전과 접목되어 아마존과 넷플릭스에 의해 구체화되고 비지니스 성공 사례로 널리 공유된 바있다. 즉 SOA가 성공되지 못했지만 클라우드 인프라의 등장으로 하드웨어를 유연하게 다룰 수 있게 되면서 성공적으로 증명된 시스템 구조가 MSA라고 할 수 있다.

martinfowler_msa

위는 마틴 파울러(Martin Fowler)가 정의한 마이크로서비스 개념을 표현한 개념도다. 각 서비스와 저장소는 다른 서비스 및 저장소와 격리돼 있으며, API를 통해서만 느슨하게 연계된다. 따라서 독립적으로 확장 가능하고 하나의 서비스만 독립적으로 배포가능하다. 다른 서비스와 연계된 API에 영향을 주지않는다면 내부의 언어나 저장소는 자율적으로 선택할 수 있다.

이처럼 특정 서비스를 구축하는 데 사용되는 언어나 저장소를 자율적으로 선택할 수 있는 방식을 가리켜 폴리글랏(Polyglot)하다라고 표현한다. 클라우드 등의 가상 인프라가 지닌 유연성이 이를 가능하도록 지원한다.

폴리글랏 저장소 특성을 통해 CBD/SOA와의 차이를 발견할 수 있다. MSA는 데이터 저장소까지 분리를 해냈다. 따라서 데이터의 강한 결합으로 애플리케이션도 독립적으로 사용하기 힘들었다. 그러나 MSA에서는 SOA에는 없었떤 다음 두가지 개념으로 모듈화 방식을 강화했고 이를 진정으로 실현한다.

  • 서비스별로 저장소를 분리해서 다른 서비스가 저장소를 직접 호출하지 못하도록 캡슐화한다. 즉, 다른 서비스의 저장소에 접근하는 수단은 API밖에 없다.
  • REST API 같은 가벼운 개방형 표준을 사용해 각 서비스가 느슨하게 연계되고 누구나 쉽게 사용할 수 있다.

마이크로 서비스를 위한 조건

여기서 설명하는 것은 마이크로서비스를 잘 구현하고 있는 조직들의 사례이며 동시에 마이크로서비스를 구현하기 위한 필요 조건이된다. 이러한 시각은 msa의 성공이 기술에만 의존한 아키텍쳐 스타일을 추구하는 데 그치지 않고 개발 환경, 문화, 일하는 방식과도 연계돼 있음을 보여준다.

조직의 변화: 업무 기능 중심팀

콘웨이 법칙(Conway’s law)는 멜빈 콘웨이(Melvin E. Conway)가 정의한 조직과 조직이 개발한 소프트웨어의 관계를 정의한 법칙이다. 쉽게 말하면 시스템을 개발할 때 항상 시스템의 모양이 팀의 의사소통 구조를 반영하는 것을 말한다.

예전에는 애플리케이션을 만드는데 UI팀, 서버개발팀, DB팀과 같은 기술별로 팀이 나뉘어져 있고 하나의 애플리케이션을 만드는 데는 세 팀간의 의사소통이 필요하다. 따라서 시스템도 이러한 의사소통 구조를 그대로 반영하고, 이러한 팀 구조에서는 팀 간의 의사결정도 느리고 의사소통도 어렵다.

마이크로 서비스 구조로 개발하는 팀은 업무 기능 중심의 팀이어야 한다. 업무 기능 중심 팀은 역할 또는 기술별로 팀이 분리되는 것이 아니라 업무 기능을 중심으로 기술이 다양한 사람들이 하나의 팀이 되어 서비스를 만드는 것을 의미한다.

업무 기능 중심 팀은 다양한 역할로 구성되고, 이 팀은 서비스를 처음부터 끝까지 만들기 위한 모든 단계에서 역할을 모두 갖추고 있다. 이 팀은 같은 공간, 같은 시간을 공유하기 때문에 의사소통도 원활하고 의사결정도 빠르게 진행할 수 있다.

이 팀을 여러 기능들이 모여 있다는 의미에서 다기능 팀(Cross-Functional Team)이라고도 한다.

crossfunctionalteam

이 팀은 자율적으로 담당 비지니스에 관련된 서비스를 만들뿐만 아니라 개발 이후에 운영할 책임까지 진다. 아마존은 이런 팀을 ‘two pizza team’이라고 표현하는데, 이는 피자 두판으로 서로 번번히 의사소통하며 함께 식사할 수 있는 정도의 팀원 수를 의미하며, 한 팀에 다양한 역할을 수행하는 사람들이 모여 있으며 개발과 운영을 동시에 수행하는 팀이다.

이러한 팀은 마이크로서비스를 만드는 데 필요한 기능과 기술을 팀 내부에 모두 가지고 있으므로 다른 마이크로서비스팀과는 협력할 일이 적을 수밖에 없다. 따라서 콘웨이 법칙에 의해 이 팀이 만든 마이크로서비스도 다른 팀이 만든 마이크로서비스와는 느슨하게 연계된다.

image

관리체계의 변화: 자율적인 분권 거버넌스, 폴리글랏

다기능 팀이 개발과 운영을 책임진다 하는데 이러한 조직문화를 가리켜 “you built it, you run it”이라는 모토로 표현한다. 간단히 의역하면 “우리가 만들고 우리가 직접 운영한다”라는 의미다. 마이크로 서비스를 만드는 조직은 중앙의 강력한 거버넌스를 추구하지 않는다. 각 마이크로서비스팀으로 구성된 조직은 중앙의 강력한 표준이나 절차 준수를 강요하지 않는다. 각 팀은 빠르게 서비스를 만드는 것을 최우선 목적으로 두고 스스로 효율적인 방법론과 도구, 기술을 찾아 적용한다. 현실 세계에 비유하자면 작은 정부나 지방자치제도와 유사할 것이다.

개발 생명 주기의 변화: 프로젝트가 아니라 제품 중심으로

기존에는 대부분 애플리케이션 개발 모델이 프로젝트 단위였다. 그래서 필요한 기술을 사용하는 인력들이 한시적으로 모여 장기간의 프로젝트를 통해 개발을 완료하고 나면 이를 운영 조직에 넘기는 방식으로 진행됐다. 즉 개발조직과 운영 조직이분리돼있다.

또한 초기에 모든 일정을 계획했다. 요구사항 정의를 통해 개발할 기능을 나열하고, 이에 대한 설계를 진행하며, 설계가 완료돼야 개발이 진행되고, 각단계는 완료 데드라인이 있어 그 일정을 완료함으로써 최종 기능을 제공한다. 따라서 프로젝트 중 발생한 변경이나 새로운 아이디어가 포용되지 못한다.

그러나 마이크로 서비스팀의 개발은 비지니스의 갑작스러운 트렌드 변화에 유연하게 대처해야하고 개발 뿐만 아니라 운영을 포함한 소프트웨어의 전체 생명주기를 책임져야한다. 따라서 소프트웨어를 완성해야 할 기능들의 집합으로 보는 것이 아니라 비지니스를 제공하는 제품으로 바라보고, 개발한 뒤에 반으을 보고 개선하는 방식으로 소프트웨어를 개발한다. 즉 소프트웨어를 개발하는 방식 측면에서 프로젝트 형태의 폭포수 모델 또는 빅뱅 방식으로 진행하는 것이 아니라 점진 반복적인 모델, 제품 중심의 애자일(agile) 개발 방식을 채용한다.

이 같은 방식은 2~3주 단위의 스프린트(Sprint)를 통해 소프트웨어를 개발 및 배포해서 바로 피드백을 받아 소프트웨어에 반영할 수 있게 해준다. 따라서 소프트웨어를 한시적 프로젝트를 통해 고객의 고정된 요건을 받아 기능이 만족되면 제공 및 전달하는 개념으로 보지 않고 요건의 변화에 따라 지속적으로 개선되고 발전시킬 제품으로 바라본다.

img

즉 마이크로서비스는 계속 피드백을 받아 지속적으로 변화, 개선되고 향상되는 존재다.

개발 환경의 변화: 인프라 자동화

마이크로서비스는 독립적으로 배포된다. 모노리스처럼 한 덩어리로 배포한다면 수동으로 배포하는 방식도 크게 문제가 없겠지만 마이크로서비스처럼 여러 개로 쪼개진 상태에서는 수동으로 배포하는 방식으로 바람직하지 않다. 따라서 여러 개의 마이크로서비스를 빠르게 배포하기 위한 방법이 필요하다.

가장 좋은 방법은 자동화다. 개발지원 환경을 자동화하는 데는 소스코드를 빌드하는 도구와 빌드와 동시에 테스트하는 도구, 가상화된 인프라에 배포하는 도구가 모두 필요하다. 마이크로서비스팀이 단기간에 제품을 빨리 개발하고 피드백을 받기 위해서는 이러한 개발지원 환경의 자동화가 반드시 갖춰져야 한다. 이 같은 환경을 개발과 운영을 동시에 수행하는 데브옵스(DevOps)를 궁극적으로 가능하게 하므로 데브옵스 개발 환경이라 속칭하기도 한다.

또한 이러한 개발 환경, 개발지원 환경을 자동화하는 것을 모두 통틀어 인프라 자동화라기도 한다. 인프라 자동화는 마이크로서비스 개발 과정의 필수조건이 돼야 한다.

빌드/배포 파이프라인은 일반적으로 소스코드 빌드 -> 개발환경 배포 -> 스테이징 환경 배포 -> 운영환경배포로 구성된다. 이러한 빌드/배포 파이프라인 프로세스는 도구를 통해 자동화해야한다. 최근에는 배포환경이 마이크로서비스 개수에 따라 급격하게 늘어나기 때문에 이를 효율적으로 관리하기 위해 인프라 구성과 자동화를 마치 소프트웨어처럼 코드로 처리하는 방식인 ‘Infrastructure as Code’가 각광받고 있다. 코드를 이용해 인프라 구성부터 애플리케이션 빌드, 배포를 정의하는 것을 의미하는데, 이렇게 되면 수많은 하드웨어 리소스 설정을 동일하게 통제할 수 있으며, 상황에 따른 검증되고 적절한 설정을 쉽게 복제하고 누구한테나 공유할 수 있게 돼서 인프라를 매우 효율적으로 관리할 수 있다.

저장소의 변화: 통합 저장소가 아닌 분권 데이터 관리

이전의 모노리스 시스템을 살펴보면 단일 통합 데이터베이스를 사용한다. 이러한 단일 데이터 베이스를 유지하는 방식은 과거 스토리지 가격 및 네트워크 속도에 따른 데이터의 안정성과 효율성을 추구한 결과다. 따라서 데이터를 잘 정리하는 정규화가 반드시 추구해야 할 가치였다. 지금은 스토리지 가격이 저렴하고 네트워크 대역폭이 매우 커졌다. 데이터를 억지로 뭉쳐 작은 공간에 넣을 필요가 없다.

마이크로 서비스는 폴리글랏 저장소(polyglot persistence) 접근법을 선택하며, 서비스별로 데이터베이스를 갖도록 설계한다. 즉, 각 저장소가 서비스별로 분산돼 있어야 하며, 다른 서비스의 저장소를 직접 호출할 수가 없고 API를 통해서만 접근해야 한다는 의미다.

이러한 구조에서는 비지니스 처리를 위해 일부 데이터의 복제와 중복 허용이 필요하다. 이 때 발생하는 문제는 데이터의 비지니스 정합성을 맞춰야하는 데이터 일관성 문제다.

데이터 일관성을 처리를 위해서는 보통 2단계 커밋(two-phase commit) 같은 분산 트랜잭션 기법을 사용하는데, 각각 다른 서비스를 하나의 트랜잭션으로 묶다 보면 각 서비스의 독립성도 침해되고 NoSQL 저장소처럼 2단계 커밋을 지원하지 않는 경우도 있다. 따라서 마이크로서비스는 데이터 일관성 문제를 해결하기 위해 두 서비스를 단일 트랜잭션으로 묶는 방법이 아닌 비동기 이벤트 처리를 통한 협업을 강조한다.

이를 가리켜 결과적 일관성(Eventual Consistency)라는 개념으로 표현하기도 하는데, 간단히 말해 두 서비스의 데이터가 일시적으로 불일치하는 시점에 있고 일관성이 없는 상태지만 결국에는 두 데이터가 같아진다는 개념이다. 즉, 여러 트랜잭션을 하나로 묶지 않고 별도의 로컬 트랜잭션을 수행하고 일관성이 달라진 부분은 체크해서 보상 트랜잭션으로 일관성을 맞추는 개념이다.

### 위기 대응 방식의 변화: 실패를 고려한 설계

시스템은 언제든 실패할 수 있고 더는 진행할 수 없을 때도 자연스럽게 대응할 수 있도록 설계해야 한다. 이러한 성격을 내결함성(fault tolerance)라고 한다. 실패를 하지 않는 시스템을 만드는 것보다 실패에 빠르게 대응할 수 있는 시스템을 만드는 편이 효율적이다.

이를 위해 대비책을 마련해야하고 실패를 감지하기 위한 모니터링 시스템도 필요하다. 이러한 예로 서킷 브레이커(circuit breaker) 패턴을 둘 수 있는데, 이 패턴은 회로 차단기처럼 각 서비스를 모니터링 하고있다가 한 서비스가 다운되거나 실패하면 이를 호출하는 서비스의 연계를 차단하고 적절하게 대응하는 것을 말한다. 이러한 설계는 긴급 상황에 빠르게 대처할 수 있다.