API Gateway Pattern에는 API Gateway가 없다.

API Gateway Pattern에는 API Gateway가 없다.

Microservices Architecture에 관해 이야기하면 왠지 API Gateway를 꼭 사용해야 할 것 같은 느낌이 든다. 과연 그럴까?
왜 함부로 API Gateway를 사용하면 안 되는지, 그래도 사용해야 한다면 언제 사용할지에 대해 다뤄보려고 한다.

우아한형제들의 서버개발그룹장분이 잘 설명해주셔서, 두고두고 보려고 기록해두는 글이다.

출처 : https://www.youtube.com/watch?v=P2nM0_YptOA

다룰 내용

  • MSA에서 필수적인 API Gateway Pattern이 API Gateway Framework와 무관한 이유
  • API Gateway Pattern 이란?
  • MSA의 API 애플리케이션의 역할 구분
  • 하나씩 알아보는 API Gateway Framework을 사용하면 안되는 이유들
  • 그래도 API Gateway Framework를 사용해도 되는 경우들

API Gateway Pattern 이란?

API Gateway Pattern은 어디 나오나?

마이크로 서비스 패턴

크리스 리처드슨은 본인이 생각한 MSA의 여러가지 패턴을 마이크로 서비스 패턴이라는 책으로 정리하였다.
그 외에도 마이크로소프트 홈페이지에서도 API Gateway 패턴을 다루고 있다. API 게이트의 패턴은 여러 마이크로 서비스로 나뉜 것을 하나로 묶어 클라이언트가 호출하게 해주는 것으로 MSA에서는 필수적인 요소이다. 그렇다면 API 게이트웨이 패턴의 정의를 그림 한장으로 나타내면 무엇일까?

API Gateway Framework 기반

모바일 앱이나 웹브라우저 혹은 외부 애플리케이션 서버 등 외부의 클라이언트가 API 게이트웨이를 통해서 내부망에 있는 api를 그대로 호출한다.
이때, API Gateway가 인증을 하고 클라이언트가 호출 가능한 api들만 공개함으로써 안전하게 내부 서비스를 보호해주게 된다고 생각할것이다.
외부 개발자는 내부망의 모든 api 호출 엔드포인트를 알 필요가 없기 때문에 API 게이트웨이 엔드포인트 하나만 확인하고 편하게 호출할 수 있는 좋은 패턴이라고 생각될 것이다.

위의 구조는 API Gateway의 프레임워크를 통해 설정 정보만으로도 구성이 가능하다.
안타깝게도 이것은 API Gateway 패턴이 전혀 아니다.
그리고 계속 생각할것이다라고 말한 이유는 사실은 그렇지 못하기 때문이다.

출처 : 마이크로서비스 패턴 책, 333쪽

Microservice.io 혹은 마이크로서비스 패턴 책에 나오는 API Gateway 패턴의 정의는 위의 도식과 같다.
이 API Gateway 패턴은 클라이언트의 특정 비즈니스 요청을 받아주는 서버 애플리케이션을 개발자가 직접 작성하고 내부 api들을 조합해서 호출한 뒤 응답을 클라이언트에게 필요한 것만 정리해서 내보내는 방식이다.

앞의 것은 설정만으로도 가능하고, 뒤의 실제 API Gateway 패턴은 개발자가 명백하게 코드로 작성해야만 하는 것이다.
코드 작성은 쉽다. 자바 개발자라면 흔한 웹프레임워크인 스프링 웹 MVC나 Webflux를 사용하면 된다.
다만 리액티브한 웹플럭스를 권한다.

1차 결론

  • 외부에 API를 제공하기 위한 API Gateway Pattern은 Spring Cloud Gateway나 Netflix Zuul 같은 API Gateway Framework를 사용하는 것과는 무관
  • API Gateway Pattern은 클라이언트의 요청을 받아서 내부 마이크로서비스를 호출하는 로직을 직접 작성하고 응답 내용도 취사 선택하여 필요한 것만 내보내느 것
  • 인증과 권한 기능을 붙였는지 여부와 무관하게 외부에 API를 제공해줄 용도로 API Gateway Framework를 사용한 요청/응답 Routing은 하면 안됨
  • 특히 규모가 작다면 실제 MSA를 하면서 API Gateway Framework를 사용할 일은 사실 많지 않음

API Gateway Framework

