Implementing an API Gateway

이제, API Gateway를 사용하는 것에 대한 동기부여와 trade-off(서로 대립되는 요소 사이의 균형점)에 대해서 살펴봤는데, 이제 고려해야할 다양한 디자인 이슈에 대해서 살펴보자.

Performance and Scalability
(성능과 확장성)

단지 몇개의 회사만 Netflix의 규모로 운영되고 있고, 하루에 수십억건의 요청을 처리할 필요가 있다. 그러나, 일반적으로 API Gateway의 성능과 확장성은 대부분의 어플리케이션에서 매우 중요하다. 그러므로 플랫폼에서 Asynchronous, Non-blocking I/O를 지원하는 API Gateway 만드는 것이 필요하다. 확장 가능한 API Gateway를 구현하기 위해 사용하는 기술들은 다양하다. JVM상에서 Netty, Vertx, Spring Reactor, JBoss Undertow와 같은 NIO(Non-Blocking I/O) 기반 framework를 사용할 수도 있다. 일반적으로 Chrome의 Javascript engine인  Node.js도 non-JVM 기반의 한가지 선택이 될 수 있다. 또다른 선택은 NGINX PLUS를 사용하는 것이다. NGINX PLUS는 성숙하고 확장 가능하며 고성능의 웹 서버와 쉽게 배포할 수 있고, 설정 가능하고, 프로그램될 수 있는 reverse proxy를 제공한다. NGINX PLUS는 authentication(인증), access control(접근제어), load balancing requests(요청 부하 분산), caching responses(응답 캐싱), 어플리케이션을 인식하는 health check와 모니터링을 관리할 수 있다.

Using a Reactive Programming Model
(반응 프로그래밍 모델 사용:이벤트를 비동기 데이터 흐름으로 보는 프로그래밍 방법)

API Gateway는 어떤 요청들에 대해서는 간단히 적합한 backend service로 전달한다. 다른 요청들에 대해서는 여러 개의 backend service를 호출하고, 그 결과를 취합한다. 상품 상세 정보 요청과 같은 어떤 요청들은 서로 독립적인 backend service에 요청하기도 한다. 응답 시간을 최소화하기 위하여, API Gateway는 동시에 독립적으로 요청을 처리해야 한다. 그러나, 때때로 요청 사이에는 의존 관계가 있다. API Gateway는 요청을 backend service로 전달하기 전에, 처음에 authentication service(인증 서비스)를 호출하여 요청에 대해 인증할 필요가 있다. 이와 유사하게, 고객의 wish list에서 상품에 대한 정보를 가져오려고 할 때, API Gateway는 먼저 정보를 담고 있는 고객의 프로파일을 조회하고, 각 상품에 대한 정보를 조회해야만 한다. API composition(구성)의 또다른 흥미로운 예제는 Netflix Video Grid이다.

전통적인 asynchronous callback approach로 API composition code를 작성하면, 여러분은 빠르게 callback hell에 빠지게 된다. Code는 꼬이고, 이해하기 어렵고, 오류가 발생하기 쉽다. 더 좋은 방법은 reactive approach를 사용하여 서술 형태로 API Gateway Code를 작성하는 것이다. Scala의 Future, Java 8의 CompletableFuture, Javascript의 Promise가 reactive abstraction의 예이다. 물론, .ㅜNET Platform을 위해서 Microsoft에서 개발한 Reactive Extension(Rx or ReactiveX라고도 불린다.)도 있다. Netflix는 그들의 API Gateway에서 특별하게 사용하기 위해 JVM에 대한 RxJava를 만들었다. 물론 브라우저와 Node.js에서 모두 동작하는 Javascript를 위한 RxJS도 있다. Reactive approach를 사용하면 API Gateway code를 굉장히 효율적으로 작성할 수 있을 것이다.

Service Invocation
(서비스 호출)

