마이크로서비스 – MicroServices

“마이크로서비스 아키텍처(Microsservice Architecture)”라는 용어는 소프트웨어 응용 프로그램을 독립적으로 배치 가능한 서비스 조합(suite)으로 설계하는 방식으로서 지난 몇 년 동안 빠르게 자리잡아 가고 있습니다. 본 아키텍처 스타일에 대해 아직 명확한 정의는 없지만, 비지니스 수행과 관련된 조직, 배포 자동화, (서비스) 엔드 포인트의 지적 능력(intelligence), 그리고 프로그래밍 언어와 데이터의 분산 제어에 관한 일반적인 특징들은 존재합니다.

2014년 3월 25일


James Lewes
ThoughtWorks의 컨설턴트며 기술자문 멤버이며, 확장성 높은 엔터프라이즈 시스템을 통합하는 것부터 작은 협력 서비스를 만드는 데 관심을 가지고 있습니다. 최근 몇 년간 커뮤니티에 왕성하게 참여하면서 마이크로서비스를 이용한 다양한 서비스를 만들어 왔습니다.

Martin Fowler
소프트웨어 개발에 대한 저자이자 연사로서 컴포넌트 기반 소프트웨어 시스템의 문제를 해결하고자 노력해 왔으며, 더 혼란스럽다는 피드백을 들었습니다. 마이크로서비스 구조를 통해 이러한 초기의 약속이 살아 있음을 전파하고자 하고 있습니다.

한국어 번역: 윤석찬(Channy Yun)
This article is Korean translation of Micro Services written by James Lewis and Martin Fowler. It may contain incorrect expressions and errota and please refer to primary article in english for your ensurance. 본 번역본은 원 저자의 허가 하에 게재되어 있으며, 번역 상 오류가 있을 수 있으며 내용을 인용하는 경우 반드시 원본을 참조하시기 바랍니다.


목차

참고글

“마이크로서비스”- 요즘 다양한 소프트웨어 아키텍처가 유행하는데 추가된 새로운 용어입니다. 뭔가 새로운 것을 거부하려는 것이 자연적인 반응이겠지만, 이 용어는 점점 매력적인 최근 소프트웨어 시스템 스타일 사례를 설명하고자 하는 것입니다. 몇 년간 이런 스타일의 프로젝트를 많이 봐 왔으며 그 결과는 지금까지 매우 성공적입니다. 그래서 우리 동료들이 엔터프라이즈 응용 프로그램을 구축하기 위한 기본 스타일로 사용 중입니다. 그런데, 안타깝게도 마이크로서비스가 무엇인지, 어떻게 하면 좋은 것인가하는 것에 대한 개요를 설명하는 정보는 많지 않습니다.

간단하게 말하면, 마이크로서비스 아키텍처 스타일 [1]은 단일 응용 프로그램을 나누어 작은 서비스의 조합으로 구축하는 방법이며, 각 개별 서비스는 자신의 프로세스에서 실행하는 HTTP 기반 API 등으로 가벼운 연결 방식을 사용합니다. 각 서비스는 비지니스 로직의 수행 기능에 맞게 구축 된 완전히 자동화 된 머신에 의한 배포를 통해 이루어 집니다. 각 서비스의 최소한의 중앙 관리 기능은 있지만, 서로 다른 프로그래밍 언어에 의해 개발되고, 다른 데이터 저장 기술이 이용할 수 있습니다.

마이크로서비스에 대한 설명함에 있어 모놀로식(Monolithic) 스타일과 비교하는 것이 효과적입니다 : 모놀리식 응용 프로그램은 하나의 큰 덩어리 단위로 구축합니다. 엔터프라이즈 응용 프로그램은 종종 세 가지 주요 부분으로 구성됩니다 : 클라이언트 측의 UI (HTML 페이지와 사용자 단말기의 브라우저에서 실행되는 Javascript), 데이터베이스(공통으로 사용되며 일반적으로 관계형 데이터베이스의 다수의 테이블로 구성) 및 서버 측 응용 프로그램입니다. 서버 사이드 애플리케이션은 HTTP 요청을 받아 도메인 로직을 실행하여 데이터베이스에서 업데이트 된 데이터를 추출한 뒤, 고객 브라우저로 HTML로 만들어진 뷰(View)를 생성하고 전달합니다. 이 서버 사이드 애플리케이션은 대부분 하나의 논리적인 실행 파일[2]입니다. 시스템에 대한 변경이나 서버 측 응용 프로그램이 바뀌면 완전히 새로운 버전을 컴파일해서 배포하게 됩니다.

이러한 모놀리식 한 구조는 이런 시스템을 구축하는 방법으로 자연스러운 것입니다. 요청을 처리하는 로직은 모두 단일 프로세스로 처리 된 응용 프로그램에서 수행하고, 클래스 및 함수, 네임스페이스로 분할하는 프로그래밍 언어의 기본 기능을 이용합니다. 자세히 살펴보면, 응용 프로그램을 개발자 컴퓨터에서 실행 및 테스트를 진행하고 이러한 테스트를 완료하면 실 서버로 배포 가능한지 확인하는 배포 파이프라인를 사용합니다. 이러한 단일 애플리이션은 일반적으로 로드 밸런서 뒤에 여러 (서버) 인스턴스에서 실행하고, 확장할 수 있습니다.

일반적으로 모놀리식 응용 프로그램은 잘 작동하지만 서서히 문제가 발생되게 됩니다. 클라우드에 애플리케이션을 점점 많이 배포되는 경우 특히 그렇습니다. 특히, 배포 주기를 늘리는 것이 점점 어려워집니다. 응용 프로그램 내 작은 부분에 대한 변경이 있더라도, 모놀리식 방식은 모드 빌드해서 다시 배포해야 합니다. 시간이 지남에 따라 모듈 구조를 문제 없이 유지하는 것은 점점 어려워지고, 각 모듈의 변경 사항을 그 모듈에만 한정하는 것도 힘들어집니다. 서버 확장성도 자원을 더 필요로 하는 부분만 ​​아니라 전체 응용 프로그램의 규모에 따라 더 필요해 집니다.

Figure 1 : Monoliths and Microservices

그림 1. 모놀리식 방식과 마이크로서비스의 비교