Spring Cloud Gateway, Netflix Zuul, AWS API Gateway 등을 이 글에서 부르는 용어

Gateway Routing Pattern

MS에서 정의한 API Gateway Framework를 통한 단순 요청/응답 라우팅에 관한 패턴

BFF - Backend For Frontend

API Gateway Pattern과 유사하게 직접 구현하는 로직을 작성하는 방법과 API Gateway 애플리케이션을 클라이언트 기기 단위로 구분하고 소유권을 정하는 방식 조합

API Gateway 라는 단어의 의미는 현재 매우 심각하게 오염되어 있다. 이 단어를 듣는 순간 대부분 사람들이 떠올리는 그림은 위 두 그림 중 하나일 텐데 아마도 대부분 사람들은 첫 번째 보여 드린 요청응답을 단순 라우팅하는 그림을 떠올렸을 것이다. 바로 이 점 때문에 의사소통과 실제 구현에서 다양한 문제들이 발생하고 있다. 그래서 필자는 우리가 보통 API 게이트웨이라고 부르는 것들 즉 스프링클라우드 게이트의 넷플릭스 Zuul과 같은 것을 지금부터 API Gateway Framework 라고 부르겠다.

그리고 마이크로소프트 홈페이지에서는 이런 API Gateway Framework를 통한 단순 요청응답으로 구성하는 것을 게이트웨이 라우팅 패턴이라고 불렀다. 그래서 필자도 앞으로 Gateway Routing Pattern이라는 용어로 API Gateway Framework를 사용하는 단순 라우팅을 지칭하도록 하겠다. 왜냐하면 최근 API Gateway Framework는 단순 라우팅뿐만 아니라 코딩을 통해 API Gateway Pattern에서 정의한대로의 역할도 수행할 수 있기 때문이다. API Gateway Framework로도 API Gateway Pattern의 구현이 가능하지만, 필자는 권하지 않는다.

참고로 API Gateway Pattern이 API Gateway라는 용어의 경우 일부 다른 사람들은 엣지 마이크로 서비스 클라이언트 어댑터 등의 다른 용어로 부르는 것도 많이 보인다.

최근에는 BFF라는 용어도 대세가 되어가는 것 같다.

MSA 자체의 역사가 길지 않다보니 많은 것들이 정리되지 못하고 다양한 오해를 일으키고 있어 보인다. 사실상 필자가 하고 싶은 말의 핵심은 여기서 끝이다. 위 두 글미을 보는 순간 딱 하고 그래 그렇지 않고 뭔가 떠오른 사람 혹은 이미 알고 있는 사람이라면 더 이상 이 글을 보지 않아도 좋을거 같다.

하지만 어쨋든 왜 API Gateway Pattern이라는게 어째서 단순히 API Gateway Framework를 통한 단순 라우팅을 하면 안되는 것인지 혹은 왜 비록 올바른 API Gateway의 구현이 가능하다 하더라도 필자가 API Gateway Framework의 사용을 권장하지 않는지 살펴보도록 하겠다.

Monolithic Architecture : 기본으로 돌아가 모놀리식 아키텍처를 살펴보자.

Spring Framework WebMVC 기반 Monolithic

일반적인 스프링 웹 MVC 기반 Monolithic 애플리케이션은 이 그림과 비슷한 형태를 띤다.애플리케이션은 크게 두 가지 계층으로 나눈다.

하나는 실제 비즈니스 로직을 처리하는 비즈니스 계층이다. 여기서 저장소에 접근하고 도메인 로직을 수행한다. 서비스 계층이라고 부르기도 한다.

그리고 프레젠테이션 계층이 외부 클라이언트의 요청을 받아서 비즈니스 계층을 호출하고 그 결과를 클라이언트가 사용하기 적합하게 변환해서 응답하게 된다.

프레젠테이션 계층에는 필터, 인터셉터가 있다. 비즈니스 계층에는 AOP가 있다. 이 둘은 역할이 비슷하다. 필터 혹은 인터셉터는 여러 컨트롤러의 공통 적용된 로직을 실행하고 컨트롤러 코드를 호출한다. AOP도 마찬가지인데 AOP는 보통 서비스나 그 외의 비즈니스 로직이 공통으로 적용할 로직을 수행한다. 둘이 하는 일을 횡단 관심사 처리라고 한다. 영어로는 Cross Cutting Concerns라고 한다.

