Monolithic 모놀리틱 아키텍처?
태초에 Monolthic이 있었다. 웹 서비스에서는 UI, 비지니스 로직, DAO(데이터 베이스 액세스 Object) 이 모든 것들이 하나의 Application을 이루었다.
그런데 문제가 생기기 시작했다. Linkedin이나 Netflix같은 큰 기업들은 그들의 비즈니스 로직이 결코 단순하지 않았다. 그들의 데이터베이스 또한 여러가지 기능을 추가하면서 늘어났다.
복잡해진 비즈니스 로직과 추가된 기능에 따른 추가된 데이터베이스 테이블들은 결국 UI를 복잡하게 만들게 된다. UI에 다양한 이벤트가 추가되어야 하고, 수많은 기능들이 동작해야 했다.
거기까진 좋았다.
Netflix는 한 때 하나의 Oracle 데이터 베이스를 사용했었다. Netflix의 유저가 늘어나기 시작하면서 결국 지구상에서 가장 강력하다는 Oracle 데이터베이스가 다운되는 사상 초유의 사태가 벌어졌다.
문제가 생겼다.
Netflix는 6시간 정도 서비스가 불가능했다고 한다.(정확한 정보는 아니다) 사실 6시간 out of service는 웹서비스에 아주 치명적인 이슈다. 특히 스트리밍 서비스를 제공하는 회사는 더욱 그렇겠지..
대안이 필요했다.
Netflix는 자신의 서비스를 가능한한 다운되지 않은 최대한 강력한 서비스로 만들고 싶었다. 그들은 여러 대안을 찾았고, 결국 마이크로 서비스 아키텍쳐를 선택했다.
뿐만이 아니다. Monolithic 어플리케이션은 커지면 커질 수록 Build와 Complile, Deploy에 필요한 시간이 점점 늘어나게 만든다. 또한 작은 버그를 수정했음에도 불구하고 전체 Application을 Deploy하지 않으면 안된다. 방금 막 들어온 신입이 수정한 코드가 전체 서비스를 다운 시킬 수 있는 영향력을 발휘할 수 있는 것이 바로 Monolithic이다. 또한 UI 컴포넌트의 변화가 어플리케이션에 영향을 주게 되는.. 수많은 의존성(Dependency)이 나타날 수 밖에 없는 구조다..
그래서 변화가 필요했다.
첫번째 변화
첫번째 변화는 아마 레이어의 구분이 아닐까? 일단 REST API의 등장이다.
REST API는 HTTP프로토콜의 장점을 살리기 위해 로이 필딩(Roy Fielding)이라는 사람이 소개한 것이다. 요약하자면, GET POST PUT DELETE의 HTTP Method를 사용해서, 데이터를 가져오고, 등록하고, 수정하고, 삭제하는 기능을 하는 API이다. 가장 큰 특징은 Stateless, 즉 무상태성을 가지기 때문에, API 서버 내부에 쿠키와 같은 클라이언트와 관련된 정보를 저장하지 않는다는 것이다.
REST API는 주로 JSON오브젝트를 리턴하게 설계된다. 이는 UI와 비지니스 로직의 분리가 가능해졌다는 것을 의미하게 된다.
UI는 주로 CSS, 자바스크립트로 작성되고, API를 부르는 형태로 바뀌게 된다. REST API가 상태를 가지지 못하고 Authentification/Authorization문제를 가지기 때문에 API Gateway를 주로 이용하는데, 이는 다른 포스팅에서 설명한다.
우리는 UI와 비즈니스 로직을 결국 구분해냈다.
두번째 변화
두번째 변화는 Domain-Driven Design(도메인 드리븐 디자인)의 인기 상승이 아닐까?
REST API로 비지니스 로직은 구분해낸 우리 Backend는 결국 API끼리의 통신으로 도메인을 구분해 낼 수 있지 않을까?라는 물음에 도달한 것으로 보인다.
우리는 주문, 배송, 메일, 유저 등의 서비스를 도메인으로 구분하고, 각각의 REST API를 만들어서 서로 통신하게 만드는 데까지 이르렀다.
사람이 이해하기 쉬운 도메인에 따라 역할을 나누고 각각의 팀이 서로 다른 API를 책임지게 되는 팀 구조의 변화도 생긴다.
우리는 비즈니스 로직에서 도메인을 추출해냈다.
도메인에 따라 우리들의 API는 전혀 다른 데이터베이스를 가질 수 있었다. 데이터베이스의 구분은 우리가 다운되지 않은 서비스 제공할 수 있게 만들어준다. 주문 데이터베이스가 다운되더라도 다른 종류의 데이터베이스는 여전히 작동할 수 있으니까 말이다.
**그런데 여전히 문제가 있었다. **
우리는 여전히 수많은 사람들이 접속하는 Black Friday와 같은 순간에 제대로 버티지 못했다. 오직 그 순간만을 위해서 서버를 증설하는 것은 바보짓에 가까웠다. 왜냐면 평소에 그렇게 많은 서버가 필요하지 않으니까 말이다.
또한, 하나의 서버에 Log 수집기, 수 많은 스트립트 등이 동시에 동작했다. 이는 결국 Application에 문제가 없음에도 불구하고, 로그 수집기의 에러, 스트립트의 에러에 의해 서비스가 다운되는 사태가 생기는 원인을 제공한다. 불필요한 의존성이 아닌가?
세번째 변화
결국 Cloud Native 환경이 등장한다. Docker가 등장하면서 우리는 컨테이너의 개념에 대해 알게되었다.
엄청나게 많은 서버를 하나의 서버로 가상화하고, 그 가상화된 서버에서 가상 서버를 마음대로 찍어낼 수 있었다. 이는 AWS, GCP(Google Cloud Platform) 등이 등장하는 밑거름이 된다.
Docker는 같은 커널을 공유하지만 완전히 고립된(isolated) 서버를 만드는 기술이다. 우리는 Application을 오직 하나의 고립된(isolated) 서버에 올릴 수 있게 되었다. 결국 우리는 다른 스트립트가 우리의 어플리케이션에 영향을 주는 것을 없앨 수 있었다.
Cloud 서비스들은 우리가 서버를 마음껏 생성할 수 있게 해주었고, Docker는 Application이 하나의 서버에만 설치될 수 있게 해주었다.
우리는 이제 Scaling의 자유를 얻었다.
많은 유저가 접속하는 Black Friday에 우리는 그냥 미리 Instance(가상화된 서버)를 늘려주거나, Auto scaling을 이용해 인스턴스의 CPU를 감시하고 몇 %이상 늘어난다면 인스턴스를 늘려주면 되었다.
이제 드디어 Microservice인가?
위와 같은 변화는 우리가 하나의 어플리케이션을 더욱 작은 단위로 구분할 수 있게 도움을 주었다. 도메인에 맞게 각각의 API를 만들어 통신하면서 각각의 API는 각각의 데이터베이스를 가지는 구조로 변하게 되었다.
그런데 또 다른 문제가 있었다.
많아진 API들과 그 API가 가지는 수많은 Instance들을 어떻게 관리할 것인지에 관한 문제다.
Microservice 서비스를 만들어오면서 작게는 수십게 많게는 수백개의 API가 생겨나게 되었고, 이제 도저히 관리하지 못하는 지경에 이른다.
어떻게 관리해야 할까?
오케스트레이션
수많은 마이크로 서비스의 오케스트레이션이 필요해졌다. 다시 말하면 컨트롤 타워 같은 것?
Low level의 관점에서 등장한 것은 Container Ochestration 도구들이다. Kubernetes와 같은 도구는, 우리가 만들어낸 수많은 container(Docker instance와 같은)들을 하나의 머신에서 컨트롤 할 수 있게 만들어 준다.
또 다른 관점에서 Spring Cloud와 같은 Cloud 프로젝트들 또한, Discovery Service를 이용해 어플리케이션 인스턴스들을 등록하고, 등록된 인스턴스들의 정보를 제공해 Application 관점에서 우리가 인스턴스를 통제하고 관리할 수 있게 해준다.
다음에는 Spring Cloud, Kubernetes 등에 대해 포스팅 하겠습니다.