이러한 문제로 인해 마이크로서비스 아키텍처 스타일를 도입하게 됩니다: 즉, 큰 응용 프로그램을 여러 작은 서비스의 조합으로 구축하는 것입니다. 각 서비스는 독립적으로 배치 가능하고 확장 가능할 뿐만 아니라 서로 다른 프로그래밍 언어로 개발된 다른 서비스임에도 불구하고 명확한 모듈 상의 경계를 가지고 있습니다. 또한, 각 서비스는 그것을 만든 팀들이 직접 관리할 수 있습니다.

우리는 마이크로서비스 스타일이 새롭거나 혁신적인 것이라 생각하지 않지만 적어도 유닉스(Unix)의 설계 사상을 근본으로 두고 있음을 말하고 싶습니다. 아직 사람들이 마이크로서비스를 충분히 고려하고 있지 않다고 생각하고, 많은 소프트웨어 개발자들이 마이크로서비스 방식을 활용함으로써 더 나은 서비스를 만들 수 있기를 바랍니다.

마이크로서비스 구조의 특징

앞서 말한대로 마이크로서비스 아키텍처 스타일의 정확한 정의는 없지만, 마이크로서비스에 대한 일반적인 특징을 나열 해 볼 수는 있습니다. 일반적인 특징을 나열한다고 해서 모든 마이크로서비스가 다 가지고 있는 특징은 아니라는 점도 밝혀둡니다. 하지만, 대부분 마이크로서비스 아키텍처가 이러한 특징을 가지고 있다고 예상합니다. 우리가 다소 느슨한 커뮤니티 보다는 더 활동적인 사람들이기는 하지만, 이 글의 원래 의도는 우리가 해 온 일과 우리가 아는 팀들이 해 온 일을 좀 더 잘 설명하기 위한 것이며, 아래 사항들이 따라야할 무엇인가를 규정하고있는 것은 아닙니다.

서비스를 통한 컴포넌트화

소프트웨어 산업에서는 오랫 동안 구성 요소(Component)를 나누고 이를 연결하는 시스템을 구축해 왔습니다. 이것은 자연계에 존재하는 일반적인 생각과 똑같은 원리입니다. 최근 10-20 년 동안 우리는 대부분의 개발 언어 환경의 공통 라이브러리의 놀라운 발전을 보아 왔습니다. 구성 요소에 대해 논의 할 때, 무엇이 구성 요소를 만드는가 하는 것을 정의하는 것은 어렵습니다. 그래서, 간단하게 우리는 구성 요소를 독립적으로 대체하거나 업그레이드 가능한 소프트웨어 단위로 정의하겠습니다.

마이크로서비스 역시 라이브러리를 사용하지만, 각 소프트웨어 자체를 컴포넌트화하는 첫 번째 방법은 여러 서비스로 분리하는 것입니다. 우리는 라이브러리로를 프로그램에 링크되어 메모리 내 함수 호출을 사용하는 구성 요소로 정의합니다. 이것은 서비스가 웹 서비스 요청 또는 RPC와 같은 통신 외부 프로세스 구성 요소인 것과는 대조적입니다. (이 정의는 많은 객체 지향 프로그램[3]의 서비스 객체의 개념과는 다른 것입니다.)

(라이브러리가 아닌) 구성 요소로서 서비스를 정의하는 주요 이유 중 하나는 각 서비스가 독립적으로 배치 가능하기 때문입니다. 만약 단일 프로세스 내에 다중 라이브러리에 의해 응용 프로그램[4]을 구성하는 경우, 각 구성 요소의 변경으로 인해 전체 응용 프로그램의 재배포가 필요합니다. 하지만, 응용 프로그램이 여러 서비스에 분해되어 있었을 경우 다수의 서비스가 각각 변경되는 경우에는 해당 서비스의 재배포만 필요합니다. 물론 이것은 절대적인 것이 아니며, 약간의 변화만 있으면 각 서비스 인터페이스도 조금씩 바뀔 수는 있습니다. 하지만, 결국 마이크로서비스 아키텍처의 목적에 맞는 적합한 서비스 경계를 만들어서 앞으로 서비스 사이의 약속을 보장하면서 진화해 나갈 것입니다.

컴포넌트로서 서비스를 사용하면 각 구성 요소의 인터페이스가 보다 명시적이 된다는 점도 중요합니다. 대부분의 프로그래밍 언어는 명시적인 공표된 인터페이스를 정의하는데 효과적인 메커니즘을 가지고 있지 않습니다. 클라이언트가 구성 요소 캡슐화를 파괴하는 것을 방지하기 위해서는 기술 문서나 내부 코딩 규칙에 의존해야 하고, 결국 구성 요소 간의 결합도를 지나치게 높이는 결과를 가져옵니다. 각 서비스는 명시적인 원격 호출 메커니즘을 이용하여 이러한 종속과 결합을 방지하는데 도움을 줍니다.

이와 같은 서비스를 만드는데 따른 부정적인 측면도 분명히 있습니다. 원격 호출은 프로세스 내부 호출보다 비용이 높기 때문에 원격 API는 각 구성 요소를 크게 나누는(coarse-grained) 경향이 있습니다. 사용하기 어려울 뿐만 아니라 만약 구성 요소 간의 책임 할당을 변경할 필요가 있는 경우, 이러한 변화는 프로세스 경계를 넘는 경우 더욱 힘든 일이 될 것입니다.

첫번째 시제품으로 서비스를 런타임 프로세스에 매핑 할 수 있을 것 같지만, 어디까지나 그것은 시제품입니다. 따라서, 서비스는 응용 프로그램 프로세스 및 서비스에서만 사용되는 데이터베이스와 함께 배포되는 다중 프로세스로 구성할 수 있습니다.

비지니스 수행에 따른 구성

거대한 응용 프로그램을 분할하는 경우에 볼 수 있는 흔한 관리 방식은 기술적 계층에 초점을 맞추어 UI 팀, 비지니스 로직 팀, 그리고 데이터베이스 팀과 같은 편성하는 것입니다. 이러한 사고 방식에 따라 각 팀을 분리할 때, 단순한 변경이 필요한 경우라도 리소스 및 예산 승인에 시간이 걸리고 자칫 많은 팀간 협업을 해야 하는 커다란 프로젝트 규모가 될 수 있습니다. 현명한 팀은 이런 일을 최적화하고 더 나은 방법을 지향합니다 – 즉, 변경이 필요한 응용 프로그램 안에 모두 로직을 넣는 것입니다. 즉, 비지니스 로직을 어디서나 포함(Logic everywhere)시킵니다. 이것은 Conway의 법칙[5] 에 따라 행동 한 예입니다.