프레젠테이션 계층에는 Facade라는 것도 보이는데 클라이언트의 요청이 하나의 비즈니스 로직이 아니라 여러 비즈니스 로직의 조합일 경우 작성한다. 이 Facade라는 용어를 모르고있더라도 혹은 별도의 클래스를 분리하지 않고 컨트롤러에 직접 Facade 코드를 작성하더라도 어찌됐든 여러분은 자기도 모르는 사이에 Facade를 작성하고 있을 것이다.
계층형 아키텍처 혹은 계층형이 아니더라도 소프트웨어 개발에서 가장 기본 중 하나는 하위 모듈이 상위 모듈을 호출할 수 없고 하위 계층이 상위 계층을 호출할 수 없다는 것이다. 여기서 하위 계층은 비즈니스 계층이고 상위 계층은 프레젠테이션 게층이다. 따라서 비즈니스 계층은 절대로 프레젠테이션 계층을 호출하면 안된다. 쉽게 말해 서비스 클래스는 컨트롤러 클래스를 호출해서는 안된다.

MSA를 이런 계층형 아키텍처로 매핑하면 어떤 모양이 될까?

MSA와 계층형 아키텍처

우리가 보통 마이크로서비스라고 부르는 그것들은 비즈니스 계층에 속한다. 그래서 마이크로 서비스 아키텍처라고 부르는 것 같다.

그리고 API Gateway Framework가 아닌 API Gateway는 프레젠테이션 계층에 속하게 된다. 몇몇 분들은 아닌데 내가 만든 마이크로서비스는 프레젠테이션 계층인데라고 하는 사람이 있을 수 있는데 이것은 조금 이따가 알아보도록 하곘다.

혹시 이 그림을 보는 순간 어째서 API Gateway Framework로 라우팅하는 것이 문제가 되는지 곧바로 파악이 되는가?
여기서 API Gateway를 API Gateway Framework를 통한 라우팅 기반으로 변경하면 어떤 형태가 되는 걸까?

API Gateway Framework으로 라우팅만 하면...

바로 이렇게 컨트롤러 코드와 Facade 코드가 존재하지 않고 횡단 관심사만 처리하는 필터/인터셉터만 남은 프레젠테이션 계층이 되어버리는 것이다.

컨트롤러와 Facade 코드가 존재하지 않는 프레젠테이션 계층은 아주 심각한 문제들을 일으킨다.

2차 결론

  • API Gateway Framework를 통해 단순 Gateway Routing Pattern으로 내부 서비스 API를 외부로 노출시키는 경우에는 필터/인터셉터 역할만 하기 때문에 컨트롤러/Facade가 존재하지 않는 상태가 되어 많은 문제를 일으킴
  • 프레젠테이션 계층 구성은 꼭 컨트롤러와 퍼사드 코드를 직접 개발자가 작성하는 API Gateway Pattern을 따라야 함.
  • 다시 말하면 비즈니스 계층 마이크로서비스 API들을 프레젠테이션 계층으로 변환하는 용도로 API Gateway Framework를 사용해서는 안된다.
  • 반대로 Filter/Interceptor/AOP 같은 횡단 관심사를 처리하는 데는 API Gateway Framework를 사용할 수 있다는 의미 - 추천하지는 않음

필자는 사실 API Gateway Framework를 사용할 일은 정말 드물다고 생각한다. 그것이 비록 횡단 관심사 처리 일지라도 말이다.
사실상 이글의 핵심은 여기서 다 나왔다고 봐도 된다. 그래도 도대체 왜 컨트롤러와 퍼사드 코드를 직접 작성하지 않으면 문제가 되는지 어째서 횡단 관심사 처리에도 API Gateway Framework를 사용하지 말라는 것인지 궁금할 것이다.

API Gateway Framework Gateway Routing 방식의 문제점

  • 보안 취약성
  • Client 개발자 혹은 특정 Micro Service에게 Business 로직 전가
  • Business 계층과 Client 간의 강결합과 그로인한 보안 취약성
  • 성능 저하
  • 내부 Service들 간의 protocol 자유도 하락
  • 계층형 아키텍처의 일반적인 원칙 위반 사례
  • 횡단 관심사 처리 관점에서도 사용하지 않아야 하는 이유
    • Single Point Of Failure
    • 성능 저하
    • 관리 부담
    • 문서화