Microservice기반 어플리케이션은 분산 시스템이기 때문에 inter-process communication mechanism(프로세스간 통신 매커니즘)을 사용해야만 한다. Inter-process communication에는 2가지 형태가 있다. 한가지는 비동기 메시지 기반 메커니즘을 사용하는 것이다. JMS나 AMQP와 같은 message broker를 사용하여 구현한다. 나머지는 ZEROMQ처럼, broker 없이 서비스들이 직접 통신하는 메커니즘이다. 또다른 inter-process communication 형태는 HTTP나 Thrift와 같은 비동기 메커니즘이다. 시스템은 동기, 비동기 모두 사용할 수도 있고, 각각의 형태의 여러 구현체들을 사용할 수도 있다. 따라서, API Gateway는 다양한 통신 매커니즘을 지원해야 한다.

Service Discovery
(서비스 발견)

API Gateway는 통신할 각 microservce들의 위치(IP 주소와 port)를 알고 있어야 한다. 고전적인 어플리케이션에서는 위치를 고정시켰으나, cloud기반 microservice 어플리케이션인 현대에는 심각한 문제이다. Message broker와 같은 기초적인 서비스는 OS 환경 변수를 통해 특정지을 수 있는 고정 주소를 가지고 있을 것이다. 그러나, application service의 위치를 결정하는 것은 그렇게 쉽지 않다. Application service는 동적으로 지정된 주소를 가지고 있다. 또한, service의 여러 instance들은 autoscaling과 upgrade때문에 동적으로 변한다. 따라서, 시스템에서 다른 서비스의 클라이언트와 같은 API Gateway는 시스템의 서비스를 발견하는 메커니즘을 사용해야 한다. 그것이 Server-side Discovery이건 Client-side Discovery이건 간에. 나중에 service discovery에 대해서는 더 자세히 다룰 것이다. 우선은 시스템이 Client-Side Discovery를 사용한다면 API Gateway가 모든 microservice instance들과 그 위치에 대한 데이터베이스인 Service Registry에 질의할 수 있어야 하는 것에 대해서 기록할만한 가치가 있다.

Handling Partial Failures
(부분적인 실패 처리)

API Gateway를 구현할 때 고민해야할 또다른 이슈는 부분적인 실패에 대한 문제이다. 이 이슈는 하나의 서비스가 또다른 서비스를 호출할 때, 느리게 응답하거나 사용불가능한 경우, 언제든지 모든 분산 시스템에서 발생한다. API Gateway는 downstream service(API Gateway에서 요청을 전송한 서비스)에 대해서 무한대로 기다리며 차단하지 않아야 한다. 그러나, 특정 시나리오에서 발생하는 실패와 서비스가 실패하는 경우는 어떻게 다루어야 하는가? 예를 들면 상품 상세 정보 시나리오에서 추천 서비스가 응답하지 않는다면, API Gateway는 아직 사용자가 사용중이기 때문에 client에 나머지 상품 상세 정보를 보내 주어야 한다. 추천 내용은 비어 있거나, 예를 들어 고정된 top 10 리스트 같은 내용으로 교체될 것이다. 그러나 만약 상품 정보 서비스가 응답을 하지 못하는 상황이라면 API Gateway는 client에 에러를 리턴해야 한다.

API Gateway는 캐시를 사용할 수 있도록 되어 있을 경우, 캐시된 데이터를 리턴할 수도 있다. 예를 들어 상품 가격이 수시로 변경될 경우 API Gateway는 상품 가격 서비스를 이용할 수 없을 경우, 캐시된 상품 가격 데이터를 리턴할 수 있다. 데이터는 API Gateway 자체에 캐시되거나 Redis, Memcached와 같은 외부 캐시에 저장될 수 있다. 기본 데이터나 캐시 데이터를 리턴하여 API Gateway는 시스템에서 발생한 실패가 사용자 경험에 영향을 미치지 않도록 한다.