(일반적으로 정의되는) 시스템을 설계하는 어떤 조직도 자신의 조직이 가진 커뮤니케이션 구조를 복제하는 아키텍쳐 디자인을 만들어 낸다.
– Melvyn Conway 1967

Conway의 법칙의 실제

그림 2. Conway의 법칙의 실제

마이크로서비스의 접근 방식은 비지니스 수행 능력에 따라 정리된 서비스로 나눈다는 점이 조금 다릅니다. 물론 각 서비스는 비즈니스 영역에 해당하는 소프트웨어 스택 구현을 광범위하게 포함 할 수 있습니다. 즉, 사용자 인터페이스, 영구 스토리지, 외부 연계 등입니다. 이에 따라 각 팀은 상호 기능적(cross-functional)이며, 개발을 위해 필요한 모든 범위의 기술을 포함 할 수 있습니다 – 사용자 체험, 데이터베이스, 프로젝트 관리 등등.

팀의 경계에서 강화 된 서비스 경계

그림 3. 팀의 경계에서 서비스 경계로

이러한 방법으로 조직 된 기업으로 comparethemarket.com을 들 수 있습니다. 각자 상호 기능형 팀은 각 제품을 구축 및 운용할 책임를 가지고 각 제품은 메시지 버스(Bus)를 통해 통신하는 여러 독립적인 서비스로 분할되어 있습니다.

물론 거대한 모놀리식 응용 프로그램도 사업 수행 능력에 따라 모듈화 할 수 있습니다. 하지만, 우리는 모놀리식 애플리케이션을 구축하는 거대한 팀을 비지니스 항목에 따라 분할하도록 권장하고 있습니다. 우리가 주목하고 있는 문제는 회사들이 맥락(context)에 따라 너무 많은 조직을 구축하는 경향이 있다는 것입니다. 만약 모놀리식 방식이 다수의 모듈 경계를 넘는 경우, 팀의 개별 구성원들의 단기 기억이 의존해야하는 어려움이 있습니다. 또한, 모듈 경계를 이해하기 위해 강제적으로 많은 교육이 필요하다는 것을 경험했습니다. 명시적인 서비스 구성 요소에 의해 분할함으로서 명확한 팀 경계를 유지하는 것이 더 쉽습니다.

마이크로서비스의 크기
마이크로서비스가 유명한 아키텍쳐 스타일이 되었다해도 용어 자체가 서비스의 크기에 초점을 맞추지 않고 “마이크로”라는 단어 때문에 계속 논쟁이 있을 수 밖에 없습니다. 마이크로서비스를 해 본 사람들도 그 범위가 넓다는 것을 인정합니다. 가장 큰 규모는 Amazon에서 밝힌 Two Pizza Team(이상적인 팀의 크기는 피자 두 판으로 한 끼를 떼울 수 있는 규모) 즉, 12명을 넘지 않는 다는 것입니다. 우리가 본 제일 작은 팀은 6개의 서비스를 지원하는 6명의 팀입니다.
서비스별로 12명이 필요한지, 서비스별로 한명만 있으면 되는지 또 다른 의문을 만들어 냅니다. 현재로서는 어떤 팀이라도 마이크로서비스를 가능하게 하면서 더 발전할 수 있는 마인드로 함께 변화하는 것이 중요합니다.

프로젝트가 아니라 제품

우리가 본 대부분의 응용 프로그램 개발 활동은 프로젝트 모델을 사용하고 있습니다: 일단 완성을 목표로 소프트웨어를 배포해야 하는 목적 때문입니다. 프로젝트가 끝나면, 소프트웨어는 운영 조직에 넘겨지고 그 소프트웨어를 구축 한 프로젝트 팀은 해산합니다.

마이크로서비스를 해 본 사람들은 이러한 모델을 피하는 대신 각 팀은 제품의 전체 라이프 사이클을 책임지는 개념을 좋아합니다. 이러한 발상은 Amazon이 만든 개념인 “자신이 만든 건 자신이 실행(you build, you run it)하라”는 것과 일맥 상통하며, 각 개발팀이 자신의 소프트웨어 제품의 전반적인 책임을 지는 것입니다. 이 개념은 매일 매일 개발자들이 배포한 소프트웨어의 실행 행태에 대해 살피면서 일반 사용자와의 접점과 피드백을 늘리는 것입니다. 물론 이는 어느 정도 고객 지원을 해야 하는 부담도 함께 안게 됩니다.

제품을 인식하는 방식에서 이러한 고려 사항은 사업 수행 능력에 강하게 결합됩니다. 즉, 소프트웨어를 완성하고자 하는 기능의 집합으로 보기보다 어떻게 소프트웨어가 사용자의 비지니스를 향상시킬 수 있는가 하는 질문에 관계하기 때문입니다.

동일한 접근이 모놀리식 응용 프로그램에도 채택될 수도 있지만, 세분화 된 서비스를 통하면 각 서비스 개발자와 사용자 사이의 밀접한 피드백 관계를 쉽게 구축할 수 있습니다.

똑똑한 엔드 포인트와 더미(Dumb) 파이프

다른 프로세스 간의 통신 구조를 만들 때, 통신 방식 그 자체를 스마트하게 하는데 중요하게 생각하는 제품 개발 접근 방식을 많이 보았습니다. 한 예로 Enterprise Service Bus (ESB)가 있습니다. ESB 제품은 메시지 라우팅, 코레오그래피(choreography), 변환 그리고 비즈니스 규칙 적용을 위한 정교한 기반을 제공하고 있습니다.

마이크로서비스 커뮤니티는 대체로 그 대안으로 “현명한 엔드 포인트와 바보 파이프라인” 방식을 선호합니다. 마이크로서비스에서 빌드 된 응용 프로그램은 가능한 느슨하게(decoupled) 만들지만, 응집성을 높히는 것을 목표로합니다 – 각 응용 프로그램은 각자 도메인 로직을 가지고 고전적인 유닉스에 있는 필터보다 더 잘 작동합니다 – 요청을 수신하면, 적절한 로직을 적용하고 응답을 생성합니다. 이는 WS-Choreography 혹은 BPEL, 또는 중앙 집중식 도구에 따른 관리(orchestration)되는 복잡한 프로토콜이 아니라, 간단한 REST 방식 프로토콜 에 의해 스스로 제어(choreographed)하는 형태입니다.