AGF문제점 : 보안 취약성

  • 인증 : 사용자의 로그인 여부 - 누구세요?
  • 권한 : 당신은 이것을 사용할 수 있고 저것은 사용할 수 없습니다. “이것” 이란?
    • 특정 API
    • 해당 API가 처리하는 객체

API Gateway Framework를 사용하면 보안이 좋아진다는 착각이 많이 있다. 하지만 사실이 아니다.
인증을 한다는 것과 특정 API 호출 권한을 제어한다는 것인 보안을 강화하는 것은 아니다. 그것은 프레젠테이션 계층이 당연히 해야할 일이다. 인증은 사용자의 로그인 여부를 체크해서 누구인지 확인한다. 여기서 문제는 권한에 대해 많이들 오해한다는 점이다.
권한에는 특정 api를 호출해도 된다라는게 있다. 그리고 그 특정 api가 처리하는 객체에 대한 접근 가능 여부도 권한에 들어간다.
Gateway Routing 방식으로 사용하면 위의 빨간색으로 된 객체 관련 권한 처리를 누락하게 된다.

  • GET /users/{userId} : 허용
  • PUT /users/{userId} : 허용
  • POST /users : 금지

Login 사용자 1번이라면

  • GET /users/1 : 허용
  • PUT /users/1 : 허용
  • POST /users : 금지
  • GET /users/2 : 허용
  • GET /users/3 : 허용
  • GET /users/... : 허용
  • PUT /users/2 : 허용
  • PUT /users/3 : 허용
  • PUT /users/... : 허용

단순한 예로 로그인 사용자에게 API Gateway Framework에서 GET /users/id와 PUT은 허용하고 POST는 금지했다고 해보자.
보안이 강화된 것처럼 보인다. 하지만 로그인 사용자 1번은 해당 api에서 1번 사용자의 개체만을 다루어야 한다. 그런데 2번 3번 객체를 다루는 것은 막지 못하고 있다.
권한을 지정할 때 http 메소드와 url 패턴이 일치하면 허용했지 패턴에 들어가 있는 값에 대해서는 확인하지 않았기 때문이다. 다른사용자의 데이터를 조회하는 것뿐만 아니라 마음대로 수정까지 가능하다. 심각한 보안 위협이다.

이 문제를 해결하는 방법은 직접 컨트롤러 코드를 작성하는 수밖에 없다.
지금 예제는 간단하다. 로그인 유저 아이디는 세션 역할의 쿠키에 저장되어 있고 이를 프레임워크가 알고 있으니까 왠지 단순하게 유저 id값과 로그인 사용자의 유저 아이디를 비교해서 호출하지 못하게 필터를 구성하면 될 것 같다. 하지만 문제가 해결된 것은 아니다.

AFG문제점 : 보안 취약성에 이어서...

오더나 리뷰처럼 이와 같이 오더 id와의 관계를 알 수 없는 수많은 api 호출들이 존재하기 때문이다. 이런 경우에도 로그인 사용자가 명백히 소유한 주문이 아니면 조회나 수정이 불가능해야 한다. 그러면 아래처럼 모든 api 호출에 대해 소유 관계를 넣으면 일부 문제는 해소해준다. 특정 프레젠테이션 계층에서는 이렇게 하면 성능도 좋아진다.
하지만 사실 아주 많은 경우에 저렇게 소유 관계만으로 객체를 조회할 수 없다. 멀리 갈 것도 없이 오더 마이크로 서비스 입장에서는 본인들이 가지고 있지도 않은 유저에 대한 정보를 API url에 넣는 것 자체가 부담일 것이고 일반적인 비즈니스 로직에서는 오더 아이디만으로 조회해야 하는 경우가 태반일텐데 그렇제 못해서 오는 불편도 상당하다. 그리고 그런 것을 넘어서 가장 중요하게 이 방식이 안 되는 이유가 있다.

많은 착각 중에 하나가 프레젠테이션 계층이 하나일 거라는 것이다. 대부분의 엔터프라이즈 애플리케이션은 프레젠테이션 계층이 여러 개이다. 요즘 많이 회자되고 있는 어떤 아키텍처가 떠오를 것이다. Admin은 모든 사용자의 주문 정보에 접근이 가능해야 한다. 가가 업주는 본인의 가게에서 일어난 주문에 대해서는 그 사용자가 누구이든 조회할 수 있어야 한다. 필자는 Batch Job이나 이벤트 컨슈머도 프레젠테이션 계층으로 보는데 이것들은 시스템으로서 무제한의 데이터 접근권을 가진 프레젠테이션 계층에 속한다.