Netflix Hystrix는 remote service를 호출하는 code를 작성하는데 믿을 수 없을 정도로 유용한 라이브러리이다. Hystrix는 특정 한계점을 넘어서는 호출을 중지시킨다. Circuit breaker pattern으로 구현되었는데, 응답하지 않는 서비스에 대해서 client가 불필요하게 기다리는 것을 멈추게 한다. 만약 서비스의 error rate가 특정 한계점을 넘어간다면, Hystrix는 circuit breaker를 작동시키고, 모든 요청들은 즉시 특정 기간동안 실패할 것이다. Hystrix는 캐시를 읽거나 기본값을 리턴하는 것과 같은 요청이 실패할 때, callback action을 정의할 수 있다. 만약 JVM을 사용한다면 Hystrix를 사용하는 것을 분명히 고려해 보라. 만약 non-JVM 환경에서 구동시키고 있다면, 동등한 라이브러리를 사용해야 한다.
받은 트랙백이 없고, 댓글이 없습니다.

댓글+트랙백 RSS :: http://www.yongbi.net/rss/response/756

Benefits and Drawbacks of an API Gateway
(API Gateway의 유익한 점과 문제점)

여러분이 기대한 대로, API Gateway를 사용하는 것은 유익한 점과 문제점이 있다. API Gateway를 사용함으로써 얻는 주요 장점은 어플리케이션의 내부 구조를 보호할 수 있다는 것이다. 클라이언트에서 특정 서비스를 호출해야 하는 것보다 더 간단하게 gateway와 통신할 수 있다. API Gateway는 클라이언트 종류에 따라 맞는 특화된 API를 제공한다. 이것은 클라이언트와 어플리케이션간의 round trip(왕복)을 줄여 준다. 그리고 클라이언트의 코드를 단순하게 한다.

API Gateway는 또한 문제점도 있다. API Gateway는 개발하고, 배포하고, 관리해야 하는 또다른 고가용성의 컴포넌트이다. 또한 API Gateway는 개발 병목지점이 되는 리스크도 안고 있다. 개발자들은 각각의 microservice의 endpoint를 노출시키기 위하여 API Gateway를 업데이트 해야 한다. 가능한한 가엽게 API Gateway를 업데이트할 수 있는 프로세스가 중요하다. 반면에 개발자들은 gateway를 업데이트하기 위해 줄서서 기다리기를 강요당할 것이다. 그러나, 이러한 문제점에도 불구하고 대다수 실제 상용 환경의 어플리케이션에서 API Gateway를 사용하는 것은 타당하다.

받은 트랙백이 없고, 댓글이 없습니다.

댓글+트랙백 RSS :: http://www.yongbi.net/rss/response/755

Summary

복잡한 어플리케이션을 만드는 것은 본질적으로 어렵다. Monolithic Architecture는 단지 간단하고 가벼운 어플리케이션에 맞다. 만약 Monolithic Architecture를 복잡한 어플리케이션에 사용한다면, 여러분은 결국 고통의 세계로 끝나게 될 것이다. Microservice Architecture Pattern은 여러 단점들에도 불구하고 복잡하고, 발전하는 어플리케이션과 도전을 성취하는데 있어 더 좋은 선택이다.

이후 블로그 포스트에서는, Microservice Architecture Pattern의 다양한 측면에서 상세하게 들어가 볼 것이다. 그리고 service discovery, service deployment options, monolithic application을 service로 리팩토링하는 전략과 같은 주제들에 대해서 논의할 것이다.

계속해서 주목해 보라....(Stay tuned...)
받은 트랙백이 없고, 댓글이 없습니다.

댓글+트랙백 RSS :: http://www.yongbi.net/rss/response/751

The Drawbacks of Microservices (Microservice의 단점)

약 30년 전, Fred Brooks가 쓴 것처럼, 획기적인 방법은 없다. 다른 모든 기술들처럼 Microservice Architecture도 단점이 있다. 한가지 단점은 이름 그 자체에 있다. Microservice라는 용어는 서비스의 크기를 과도하게 강조한다. 사실, 극도로 잘게 나누어진, 10~100줄의 코드로 이루어진 서비스 개발을 지지하는 개발자들도 있다. 작은 서비스들이 더 좋지만, 그것은 목적을 위한 수단이고, 주된 목적은 아니라는 것을 기억하는 것이 중요하다. Microservice의 목적은 어플리케이션을 빠르게 개발하고 배포 가능하도록 하기 위하여 어플리케이션을 충분히 분해하는 것이다.