가장 일반적으로 사용되는 두 개의 프로토콜은 리소스 API 를 이용한 HTTP 요청 응답과 경량 메시지 전달 [6]입니다. 전자의 최선의 표현은 다음과 같습니다.

바로 웹으로 해라! 웹 뒤에 두지 말고…
– Ian Robinson

마이크로서비스를 다루는 팀은 월드 와이드 웹과 (Unix의 확장 방식을) 기초로 한 원칙과 프로토콜을 사용합니다. 자주 사용되는 자원은 각 개발자 및 운영자의 작은 노력으로 캐싱할 수도 있습니다.

두 번째 접근 방식은 가벼운 메시지 버스 너머로 메시지 통신을 하는 것입니다. (단지 메시지 라우터로만 작동하는) 더미 방식의 인프라입니다 – RabbitMQ 또는 ZeroMQ 같은 간단한 구현은 신뢰성있는 비동기 패브릭 기능 이상 하지 않습니다 – 똑똑한 기능 처리는 바로 메시지의 생성과 소비를 할 엔드 포인트에 존재합니다; 즉, 서비스에 있습니다.

모놀리스에서는 각 구성 요소를 프로세스에서 실행하고, 구성 요소 간의 통신을 메소드 호출이나 함수 호출에 의해서 이루어집니다. 마이크로서비스로 변경하는 가장 주목할 만한 문제점이 바로 통신 패턴의의 변경에 따르는 점입니다. 인메모리의 메소드 호출에서 RPC로 바꾸어 보면 그다지 잘 작동하지 않는 복잡한(chatty) 통신이 되어 버립니다. 크게 만들어진 통신 방식 대신 더 세밀한 방식으로 대체해야 합니다.

마이크로서비스와 서비스 지향 구조(SOA)
마이크로 서비스를 이야기할 때 가장 많이 받는 질문 중이 바로 10년전 우리가 알고 있는 SOA와 무엇이 다른가 하는 점입니다. 마이크로서비스는 SOA가 말하는 것과 유사해서 이해시키기 빠르다는 장점이 있습니다. 하지만 SOA는 너무나 많은 다른 개념을 가지고 있고, 여기서 말하는 마이크로서비스 스타일과는 확실이 다릅니다. 즉, 모놀리식 애플리케이션을 서로 연결하는 ESB에 초점을 맞추니까요.ESB에서 복잡성을 숨기는 서비스 지향 구현 방식[7]을 많이 봐 왔는데, 몇 년씩 시간만 낭비하고 수백만 달러가 날아가는데도 별 가치가 없는 중앙 집중식 거버넌스를 가진 경우가 많았습니다. 이것이 바로 과거의 문제점입니다.마이크로서비스에서 커뮤니티에서 사용한 많은 기술들은 큰 조직에서 다양한 서비스를 통합하려는 개발자들의 경험에서 비롯되었습니다. Tolerant Reader패턴이 바로 그 실례입니다. 웹을 사용하는 노력과 단순한 프로토콜을 이용하면 다른 경험들을 파생합니다. 하지만, 고정된 표준은 복잡성을 증가시켜서 결국 복잡한 표준을 만들어 온톨로지와 같은 관리하기 힘든 문제에 봉착합니다.)

SOA에 대한 일반적인 거부감 때문에 마이크로서비스를 SOA 정도로 치부하고 반대하는 경향이 있습니다[8]. 마이크로서비스가 SOA와 비슷한 형태로 이해하더라도, 서비스 지향 방법론은 나쁘지 않고 좀더 아키텍쳐 측면에서 다루는 용어라고 생각하면 좋을 것입니다.

분산화 거버넌스

중앙 집중 거버넌스 시스템의 만드는 결과 중 하나는 단일 기술 플랫폼을 표준화하는 경향입니다. 이것은 문제 해결 활동을 억제하는 결과를 초래할 있습니다 – 들고 있는 게 망치 뿐이라면 모든 문제가 못으로 보입니다. 우리는 문제 해결을 위한 올바른 도구를 선택하는 것을 선호합니다. 모놀리식 응용 프로그램이 어느 정도까지 서로 다른 언어를 사용할 수 있는 장점을 얻을 수 있더라도 일반적이지 않습니다.

모놀리식 구성 요소를 각각 서비스로 나누게 되면, 이들을 구축 할 때 기술 플랫폼을 선택할 수 있는 여지가 있습니다. 간단한 보고서 페이지를 구축하기 위해 Node.js를 사용 하시겠습니까? 준 실시간 반응 기능을 가진 서비스를 만들기 위해 C++를 사용할까요? 한 구성 요소의 데이터를 간단히 읽기 위해 완전히 다른 관계형 데이터베이스를 쓸 것인가요? 재구축을 하기 위해 선택할 수 있는 적합한 기술들이 있습니다.

물론 할 수 있다고, 그것을 해야한다는 것은 아닙니다 – 그러나 시스템을 분할함으로서 이런 선택 사항이 가능한 것입니다.

마이크로서비스를 구축해 왔던 팀은 표준에 대해서도 다른 접근 방식을 선호합니다. 문서에 정의된 표준 구축 가이드를 사용하는 것보다, 그들이 직면한 문제와 유용한 해결 도구를 직접 만드는 발상을 좋아합니다. 이러한 도구를 각 개발 그룹에서 공유하고 때로는 폐쇄된 내부 오픈 소스 모델 형식을 취합니다. git과 github가 사실상 표준 버전 컨트롤 시스템의 선택이 된 지금 이러한 조직 내 오픈 소스 방식의 개발이 점점 확산되고 있습니다.

Netflix는 이러한 이념을 따르는 조직의 좋은 예입니다. 먼저 유용한 도구를 공유하고, 실전에서 단련된 라이브러리 코드를 통해 다른 개발자가 같은 문제를 같은 방법으로 해결 가능합니다. 필요한 경우, 다른 방법을 선택할 수 있도록 열려 있습니다. 공유 라이브러리는 데이터 저장 과정의 통신 방식, 그리고 이후에 설명하는 인프라 자동화와 같은 공통 문제에 집중할 수 있게 합니다.