또한 타사의 서버 애플리케이션 호출 지점도 프레젠테이션 계층이다. 이 모든 경우를 미세하게 API Gateway Framework로 제어하는 것은 필자가 보기엔 불가능하다. 따라서 비즈니스 계층은 프레젠테이션 계층의 접근자가 누구인지 구분하지 않고 요청을 받아주고 프레젠테이션 계층에서 각자 코딩을 통해 권한을 미세하게 조정해야 한다. 아마도 비즈니스 계층 자체에 저 모든 처리르 넣고 API Gateway Framework를 붙이려는 욕구가 생길 수 있는데 비즈니스 계층 서비스가 100개이고 처음에는 두 개 정도의 프리젠테이션 계층으로 시작했는데 나중에 두 개의 또 다른 프리젠테이션 계층이 더 추가됐다고 상상해 보길 바란다… 당장 100개는 아니더라도 수많은 마이크로서비스에 자기들은 관심도 없는 프리젠테이션 계층의 권한 로직을 추가해야 하는 부담을 지게된다.

과연 또 다른 프리젠테이션 계층이 추가될 것 같은가? 지금 당장 생각나는 것은 배달원 프리젠테이션 계층 고객센터 직원 프리젠테이션 계층 고객사 직원 계층이 생각난다. 또 얼마나 많이 추가될지 상상도 안된다. 애초에 저런 권한 로직을 비즈니스 계층에 넣는 것 자체가 비즈니스 계층과 프리젠테이션 계층을 모호하게 만드는 잘못된 행동으로 보인다.

AGF문제점 : 보안 취약성 IDOR

IDOR 취약점

IDOR : Insecure Direct Object Reference

  • 그 중에서도 “수평적 권한상승”

  • 개발자가 꼭 알아야 할 애플리케이션 보안 : 입문부터 놓치면 안될 트렌드까지?! (8월 우아한테크세미나 - 권현준)

수평적 권한상승

쉽게 말해, 동일한 권한을 가진 다른 사용자의 객체에 접근할 수 있을때를 수평적 권한상승이라고 함

수직적 권한상승

본인이 지닌 권한을 넘어서는 기능을 수행할 수 있을때를 수직적 권한상승이라 함

필자는 이 취약점이 최근에 급부상한 이유가 마이크로 서비스 아키텍처가 급부상하면서 함께 증가한 API Gateway Framework 사용 때문이라고 추측하고 있다.
방금은 수평적 권한 획득의 예였고 잘못 설계된 마이크로 서비스 아키텍처에는 수직적 권한 상승 문제도 마찬가지로 발생한다. 그 예는 추후에 포스팅 하도록 하겠다.

AGF 문제점 : 잘못된 로직 구현 전가

정말로 어떻게 해서 절대로 보안 문제가 없는 경우라고 가정해도 단순 라우팅을 하게되면 Facade가 필요한 경우에 엉뚱한 곳에 로직을 전가하게 된다.

  • 클라이언트(Mobile App, Web Browser)가 직접 스스로 비즈니스 계층의 로직을 다양하게 조합해서 호출하게 됨
  • 혹은 반대로 Order Service가 엉뚱하게 Product Service를 호출해서 클라이언트에 필요한 정보를 조합해 내려주는 것처럼 본인의 비즈니스가 아닌 것에 대해 구현하고 의존하게 됨

이게 뭐가 문제일까?

AFG 문제점 : Client에 구현 전가

  • 일단 클라이언트 개발자가 UI 처리에 집중하지 못하게 됨
  • 비즈니스 로직은 서버개발자와 클라이언트 개발자 둘 다 밀도 높게 파악해야 함
  • 비즈니스 로직 하나하나는 무슨 수르 ㄹ써서 든 보안 요구를 충족할지라도 그것들을 자유롭게 조합할 권한을 해커에게 내준 것이라서 그 조합이 어떤 문제를 일으킬지 확신할 수 없음
  • 버그가 존재할 경우 Mobile App은 각종 앱스토어 인증 절차에 걸리는 시간과 사용자들이 자발적으로 앱을 업데이트 할 때 까지의 시간동안 버그 해결이 불가능해짐