Microservice의 또다른 주요 단점은 microservice 어플리케이션들이 분산환경에 있다는 사실에서 발생하는 복잡성에 있다. 개발자들은 메시지나 RPC중 하나에 기반한 inter-process communication 메커니즘을 선택하고 구현할 필요가 있다. 더욱이, 요청의 목적지가 느려지거나 이용불가능할 경우가 있기 때문에 부분적인 오류를 다루는 코드를 반드시 작성해야만 한다. 고도의 지능이 요구되는 일은 아니지만, 모듈간 language-level method/procedure 호출을 통해 서로 통신하는 monolithic application에서 훨씬 더 복잡하다.
(Inter-process communication : 프로세스들 사이에 서로 데이터를 주고 받는 통신 방법 혹은 경로)

Microservice의 또다른 도전은 분할된 데이터베이스 구조(partitioned database architecture)이다. 일반적으로 Business Transaction은 여러 개의 business entity들을 업데이트한다. 이러한 종류의 transaction들을 monolithic application에서 구현하는 것은 사소한 일이다. 왜냐하면, 하나의 데이터베이스만 있기 때문이다. 그러나 Microservice 기반 application 에서는 다른 서비스들이 소유한 여러 개의 데이터베이스를 업데이트할 필요가 있다. 분산 transaction을 사용하는 것은 CAP theorem 때문에 유일한 해결책은 아니다. 오늘날 매우 확장 가능한 많은 NoSQL 데이터베이스나 messaging broker에서 분산 transaction을 지원하지 않는다. 결국 개발자들에게 더 도전적인, 궁극적인 일관성에 기반한 접근법을 사용해야만 하는 상황에 직면하게 된다.

Microservice 어플리케이션을 테스트하는 것 또한 훨씬 더 복잡하다. 예를 들면, Spring Boot과 같은 최근의 framework으로 monolithic 웹 어플리케이션을 구동하는 테스트 클래스를 작성하고, REST API를 통해서 테스트 하는 것은 사소한 일이다. 반대로, 서비스에 대한 유사한 테스트 클래스는 테스트 대상 서비스와 의존 관계에 있는 다른 서비스들을 실행할 필요가 있다.(최소한 그러한 서비스들에 대한 stub 환경 설정이라도 해야 한다.) 한번 더 말하면, 이것이 고도의 지능을 요구하는 일은 아니지만, 테스트 수행에 대한 복잡도를 너무 적게 잡지 않는 것이 중요하다. (테스트 수행이 monolithic application 보다 복잡하다는 뜻.)

Microservice Architecture Pattern의 또 다른 주요 도전은 여러 서비스에 퍼져 있는 변경 사항들을 구현하는 것이다. 예를 들어, 서비스 A, B, C의 변경을 요구하는 스토리를 구현하는 것을 상상해 보자.서비스 A는 서비스 B에 의존하고, 서비스 B는 서비스 C에 의존한다. Monolithic application 에서는 해당 모듈들을 간단하게 변경하고, 변경 사항들을 취합하여 한번에 배포할 수 있다. 반대로, Microservice Architecture Pattern 에서는 주의하여 계획을 세우고, 뽑아낸 변경사항들에 대해 각 서비스들을 조정, 반영해야 한다. 예를 들어, 서비스 C를 업데이트할 필요가 있을 경우, 서비스 B도 따라서 업데이트 하고, 마지막으로 서비스 A도 업데이트 해야 한다. 다행스럽게도 대부분의 변경사항들은 보통 하나의 서비스에만 영향을 주고 조정이 필요한 여러 서비스를 변경하는 경우는 거의 드물다.