마이크로서비스 커뮤니티에서 오버 헤드는 신경 쓰는 요소가 아닙니다. 서비스간 약속이 중요하지 않아서 그렇게 말하는 것이 아닙니다. 정반대로 매우 중시하는 경향이 있습니다. 단순히 상호 교류 방식을 관리하기 위해 전혀 다른 방법을 생각하고 있을 뿐 입니다. Torelant ReaderConsumer-Driven Contracts 같은 패턴을 마이크로서비스에 적용해 왔습니다. 이들은 서비스간 교류를 독자적으로 진화 할 수 있도록 지원합니다. 개발 중에 고객에 대한 기능 약속을 이행하는 것은 개발자 스스로 자신감을 높히고 서비스 기능에 대해 의견을 신속하게 제공합니다. 고객 기반 계약을 통해 새로운 서비스 구축을 추진하고있는 호주의 팀을 알고 있습니다. 그들은 서비스 계약을 정의하는 간단한 도구를 이용하고 있습니다. 이 도구는 새로운 서비스 코딩을 하기 전에 이미 자동 빌드가 되고 있습니다. 각 서비스는 그 때 요구 사항을 만족하는 기능만 개발합니다 – 새로운 소프트웨어를 구축 할 때 ‘YAGNI’[9] 딜레마를 해결하기 위한 방식입니다. 이러한 기법 및 도구의 활용을 통해 주위에 만들어진 서비스 간의 임시 결합을 감소시킴으로써 중앙 집중식 계약 관리의 필요성을 제한하고 있습니다.

분산 거버넌스의 가장 최고의 사례는 바로 Amaozon이 만들고 실행하는 이념입니다. 각 팀은 일 주일 7일/24시간 운영하는 것을 포함하여 각 팀이 구축한 소프트웨어의 모든 측면을 책임지고 있습니다. 이 책임 수준이 옮겨지는 경우는 거의 없으며, 각 회사에서 개발팀에 대한 책임을 가지게 하는 업체가 점점 늘어나는 있습니다. Netflix도 이러한 개념을 도입한 곳입니다[11]. (장애로 인해) 매일 밤 새벽 3시에 개발자를 호출하게 되면, 나중에 코딩을 할 때 품질에 대해 더 생각하게 하는 강력한 동기가 됩니다. 이러한 아이디어가 실현 가능해짐에 따라 전통적인 중앙 집중적 거버너스 모델에서 벗어나게됩니다.

프로그래밍 언어와 선택 사항
JVM이 플랫폼으로 성장한 것이 일반적인 플랫폼내에서도 다양한 언어를 활용할 수 있는 단초를 제공했습니다. 수십년 동안 높은 단계의 추상화를 실현하기 위해 고급 언어를 쓰는 잇점을 벗어나 좀 더 성능을 높이려면 낮은 수준의 언어도 써야 한다는 점을 알게 되었습니다. 그러나 모놀리식 방식은 이러한 수준별 성능 최적화를 할 수 없을 뿐 아니라 높은 수준의 추상화에도 어려움이 생깁니다. 모놀리스 방식이 하나의 언어만 사용하고 사용 가능한 기술의 숫자를 제한할 수 밖에 없습니다.[10]

분산화된 데이터 관리

분산화 데이터 관리는 많은 다양한 방법이 존재합니다. 가장 추상적인 수준에서 시스템 간의 다른 세계의 개념적 모델을 의미합니다. 이는 큰 기업 솔루션을 통합 할 때 일반적인 문제이며, 고객에 대한 판매 관점은 기술 지원 관점과 다릅니다. 판매 관점의 고객이라고 칭한 무언인가는 기술 지원 관점에서는 전혀 나오지 않을 것입니다. 다른 속성을 가질 수 있고, 더 나쁜 것은 미묘하게 다른 의미를 가진 일반적인 특징이 있습니다.

이러한 문제는 그간 응용 프로그램 사이에 공통적으로 발생한 것으로서 각 응용 프로그램이 별도의 구성 요소로 분할 되어있을 때 특히 그렇습니다. 이 문제를 검토 할 때, 효과적인 방법이 도메인 지향 설계(Domain-Driven Design, DDD)에서 도메인 경계를 고려하는 것입니다. DDD는 복잡한 도메인을 여러 도메인 경계로 분할하여 각자 관계를 설계합니다. 이 프로세스는 모놀리식 및 마이크로서비스 아키텍처 둘다 적용되지만, 서비스와 컨텍스트 경계 사이에는 이들을 명확히 하는 것을 돕는 자연적인 관계를 통해 비지니스 수행 능력의 분리를 권장합니다.

개념 모델에 대한 분산화 결정과 마찬가지로 마이크로서비스는 데이터 스토리지를 분산시킵니다. 모놀리식 응용 프로그램이 데이터 지속성을 위해 단일 논리 데이터베이스를 사용하는 것을 선호하는 반면, 기업은 다양한 애플리케이션에 걸쳐 하나의 데이터베이스를 사용하는 것을 선호합니다 – 이러한 결정의 대부분은 벤더들의 라이센스와 상용 구매 모델에 관련되어 있습니다. 마이크로서비스는 각 서비스가 각각 소유하는 데이터베이스를 각자 관리하도록 하고, 다른 인스턴스가 동일한 데이터베이스 기술 또는 완전히 다른 데이터베이스 시스템에서 구동해도 상관하지 않습니다 – 이를 Polyglot Persistence라고 합니다. 모놀리스 방식에서도 Polyglot Persistence 사용할 수 있지만, 마이크로서비스에서 더 자주 볼 수 있습니다.

Polyglot Persistence

마이크로서비스를 거쳐서 데이터에 대한 분산 책임은 업데이트 관리에 대한 점을 시사합니다. 업데이트에 대처하는 일반적인 방법은 여러 리소스를 업데이트 할 때 일관성을 보장하기 위해 트랜잭션을 사용하는 것입니다. 이 방법은 모놀리스 내부에서 자주 사용됩니다.

이처럼 트랜잭션을 사용하는 것이 일관성 유지에 도움을 주지만, 상당히 임시적 결합을 강제하게 되고 이 결합은 여러 서비스에 걸쳐 있는 어려운 과제입니다. 분산 트랜잭션은 아시다시피 구현이 어렵고, 결과적으로 마이크로서비스 아키텍처는 서비스 간의 트랜잭션 협조를 중요시 합니다. 일관성은 영구적인 일관되기만 하면 좋고, 문제는 보상 작업으로 다뤄진다는 인식에 따릅니다.