클라이언트 개발자에게 전가하기가 불가능 경우가 있거나 혹은 위에서 말한 문제들 떄문에 이 Facade 구현을 서버측에 전가하면 퍼사드의 역할을 결국은 누가 됐든 특정 마이크로서비스에서 처리해야한다. 그때도 문제가 심각해진다.

AFG 문제점 : 각 마이크로서비스에 전가

  • 특정 서비스 개발자들은 알지도 못하는 로직 구현 책임을 맡게되고
  • 해당 서비스는 본 서비스가 아닌 다른 역할을 맡음으로써 불필요하게 복잡도 증가와 타 서비스들과의 결합도 증가
  • 본 역할도 아닌 타 API Network 호출 증가로 인해 정작 본 서비스의 처리에 장애 유발 요인 증가
    • 특정 프리젠테이션 계층 API Gateway에서 문제가 생겼다면 해당 API Gateway만 문제가 되지만
    • 비즈니스 계층 Microservice에서 장애가 발생하면 이를 호출하는 다른 모든 계층에서 문제가 될 수 있음 - 장애 여파 훨씬 커지게 됨

이런식으로 전혀 엉뚱한 역할을 전가받은 서비스의 개발자들의 시선은 복잡해 개발만족도는 갈수록 떨어지게 된다. 그리고 애초에 마이크로 서비스로 나눈 이유 자체에도 반하게 되는 결정이 된다. 마이크로 서비스 패턴 책을 보면 API Gateway Pattern을 구현하는 방법을 스프링 웹 MVC, Webflux처럼 직접 웹플럭스처럼 직접 웹프레임워크로 개발하기와 스프링클라우드 게이트웨이처럼 라우팅과 직접 구현을 동시에 지원하는 API Gateway Framework를 사용하는 방법을 추천하고 있다. 실제 예제로도 스프링클라우드 게이트웨이를 사용한다. 즉 일부는 단순 라우팅, 나머지는 직접 구현하는 것을 섞어서 하고 있다.

하지만 필자는 앞서 API Gateway Framework를 통해 비록 API Gateway Pattern이 구현가능하고 일부 단순한 api는 간편하게 라우팅 처리를 할 수 있다 하더라도 그렇게 해서는 안된다고 말했다.
이제 그 이유에 대해 다뤄보겠다.

AFG 문제점 : Client / Business 계층간 강결합

이제부터 Business 계층 개발자는 항상 Client의 변경사항을 주시해야 한다.

1
2
3
4
5
6
7
{
"userId" : 1,
"name" : "강백호",
"address" : "서울시 동작구 ...",
"phone" : "010-1111-2222",
"ssn" : "221212-1234567"
}
  • 배달원 앱용 Presentation AFG에서 User Microservice의 /users/{userId} API를 단순 라우팅 했고 그 응답 객체도 단순 반환했는데
  • 나중에 User Microservice의 개발자가 별 생각없이 /users/{userId}의 응답에 고객의 전화번호와 주민번호를 추가한다면? -> 배달원 앱을 통해 고객의 전화번호와 주민등록번호가 그대로 노출
  • 이를 막으려면 User Microservice 측에서는 모든 Presentation 계층별로 서로 다른 사용자 정보 조회 API를 만드는 방법 밖에 없게 됨
    • Business 계층이 Presentation 계층에 의해서 계속 변화하게 됨

단순 요청/응답 라우팅은 어떠한 경우에도 사용하지 말고 항상 응답 내용을 프리젠테이션 게층에서 Client에 필요한 것만 정제해서 내보내기

배달앱에서는 어차피 새로 추가된 데이터를 보여주지 않을테니까 괜찮다는 식의 안심은 금물인 것은 당연히 알 것이다. 보다시피 게이트웨이 라우팅 패턴이 스며드는 순간 비즈니스 계층은 프리젠테이션 계층의 속박에서 벗어날 길이 없게 된다.

AGF 문제점 : client 성능 저하

Client는 느리다

  • 여러 api 호출을 조합해야 하므로 network 호출이 여러번 일어나게 되고
  • api 호출 결과가 불필요한 데이터까지 포함하여 과하게 크거나
  • 필요한 데이터가 없어서 추가 api 호출을 하게 됨
  • API Gateway Pattern을 Non Blocking IO / Reactive 하게 구현하여 성능 향상 추천 (Spring WebFlux 등)