Microservice 기반 어플리케이션을 배포하는 것은 훨씬 더 복잡하다. Monolithic 어플리케이션은 전통적인 load balancer 뒤에 있는 동일한 서버에 간단하게 배포된다. 각각의 application instance에는 데이터베이스와 messaging broker와 같은 infrastructure service의 위치(host and ports)가 설정되어 있다. 반대로, microservice application은 일반적으로 수많은 서비스들로 이루어져 있다. 예를 들어, Hailo는 160개의 다른 서비스들로 이루어져 있고, Netflix는 Adrian Cockcroft에 따르면 600개가 넘는다. 각 서비스는 여러 개의 runtime instance를 가지고 있을 것이다. 여기에는 설정하고, 배포하고, 확장하고, 모니터링 대상이 되는 많은 이동하는 부품들이 있다. 게다가, 하나의 서비스에서 통신할 필요가 있는 다른 서비스들의 위치(host and ports)를 찾기 위한 service discovery mechanism(나중에 다른 post에서 논의할 것이다.)을 구현할 필요가 있다. 전통적인 trouble ticket 기반과 operation에 대한 수작업 접근법은 복잡도의 레벨을 변경할 수 없다. 따라서, microservice application 을 성공적으로 배포하는 것은 개발자들이 배포 방법을 더 많이 제어하고, high level 자동화가 필요하다.

자동화에 대한 한가지 접근 방법은 Cloud Foundry와 같은 기성 PaaS를 이용하는 것이다. PaaS는 개발자들이 microservice를 배포하고 관리하는 데 쉬운 방법을 제공한다. PaaS는 IT 리소스를 어렵게 구하고 설정하는 것에 대한 우려를 불식시킨다. 동시에, PaaS를 설정하는 시스템과 네트워크 전문가들은 best practice와 회사 정책에 따른 법규 준수를 보장할 수 있다. Microservice 배포를 자동화하는 또다른 방법은 근본적으로 여러분 자신의 PaaS를 개발하는 것이다. 한가지 전형적인 시작 포인트는 Docker와 같은 기술과 함께 Kubernetes와 같은 클러스터링 솔루션을 이용하는 것이다. 이 시리즈의 뒤쪽에서, Microservice level에서 caching, access control, API metering, monitoring을 쉽게 다루는 NGINX와 같은 software 기반 어플리케이션 배포 방법들이 이 문제를 해결하는데 어떤 도움을 줄 수 있는지를 보여줄 것이다.

받은 트랙백이 없고, 댓글이 없습니다.

댓글+트랙백 RSS :: http://www.yongbi.net/rss/response/750

Microservices-Tackling the Complexity
   (Microservice - 복잡함에 태클을 걸다)

Amazon, eBay, Netflix 같은 많은 조직들에서 Microservice Architecture Pattern이라고 알려져 있는 기술을 채택하여 이러한 문제를 해결하고 있다. Microservice Architecture 하나의 괴물같은 monolithic application 만드는 대신에, 작고 서로 연결되어 있는 서비스들의 집합으로 application 나누는 것이다.


일반적으로 서비스는 order management(주문관리), customer management(고객관리), 등과 같은 별개의 특징이나 기능 집합으로 구현되어 있다. 각각의 microservice 자체에 다양한 어댑터에 대한 비즈니스 로직을 가진 6각형의 아키텍처를 가지는 mini-application이다. 어떤 microservice 다른 microservice application client 의해서 호출되는 API 제공하고, 다른 microservice Wen UI 구현할 수도 있다.


런타임시에는 각각의 instance 클라우드 VM이나 Docker container 상에 실행되기도 한다.


예를 들면, 앞서 기술된 시스템을 분해하면, 다음과 같은 다이어그램으로 표현할 있다.


사용자 삽입 이미지


Application 개별 기능은 각각의 microservice 구현되어 있다. 더욱이 web application 간단한 web application 집합으로 나누어져 있다. (택시 호출 서비스 예제에서 보면, 명의 운전 기사가 명의 승객과 매칭되는 경우). 이것은 특정 user, device, 혹은 특별한 use case별로 개별 경험을 쉽게 배포하게 한다.


backend service REST API 제공하고, 대부분의 service들은 다른 service 제공하는 API 사용한다. 예를 들어, Driver Management(기사 관리) 잠재적 이동에 대해 활동 가능한 운전 기사에게 알려주는데 Notification Server 사용한다. UI service들은 web page들을 렌더링하기 위해 다른 서비스들을 호출한다. 서비스들은 메시지 기반의 communication async방식을 사용한다. 서비스간의 communication 대해서는 추가로 나중에 자세히 다룰 것이다.