이러한 방법에 따라 비일관성 관리를 선택하는 것은 많은 개발팀에게 새로운 도전이지만, 비지니스 현장에서는 잘 맞습니다. 종종 실무에서 오는 요구에 신속하게 반응하여 이러한 모순을 해결합니다. 이때, 오류에 대처하기 위해 어떤 역처리 방식이 있습니다. 이러한 트레이드 오프를 통해 오류를 수정하는 비용이 일관성 하에서 사업 기회를 잃는 비용보다 적은 더 가치가 있습니다.

현장 테스트식 표준과 규정된 표준
마이크로서비스 팀은 기업 내부의 엄격한 규정으로 만든 표준은 피하고, HTTP나 ATOM 및 다른 공개 표준을 선호한다고 하는 이분법적인 생각이 존재합니다.

다른점은 표준이 어떻게 만들어지고, 어떻게 강제되는가 하는 점입니다. IEFT와 같은 표준 그룹에서 표준을 만들고 관리하지만, 오픈 소스 프로젝트에서 만든 것이 더 성공적으로 이용되고 더 많이 구현되고 더 오 살아남습니다.

이런 특정 주도 표준들은 기업 현장과는 약간 동떨어져 있고, 즉 최신 프로그래밍 경험이 적은 그룹이나 벤더에 영향을 받아 만들어지기도 합니다.

인프라 자동화

인프라 자동화 기술은 지난 몇 년 동안 눈부시게 발전하고 있습니다 – 클라우드 특히 AWS의 진화는 마이크로서비스 구축, 배포, 운영의 복잡도를 현저하게 감소시키고 있습니다.

마이크로서비스로 구축된 제품과 서비스 대부분은 지속적인 배포지속적인 통합과 같은 풍부한 경험을 가진 팀에 의해 구축되어 있습니다. 이 방법으로 소프트웨어를 구축하고있는 팀은 인프라 자동화 기술을 광범위하게 사용하고 있습니다. 이것은 아래에 나타내는 파이프 라인에 의해 표시할 수 있습니다다.

Figure 5 : basic build pipeline

그림 5. 기본적인 빌드 파이프라인

이 글은 지속적 배포에 상세한 내용을 다루기는 어렵고 두 가지 주요 특징에 대해서만 언급하겠습니다. 우리는 소프트웨어가 동작한다는 신뢰를 가능한 많이 얻기 원하기 때문에 많은 자동화 된 테스트를 실행합니다. 잘 동작하는 소프트웨어가 파이프 라인을 “올라”가는 것은 각 새로운 환경에 배포 자동화를 의미합니다.

모놀리식 응용 프로그램을 구축 테스트하고 이러한 환경을 완수하는 것은 사실 운이 좋은 것일 수 있을 것입니다. 일단 제품의 경로를 자동화하는 데, 힘을 쏟아 붓는 프로그램을 추가 배치하는 것은 그렇게 힘든 일은 아닙니다. 지속적인 배포의 목적 중 하나는 것을 알 수 있습니다. 지속적인 전달의 목적 중 귀찮게 하는 것을 없애준다는 것을 잊지 마십시오. 따라서, 응용 프로그램이 한 개가 되었든 세 개로 됐건 문제가 아닙니다.[12]

광범위한 인프라 자동화를 사용하는 팀에 있어서 주목할 점 중 하나는 제품화 중 마이크로서비스를 관리하는 시기입니다. 배포가 귀찮다는 점에서 모노리스와 마이크로서비스 사이에 대단한 차이가 없다는 주장과는 대조적으로 각 방식을 운용하는 데 대한 상황은 놀랄만큼 달라집니다.

Figure 6 : Module deployment often differs

그림 6. 모듈 기반 배포 방식의 차이

올바른 것을 쉽게 만드는 방식
지속적인 배포 및 통합으로 자동화를 함으로서 얻은 추가 효과중 하나는 개발자 및 운영자들의 작업을 돕는 유용한 도구를 만든다는 점입니다. 새롭게 가공하고, 코드를 관리하여 간단한 서비스로 만들거나 모니터링 및 표준적인 로깅을 적용하는 것은 일상적입니다. 가장 최고의 사례가 바로 Netflix의 오픈 소스 도구입니다. 이 중 Dropwizard는 널리 알려진 도구입니다.

장애 방지 설계

컴포넌트로서 서비스를 사용한 이유로 응용 프로그램을 각 서비스 장애에 견딜 수 있도록 설계해야 합니다. 모든 서비스 호출이 공급자 측면에서 제공하지 못하는 원인으로 실패할 가능성이 있기 때문에 클라이언트는 가능한 한 이 상황에 대응 해야합니다. 이것은 모놀리식 설계에 비해 불리한 것으로 해당하는 추가적인 복잡성을 도입해야 합니다. 그 결과, 마이크로서비스를 채택하는 팀은 서비스가 사용자 경험에 미치는 영향을 지속적으로 검토합니다. Netflix의 Simian Army는 응용 프로그램의 내구성 및 모니터링을 테스트하기 위해 업무 시간에 서비스와 데이터 센터에 대해서도 직접 장애를 만들기도 합니다.

제품화 과정에서 이런 종류의 자동화 테스트는 보통 일 주일 휴가를 떠나기 직전에 일어나는 것과 비슷한 두려움과 비슷합니다. 모놀리식 아키텍처 스타일은 정교한 모니터링을 설정하는 데 충분하다고 말할 수 없습니다 – 적어도 우리의 경험에서는 말이죠.

각 서비스는 언제든지 실패 할 가능성이 있기 때문에 신속하게 장애를 감지하고 가능하면 자동으로 서비스를 복구 할 수하는 것이 중요합니다. 마이크로서비스 응용 프로그램은 실시간 감시에 중점을두고 있으며, 아키텍처 요소(데이터베이스가 받는 1초당 요청 수)와 비즈니스 관련(1초당 받든 주문 번호와 같은) 부분을 모두 확인합니다. 의미있는 모니터링을 실시함으로써 개발 팀이 계속 추적 및 연구해야 뭔가 나쁜 상황을 조기에 경고 시스템을 통해 제공 받을 수 있습니다.

마이크로서비스의 경우, 서비스 기반 취향과 이벤트 협업으로 인해 긴급 상황에 대한 일이 생기기 때문에 모니터링이 특히 중요합니다. 기존의 현명한 사람들은 우연하게 발생하는 문제의 가치를 중요시하는 한편, 이런 긴급 상황이 때로는 좋지 않은 상황이 될 수도 있습니다. 모니터링은 나쁜 상황에 대해서도 이를 감지하고 신속하게 해결할 수 있도록하기 위해 필수적입니다.