출처 : https://netflixtechblog.com/optimizing-the-netflix-api-5c9ac715cf19

이 그림은 넷플릭스 블로그에 나온 API 게이트웨이 예이다. 여기서 넷플릭스 api가 API GW라고 보면 되고 API GW의 서버가 다른 비즈니스 계층 서비스를 패러럴하게 호출하고 있다. 클라이언트는 단 한 번만 호출하고 있다.

GraphQL로 이 문제를 해소 가능하지만, 비즈니스 계층 Micfoservice에 GraphQL을 구축하고 이를 그대로 프리젠테이션 계층까지 노출하면 앞서 말했던 보안 문제들이 그대로 발생함. GraphQL도 API Gateway Pattern에 따라 프리젠테이션 계층 서버 애플리케이션으로 적절한 보안 처리를 해서 별도 구축

AGF 문제점 : 내부 서비스의 프로토콜 제약

  • API Gateway Framework로 프리젠테이션 계층을 구현한다는 것은 곧 내부 비즈니스 계층 서비스가 모두 HTTP API(REST?)로 고정된다는 의미
  • 내부 비즈니스 계층을 한 번 밖으로 노출하면 프로토콜 변경은 어려워짐
  • 내부적으로 성능 향상과 다양한 요구 사항만족을 위해 gRPC, Message Queue, HTTP API, 기타 등등을 사용할 수 있는 자유도를 포기하지 말기