몇몇 REST API 기사나 승객에 의해 사용되는 mobile app에서 이용한다. 그러나 이러한 app들은 backend service 직접 접속할 없다. 대신에 communication API Gateway 알려진 중재자를 통해 가능하게 된다. API Gateway 로드밸런싱, caching, access control, API metering, monitoring 같은 부분들을 처리해야 한다. 이러한 부분들은 nignx 사용하여 효과적으로 구현할 있다.


사용자 삽입 이미지


Microservice architecture pattern scalability(확장성) 3D Model 대한 최고의 책인 "The Art of Scalability" 나오는 Scale Cube Y Scaling 대응된다. 다른 2개의 Scaling 축은 load balancer 뒤에서 실행중인 여러 개의 동일한 application 복사본으로 구성된  X Scaling 요청의 속성(예를 들면, row primary key 고객의 identity) 특정 서버에 대한 요청으로 route하는데 사용되는 Z Scaling(혹은 data partitioning) 있다.


Application들은 일반적으로 3가지 Scaling 타입을 함께 사용한다. Y Scaling 섹션 첫번째 그림에서 보여주는 대로 application microservice로 분해한다. Runtime 시점에 X Scaling load balancer 뒤에서 처리량과 가용성을 위해 서비스에 대해 여러 개의 instance 실행한다. 어떤 application들은 service partition하기 위해 Z Scaling 사용하기도 한다.


다음 다이어그램은 Trip Management 서비스가 Amazon EC2 서버 상에 Docker 어떻게 배포되는지를 보여준다.


사용자 삽입 이미지


Runtime시에 Trip Management 서비스는 여러 개의 instance 구성되어 있다. 서비스 instance Docker container 제공된다. 가용성을 높이기 위해서 docker container들은 여러 개의 cloud VM에서 돌아간다. Service instance 앞단에는 여러 instance 요청을 분산하는 nginx 같은 load balancer가 있다. Load balancer caching, access control, API metering, monitoring 같은 여러 가지 관심 사항들을 취급할 있어야 한다.


Microservice Architecture Pattern 특히 application database 사이의 관계에 중요한 영향을 준다. 서로 다른 service 하나의 database schema 공유하는 것보다는 각각의 서비스가 독자적인 database schema 갖는다. 다른 한편으로 이러한 접근은 Enterprise-Data Model 관점에서는 이상하다. 또한, 어떤 데이터들은 종종 중복되기도 한다. 그러나 서비스별 database schema 갖는 것은 microservice 통해 혜택을 보기 원한다면, 본질적인 부분이다. 왜냐하면, microservice 느슨한 연결(loose coupling) 보장하기 때문이다. 다음 다이어그램은 예제로 제시된 application 대한 database architecture 보여주고 있다.


사용자 삽입 이미지

각각의 서비스는 자체적으로 데이터베이스를 가지고 있다. 게다가, 서비스별로 소위 polyglot persistence architecture(상황에 맞게 최적화된 구조로 데이터를 구분하여 저장하는 아키텍처)라고 불리는 가장 최적의 데이터베이스 타입을 사용할 있다.


예를 들어, 잠재적인 승객에게 가장 가까운 운전 기사들을 찾아야 하는 Driver Management(기사 관리) geo-query(지리기반 질의) 지원하는 데이터베이스를 사용해야만 한다. 표면적으로는 MSA SOA 유사하다. 두가지 모두 서비스들의 집합으로 구성된 아키텍처이다. 하지만, MSA WS 표준과 ESB 없는 SOA라고 생각하면 된다.


Microservice 기반 application WS 표준보다 굉장히 단순하고, REST 같은 가벼운 프로토콜을 사용한다. 또한 ESB 사용을 지양하고, microservice 자체적으로 ESB 유사한 기능을 구현한다. Microservice Architecture Pattern 정규 스키마(canonical schema) 같은 SOA 다른 부분도 거부한다.

받은 트랙백이 없고, 댓글이 없습니다.

댓글+트랙백 RSS :: http://www.yongbi.net/rss/response/747