모놀리식 방식도 마이크로서비스 만큼이나 높은 투명성으로 구축 할 수 있습니다 – 실제로, 그래야 합니다. 그 차이는 서로 다른 프로세스에서 실행되는 서비스가 종료 된 때, 완벽하게 파악하는 것이 필요하다는 것입니다. 동일한 프로세스 내의 라이브러리가 있는 경우 이런 종류의 투명성은 별로 유효하지 않습니다.

마이크로서비스를 채택하는 팀은 서비스의 설정 상태 및 각종 운영 및 비즈니스 관련 메트릭을 표시하는 대시 보드와 같은 개별 서비스에 대한 정교한 모니터링 및 로깅 설정을 볼 수 있어야 합니다. Circuit breaker 상태에도 현재 처리량과 지연에 대한 자세한 내용은 현장에서 자주 마주치는 사례입니다.

서킷브레이커와 제품 기반 코딩
서킷브레이커는 제품 출시에 나타납니다. 대량 접속과 타임아웃 같은 패턴을 동반합니다. 잘 구현이 되었는데도 이와 같은 패턴이 자주나타나는 이뉴는 애플리케이션간 통신을 만들때 일어납니다. 이러한 의존성을 잘 설명하는 방법을 넷플릭스 블로그 글에서 잘 설명하고 있습니다.

진화하는 설계

마이크로서비스를 실행하려는 분들은 보통 진화하는 설계 경험을 배경으로 가지고 서비스를 분해하는 것을 변화를 감속시키지 않고 제어하기 위한 더욱 진보된 방식이라고 생각하고 있습니다. 변경 사항 제어는 반드시 변경을 속도를 줄이는 것을 의미하는 것은 아닙니다 – 올바른 태도와 도구를 통해 소프트웨어를 더 자주 빠르게 제어 할 수 있습니다.

소프트웨어 구성 요소 로 분해하려고 할 때마다 어떻게 조각으로 분할할 것인가 결정을 해야합니다 – 응용 프로그램을 나누는 원칙은 무엇일까요? 구성 요소 의 핵심 속성은 독립적인 교환 및 업그레이드 가능성입니다[13]. – 즉, 관련 모듈에 영향을 주지 않고 구성 요소 를 다시 업데이트 할 수있는 포인트를 찾을 필요가 있다는 것입니다. 많은 마이크로서비스 그룹은 장기적으로 많은 서비스가 진화하기보다는 스크랩하는 것을 명확히 예상하는 개념을 중시합니다.

Gurdian의 웹 사이트는 모놀리식 방식으로 설계 · 구축되었다가, 마이크로서비스의 방향으로 진화한 응용 프로그램의 좋은 예입니다. 모놀리식 방식은 지금도 대다수 웹 사이트의 존재하고 있으나, 새로운 기능을 만들 때 기존 모놀리식 방식에 API를 이용한 마이크로서비스로 구축할 수 있습니다. 이러한 접근 방식은 본질적으로 임시 기능, 예를 들면 특별 페이지나 스포츠 이벤트의 종류에 특히 유용합니다. 이러한 웹 사이트의 부분은 빠르게 개발할 수있는 프로그래밍 언어를 이용하여 구성하고, 이벤트가 끝나면 즉시 폐기를 빠르게 할 수 있습니다. 유사한 접근 방식을 금융 기관에서도 볼 수 있어 시장 기회를 파악하고 새로운 서비스를 시작하거나 몇 주 또는 몇 달 후 폐기할 수 있습니다.

호환성을 중시하는 모듈 방식 설계의 일반적인 원칙이며, 이러한 방식의 설계 변경 패턴을 통해 모듈화를 구동하는 것입니다[14]. 변경 사항은 동시에 같은 모듈에서 일어나는 것이 바람직합니다. 거의 변경되지 않는 시스템 부분은 현재 변경을 많이 하고있는 부분과는 다른 서비스로 해야 합니다. 만약 두 서비스를 동시에 변경할 경우가 여러번 있으면, 이는 그 서비스들이 합쳐져야 합니다.

구성 요소를 서비스로 추가하면, 더 세분화된 출시 계획을 잡을 수 있는 기회를 얻을 수 있습니다. 모놀리스 의 경우 어떤한 병경 사항도 응용 프로그램 전체의 재배포를 필요로합니다. 마이크로서비스의 경우, 변경된 서비스 만 다시 배포하면 됩니다. 이는 출시 프로세스를 더욱 간단하고 신속하게 할 수 있습니다. 단점은 기존 서비스에 대한 변경이 이 서비스를 이용하고있는 다른 서비스에 영향을 주는지 여부를 신경써야 한다는 점입니다. 기존의 통합 접근 방식은 버전 관리를 사용하여 이 문제를 해결하려고합니다. 그러나, 마이크로서비스의 세계에서는 마지막 수단으로 버전 관리를 사용하는 것을 선택합니다. 서비스를 제공 측에서 변경 사항에 나올 문제를 견딜 수 있도록 설계하여, 복잡한 버전 관리를 피할 수 있습니다.

동기화 호출의 해악
서비스간에 동기화 호출이 일어나게 되면 시스템이 다운되는 복잡한 상황에 직면하게 됩니다. 시스템이 다운되면 각 서비스의 개별 컴포넌트에도 영향을 미치칩니다. 이 때 다운타임을 관리할 것인지 비동기로 돌릴 것인지 선택해야 합니다. 가디언 웹 사이트의 경우, 새로운 시스템을 설계할 때 사용자 호출에 대해 하나의 동기화 호출을 한다는 정책을 정했고, 넷플릭스의 경우는 아예 모든 API가 비동기적으로 통신하게 새로 API를 디자인했습니다.

마이크로서비스의 미래

이 글을 쓴 주요 목표는 마이크로서비스의 큰 틀에서의 이상과 원리를 설명하는 것입니다. 글을 쓰는 도중에도 마이크로서비스 아키텍처 스타일이 중요하다고 확신하게 되었으며, 엔터프라이즈 응용 프로그램에 대해 진지하게 심사 숙고할 만한 사항입니다. 우리는 최근 이러한 스타일을 사용하여 여러 시스템을 구축하고, 이 방법을 사용하길 원하는 경우가 많다는 것을 알게되었습니다.