API Gateway
(출처 : https://microservices.io/patterns/apigateway.html)

계층형 아키텍처의 일반적인 원칙 무시 사례

계층형 아키텍처의 일반적인 원칙을 무시한 사례 중 마이크로 서비스를 나눌 때 비즈니스 계층으로 나눈게 아니라 애초에 프리젠테이션 계층으로 만들어 버리는 사례이다.
예를 들어 주문 마이크로 서비스를 만드는데 애초에 앱클라이언트의 요청을 받게 만들어 버리는 것이다.
인증도 붙이고 권한처리도 한다. 그리고 내부적으로 비즈니스 계층에서 비즈니스 로직을 처리하고 저장소 처리까지 합한다.
사실 여기는까지는 괜찮다. 다만 많은 경우에 바로 이런 도식과 같은 형태를 띄게 버리는 것이다.

프리젠테이션 계층 서비스를 직접 구현

프리젠테이션 계층 api가 다른 프리젠테이션 계층 api를 호출하고 비즈니스 계층 api가 없다보니 프리젠테이션은 계층의 비즈니스 처리용 api를 만들어서 호출해버리는 것이다.
이는 모놀리식 아키텍처에서 컨트롤러가 컨트롤러를 호출하고 서비스가 컨트롤러를 호출하는 형국이다.
비즈니스 계층에 속하는 상품 서비스가 주문 프리젠테이션 계층을 호출하려면 필연적으로 주문 프리젠테이션 계층에서 인증을 풀어주거나 단순화한 형태의 api를 제공해줘야 한다.
이는 IDOR의 수직적 권한 상승에 취약해지는 결과를 낳는다.
Private 망의 상품 서비스가 Public 망의 api를 호출하려면 외부망으로 접속이 연결되면서 연결 지연이 발생한다.
웹 방화벽에 의해 Private 망의 모든 호출이 단일 ip에서 오는 DDOS 공격으로 간주되어 차단될 수도 있다.

수직적 권한 상승에 취약해진다는것은 잘못하면 해커가 무제한의 권한을 가진 api를 알아낼 수 있다는 의미이다.
계층형 아키텍처의 기본을 어김으로써 나타나는 문제들을 차치하고서라도 보안 문제와 네트워크 인프라적으로도 심각한 문제가 발생하는 것을 볼 수 있다.

프리젠테이션 계층 서비스를 직접 구현

하나의 메소드, 하나의 역할만 하듯 하나의 마이크로 서비스도 하나의 계층 역할만 해야한다.
의존 관계는 항상 프리젠테이션 계층에서 비즈니스 계층으로 흐르거나 비즈니스 계층간에만 이루어져야 한다.
비즈니스 계층간의 호출에 있어서도 Circular 호출이 일어나서는 안 됨 (A -> B -> A)

마이크로 서비스로 분할된 애플리케이션들간의 호출에 있어서도 우리가 보편적으로 코드를 짤 때 지켜야 하는 규칙을 철저히 지켜야한다.

AGF를 횡단 관심사에서도 사용하지 말기

진짜 진짜 필요한게 아니라면…

  • Single Point Of Failure(단일 장애 지점)가 된다.
  • 불필요하게 서버 관리 부담이 늘어나고 비용도 증가
  • Client가 하나의 end point만 바라본다고 해서 좋아질 것은 크게 없음
    • API Gateway pattern을 구현하게 되면 실제 client 개발자가 바라보는 API endpoint 개수는 현저하게 줄어들게 됨.
    • ktNaviService.메소드수천개() : 정말 좋은가?
    • 진짜 중요한 것은 필요한 API를 빠르게 찾아볼 수 있게 문서들을 잘 모아두기

API Gateway Framework를 사용할 만한 경우

사실 대부분의 규모의 서비스에서 API Gateway Framework가 별로 필요 없다.

Zuul in Netflix's Cloud Architecture
출처 : Announcing Zuul: Edge Service in the Cloud

이 그림은 넷플릭스가 2014년 Zuul API Gateway Framework를 발표한 내용을 가져온것이다.
넷플릭스는 여기서 프리젠테이션 계층 API Gateway에 해당하는 부분을 클라이언트 어댑터라고 부르고 있으며 코드를 직접 짜서 구현하고 있다.
넷플릭스는 Zuul을 비즈니스 계층 api를 프리젠테이션 계층으로 노출하는 용도로 사용한 것이 아니라 명백하게 각각의 프리젠테이션 계층에 대해서 횡단 관심사 처리를 위해 사용한 것이다.
여기서 다양한 횡단 관심사를 보여주는데 흔히 생각하듯 인증 정적응답 처리 Canary testing, Stress testing, 동적 라우티을 위해서 사용하고 있다.
만들 Micro Service에서 프리젠테이션 계층이 저정도 용도가 필요하다면 사용해도 좋을 것 같다.

참고로 넷플릭스는 위의 도식에 해당하는 아키텍처를 버린듯한 내용의 포스팅이 최근에 올라와있다.
전반적으로 프리젠테이션 계층을 GraphQL로 전환하고 있는 것으로 보인다.
자세한 것은 아래 참조 문서를 참고바란다.

How Netflix Scales its API with GraphQL Federation (Part 1)

비즈니스 계층 횡단 관심사 처리

위 그림은 비즈니스 계층에 속하는 마이크로 서비스 API 서버에 API Gateway Framework를 적용한 경우로 이를 호출하는 프리젠테이션 계층 API Gateway들이 꼭 필요로 하는 API들만을 호출 가능하게 제약하고, 호출에 대한 로그를 남기는 API Gateway Framework를 두었다.

사실 실제로 이렇게까지 사용하는 경우는 드물다. 이것을 다시 모놀리식으로 비유하자면 서비스 코드에다가 AOP로, 어느 컨트롤러는 이 서비스 클래스의 메소드를 호출할 수 있고 어느 클래스는 호출 못하고 이런 것을 설정을 안할 것이다. 그래서 이런 API Gateway Framework도 별로 필요하지 않다고 말하는 것이다.

하지만 그래도 특정 프리젠테이션 계층 API Gateway에 대해 늘 철저히 보안 처리를 하고 싶다면 사용해도 좋을 것 같다. 여기서도 보다시피 절대로 API Gateay Framework는 비즈니스 계층을 프리젠테이션 계층으로 격상하는 용도로 사용한 것이 아니다. AOP처럼 횡단 관심사 처리를 위해 사용되었을 뿐이다.

여기서 내가 생각하거나 혹은 이미 마이크로서비스 패턴 책 등에 나와 있는 API Gateway Framework의 문제점들을 다양하게 제시했다. 마무리로 첨언하자면 여기서 다룬 모든 문제들이 모두 해결 가능하거나, 그런 문제들에도 불구하고 이를 사용해서 얻는 이득이 훨씬 큰 경우가 있다면 당연히 API Gateway Framework를 사용해도 괜찮을 것이다.

API Gateway Pattern에는 API Gateway가 없다.

https://hamin7.github.io/2024/04/14/API-Gateway/

Author

hamin

Posted on

2024-04-14

Updated on

2024-05-12

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.
You need to set client_id and slot_id to show this AD unit. Please set it in _config.yml.