우리가 알고있는 Amazon, Netflix, The Gardian, 영국 정부 전자 서비스, Realestate.com.au, Forward와 Comparethemarket.com을 포함한 많은 서비스가 이러한 아키텍처 스타일을 개척하고 있습니다. 2013 년의 각종 컨퍼런스에서는 마이크로서비스로 전환하려고 하고 있는 기업의 사례로 가득했습니다 – 여 Travis CI를 포함합니다. 또한, 우리가 마이크로서비스로 분류하는 기법을 오랫동안 해온 조직도 많이 있지만, 마이크로서비스라는 이름은 사용하지 않는 곳도 있습니다.(종종 이것은 SOA 라고 호칭합니다 – 그러나 이미 언급 한 바와 같이 SOA 는 많은 대립하는 형식을 가지고 있습니다[15])

이러한 긍정적 경험에도 불구하고 우리는 마이크로서비스가 향후 소프트웨어 아키텍처의 미래 방향성이라는 것을 자신있게 말하고자 하는 것은 아닙니다. 현재 우리의 경험에 의하면 모놀리식 애플리케이션에 비해 선호하지만, 자신있게 판단을 내릴 시간은 아직 아닙니다.

아키텍처 결정의 실제 결과는 구축 후 몇 년이 지난 후에 입증되는 것입니다. 모듈화의 강렬한 욕망이있는 좋은 팀이 수 년을 거쳐 쇠퇴하는 모놀리식 아키텍처를 구축한 프로젝트를 보기도 했습니다. 서비스 경계가 명확하고 여기 저기에 걸치는 게 어렵기 때문에 마이크로서비스보다 문제가 적다고 볼 수도 있습니다. 그러나, 아직 충분한 시간을 거쳐 충분한 수의 시스템을 보지 않았기 때문에 우리는 마이크로서비스 아키텍처가 얼마나 성숙하는지 판단 할 수 없습니다.

마이크로서비스가 덜 성숙하는 것이 아닌가라고 누군가가 생각하는 이유는 분명히 있습니다. 어떤 구성 요소에 대한 노력도 소프트웨어에 구성 요소를 어떻게 적응 하느냐에 달려 있습니다. 구성 요소 경계를 어디에선가 규정해야 하는지를 정확하게 이해하는 것은 힘듭니다. 진화하는 디자인은 올바른 경계를 얻기의 어려움을 인식하고, 그래서 리팩토링 하기 쉽다는 것에 중점을 두고 있습니다. 구성 요소가 원격 통신을 서비스 할 때, 리팩토링 과정의 라이브러리는 더 힘듭니다. 서비스 경계를 넘어 코드를 이동시키는 것은 어렵고, 어떤 인터페이스 의 변경도 관계자 간의 조정이 필요하며, 하위 호환성 을위한 레이어가 추가되어 테스트는 복잡해질 수 밖에 없습니다.

다른 과제로 만약 구성 요소가 질서 정연하게 구성되지 않는 경우, 구성 요소 내부의 복잡성을 구성 요소 간의 연결 복잡성으로 마이그레이션 할 수 있습니다. 이것은 단순히 복잡성이 주위에 이동했다는뿐만 아니라 거기가 복잡성을 명시이지 않고 제어가 어려운 장소라는 것입니다. 구성 요소 내부가 작고 단순하게보기 좋아진 것처럼 보이지만, 서비스 간의 별거 연결을 간과하는 경향이있다.

마지막으로, 팀의 기술 요소가 있습니다. 신기술은 더 능력이 높은 팀에 맞는 경향이 있습니다. 그러나 더 능력이 높은 팀에 효과적인 기술이 더 능력이 낮은 팀에서 반드시 잘 작동한다고는 할 수 없을 것입니다. 우리는 더 능력이 낮은 팀이 심한 모놀리식 아키텍처 를 구축 한 예를 많이 봐 왔지만, 이런 종류의 문제가 마이크로서비스 발생했을 때 무슨 일이 일어나는가는 시간이 지나도 보지 않으면 알 수 않습니다. 빈약한 팀은 항상 빈약 한 시스템을 만듭니다 – 마이크로서비스가 이러한 경우 끔찍한 상황을 완화하고 가치를 창출하는지 여부를 자신있게 말하는 것은 매우 어렵습니다.

우리가들은 하나의 납득할 수있는 논의는 반드시 마이크로서비스 아키텍처에서 시작해야한다는 뜻은 아니라는 것입니다. 모놀리스에서 시작하는 대신 모듈화를 유지하고 일단 모놀리스 가 문제가되면 마이크로서비스로 분할하는 것입니다. (좋은 프로세스의 인터페이스는 일반적으로 좋은 서비스 인터페이스가 아니기 때문에 이러한 조언이 이상적이라는 것은 아니지만 말입니다.)

우리는 신중한 낙관론을 가지고 이 글을 쓰고 있습니다. 지금까지 우리는 마이크로서비스를 충분히 관찰하고 이것을 밟아 다진 길에 가치가있는 것이라는 느낌을 받고 있습니다. 이것이 종착점이라고 확신을 가지고 단언 할 수 없습니다. 그러나 현재 손에 들고있는 완벽한보기는 어렵다 정보를 바탕으로 결정을 할 수 밖에 없다는 것은 소프트웨어 개발의 도전입니다.

더 읽어 볼 글

블로그 및 온라인 기사

서적

발표 자료

논문

  • L. Lamport, “The Implementation of Reliable Distributed Multiprocess Systems”, 1978 http:// research.microsoft.com/en-us/um/people/lamport/pubs/implementation.pdf
  • L. Lamport, R. Shostak, M. Pease, “The Byzantine Generals Problem”, 1982 (available at) http:// www.cs.cornell.edu/courses/cs614/2004sp/papers/lsp82.pdf
  • R.T. Fielding, “Architectural Styles and the Design of Network-based Software Architectures”, 2000 http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
  • E. A. Brewer, “Towards Robust Distributed Systems”, 2000 http://www.cs.berkeley.edu/ ~brewer/cs262b-2004/PODC-keynote.pdf
  • E. Brewer, “CAP Twelve Years Later: How the ‘Rules’ Have Changed”, 2012, http:// www.infoq.com/articles/cap-twelve-years-later-how-the-rules-have-changed