
FTGO 어플리케이션의 서비스 API는 다음 네 종류의 클라이언트에서 호출된다.
이 중 웹 어플리케이션은 주로 방화벽 내부에서 실행되기 때문에 망 연동에 문제가 크지 않지만, 다른 클라이언트는 방화벽 외부에 있으므로 대역폭 및 지연 시간에 민감할 수 있다. 클라이언트에서 서비스에서 오픈한 API를 직접 접근하는 형태로 구성할 수는 있지만, 다음 사유들로 인해 실질적으로 사용되지 않는다.

소비자는 FTGO 모바일 클라이언트를 통해 서비스에 접근하여 새로운 주문을 생성하거나, 현재 주문을 갱신하거나, 과거의 주문에 대한 이력을 관리할 수 있어야 한다. 주문상태, 지불상태, 음식점 관점에서의 주문 상태 등의 주문 기본 정보와 배달 중일 경우 현재 위치 및 예상 배달시간등의 배달 상태를 한눈에 볼 수 있는 주문 조회 뷰 등의 기능이 요구될 수 있다. 만약 모놀리식 패턴으로 개발을 진행한다면, 주문내역을 반환하는 API 끝점에 클라이언트가 원하는 정보를 한번의 요청으로 모두 가져갈 수 있도록 구현이 가능하지만, 마이크로 서비스 버전은 주문 데이터가 아래 처럼 여러 곳에 분산되어 있어 한번에 가져가는 것이 어렵다.

주문, 주방, 배달, 회계의 각 서비스를 호출하면 UX관점에서 지연에 따른 불편함이 발생할 수 있다. 클라이언트가 여러 서비스를 병행해서 호출하는 형태로 지연 최소화를 시도할 수 있으나, 선행 서비스 API에서 가져온 키 정보를 기반으로 이후 서비스를 호출해야 하는 경우라면(예를 들어 주문서비스에서 오더 내역을 받아와야 회계 서비스 정보를 쿼리 가능) UX품질이 매우 저하될 수 있다.
또한 모바일 클라이언트 개발 부서에서 서비스 API 호출에 역량을 많이 투입하면 본연의 업무를 소홀이 하게 되는 문제가 발생하게 되며, 부수적으로는 망 요청이 늘어날 수록 배터리 소모도 더 커지는 등의 문제가 발생하게 된다.
어플리케이션이 발전함에 따라 다양한 클라이언트(모바일 기기 등)와 호환되지 않는 변경이 발생될 수 있다. 서비스에 대한 로직이 클라이언트에 포함되어 있으면 서비스 API를 변경하는 것이 매우 어려워질 수 있다. 따라서 서비스 API를 최종 클라이언트에 오픈하는 것은 장기적으로 큰 걸림돌이 될 수 있다.
클라이언트의 네트워크는 다양한 방화벽 장비 등을 경유해서 서비스에 접근하게 된다. 일반적으로 사용하는 HTTP, 웹소켓 등이 아닌 경우, 서비스 제공자가 제어할 수 없는 외부의 방화벽에서 차단되는 문제가 발생할 수 있다. 더욱이 클라이언트는 성능, 용량 등의 한계로 인해 gRPC, AMQP 등의 프로토콜을 지원하지 않을 수도 있으며, 지원이 갑자기 종료되는 등의 문제가 발생할 수 있다.
웹어플리케이션은 방화벽 내부에서 서비스를 호출하여 HTML을 응답하는 역할을 수행하며, 주로 방화벽 내부에서 빠른 네트워크를 통해 접근하며, 개발 부서가 백엔드 서비스 개발 부서와 밀접하게 협업이 가능하므로 다양한 프로토콜들을 사용하는 것이 용이하다.
서비스를 호출하는 주체는 주로 브라우저에서 실행되는 자바스크립트인 경우가 많다. 예를 들어 소비자의 웹 어플리케이션은 자바스크립트로 주문 내역 페이지를 동적으로 새로고침 하면서 현재 주문 상태, 배달 위치 등을 제공할 수 있다. 자바스크립트 어플리케이션은 서버에서 그때 그때 다운로드 받아가는 형태이므로 상대적으로 업데이트는 용이하지만, 인터넷을 통한 접근이므로 네트워크 지연 및 비용 문제는 발생할 수 있다.
FTGO는 외부 개발자들이 필요한 데이터를 가져가 사용할 수 있도록 개발자용 API를 제공할 수 있다. 이러한 API는 업그레이드를 강요하기 어려운 문제이므로, 구 버전을 오랫동안 유지해야 하는 경우가 발생할 수 있고, 따라서 유지보수가 어렵게 만드는 문제가 될 수 있다. 장기간 하위호환성을 유지해야 한다면 서버 개발자는 검증 및 개발해야 할 분량이 급수적으로 늘어나게 되어 큰 문제가 될 수 있다. 따라서 서드파티 개발자에게는 안정적으로 제공 가능한 별도의 API를 제공하는 형태가 필요하다.
패턴:API 게이트웨이
마이크로서비스 어플리케이션에 외부 API 클라이언트의 진입점에 해당하는 서비스를 구현한다.
마이크로 서비스 아키텍처에서 클라이언트는 둘 이상의 프런트 엔드 서비스와 상호 작용하게 된다. 앞서 살펴본 클라이언트가 서비스를 직접 호출할때의 여러 이슈 뿐만 아니라, 클라이언트는 자신이 서비스받기 위해 호출할 엔드포인트를 확인할 수 있어야 하고, 또 새 서비스가 도입되거나 기존 서비스가 리팩터링되어도 새로운 엔드 포인트를 지속 파악할 수 있어야 한다. 추가로 서비스에서 SSL 종료, 인증 및 기타 고려 사항들을 처리할 수 있는 방안으로 API 게이트웨이의 사용이 합리적이다.

API 게이트웨이는 클라이언트와 서비스 사이에 배치하여, 클라이언트가 서비스로 보내는 요청을 라우팅하는 역할을 수행(일종의 역방향 프록시)하며, 인증, 로깅, SSL 처리, 트래픽 제한 등 서비스 AP에 공통적으로 필요한 부수적인 작업을 포함하여 수행할 수도 있다. 게이트웨이는 같은 디자인 패턴으로 그룹화할 수 있습니다.
API게이트웨이는 방화벽 외부의 클라이언트가 어플리케이션에 API요청을 하는 단일 창구 역할을 하는 서비스로, façade[fəˈsɑːd] 패턴과 유사하다. 퍼사드처럼 API게이트웨이도 내부 어플리케이션의 아키텍처를 캐술화 하고 자신의 클라이언트에게 API를 제공하면서, 인증, 모니터링, 사용량 제한 등 부수적인 업무도 수행한다.

클라이언트로부터 요청이 들어오면, 라우팅 맵(routing map)을 활용하여 어느 서비스로 요청을 보낼지 결정하는 역할을 수행한다. HTTP메소드와 HTTL의 URL을 매핑한 형태로, 역방향 프록시 형태로 동작한다.
API 게이트웨이는 단순 리버스 프록시와 큰 차이점으로 API 조합을 한다는 것이다. FTGO의 주문 내역 조회 API는 주문, 배달, 회계, 주방의 서비스를 각각 호출하여 하나의 응답으로 클라이언트에게 응답하게 된다. 따라서 API 게이트웨이는 개별 서비스의 미세한 API와 달리 큰 규모의 API를 제공한다.

API 게이트웨이는 클라이언트로부터 요청 받은 프로토콜과 다른 프로토콜을 사용하여 서비스를 호출 할 수 있다. 예를 들어 클라이언트는 REST API로 API 게이트웨이에 요청을 하지만, API 게이트웨이는 내부의 gRCP, kafka 등의 프로토콜을 사용하여 요청을 보낼 수 있다.
엣지 기능(주변 기능)으로 인증, 인가, 사용량 제한 등의 공통적으로 필요한 기능들은 개별 서비스에서 구현하는 것 보다는 게이트웨이로 오프로딩하여 구현하는 것이 유리하다. API게이트웨이는 클라이언트와 직접 연계되는 API 단에서 구현할 수도 있으며(upstream) 혹은 별도의 엣지 서비스를 구성하는 형태도 가능하다. 전자는 API게이트위에의 라우팅, 조합 등의 본연의 기능에 추가적인 기능을 포함하여 개발하기 때문에 관심사가 조금 혼재되는 것에 비하여, 후자는 라우팅과 조합을 담당하는 서비스와 엣지 서비스를 담당하는 서비스로 분산하여 관심사를 분리하는 장점이 있다. 반면에 API게이트웨이와 엣지 서비스를 분리하는 경우 한 홉이 증가함에 따라 네트워크 지연, 복잡도 증가 및 유지보수의 어려움 등이 단점이다.
다양한 클라이언트의 출현으로 시스템 요건이 점점 복잡해지고 있다. 모바일 앱, PC 앱, 그리고 다양한 브라우저별 웹 등 여러 유형의 클라이언트가 존재한다. 모든 데이터를 클라이언트로 보내고, 클라이언트가 필요한 정보를 선택하여 사용자에게 보여주는 방식도 가능하지만, 이 경우 불필요한 데이터 전송으로 인해 서비스 트랜잭션 부하와 네트워크 부하가 증가하게 된다. 이로 인해 사용자 단말의 메모리 및 네트워크 사용량이 늘어나면서 UX 측면에서 불리해지고, 보안 리스크 또한 커질 수 있다.
따라서 API 게이트웨이를 사용해 각 단말의 특성에 맞는 API를 제공하는 것이 더 효율적이다. 이를 통해 클라이언트별로 필요한 데이터만 전달하여 성능을 최적화하고, 네트워크 사용량과 보안 문제를 최소화할 수 있다.
API 게이트웨이는 클라이언트 쪽에 오픈된 API계층과 인증, 인가, 로깅 등 엣지 기능을 수행하는 공통 계층으로 구성된다. 다음 예제 그림에서는 모바일API, 브라우져API, 퍼블릭API의 세 API 모듈과 공통 모듈로 구성되어 있다.

API 게이트웨이는 어느 개발 부서에서 담당해야 하는가는 새로운 이슈이다. 넷플릭스는 API가 표출된 모든 모듈은 해당 클라이언트 팀이 소유하는 형태로 운영된다. API게이트웨이를 담당하는 부서는 공통 모듈의 개발 및 운영에 집중하는 형태이다. 그러나 이러한 형태는 책임 소재가 불분명해 지고, 배포 파이프라인에 적용하는데 지연이 발생할 수 있는 문제가 있다. 여러 팀의 사람들이 동일 코드베이스에 코드를 커밋하고, API 게이트웨이팀이 그 운영을 담당하는 것은 책임 소재가 불분명해지는 문제가 있다.

"if you build it, you own it (빌드한 사람이 주인이다.)"
BFF(Backend for Frontend)는 프런트엔드 클라이언트의 요구에 맞게 최적화된 백엔드 레이어를 제공하는 패턴이다. 각 클라이언트 유형(모바일 앱, 웹 앱 등)에 특화된 API를 별도로 설계하여 제공하는 방식으로 각 API 모듈을 하나의 클라이언트 팀이 개발/운영하는 stand alone 형태의 API 게이트웨이를 구성하는 형태이다. 다만 공통 기능에 대하여 중복 코드를 개발할 우려가 있으므로, API 게이트웨이에 동일한 기술 스택을 적용하여 운영하는 것이 합리적이며, 공통 기능은 API 게이트웨이 팀이 개발하는 공유 라이브러리 형태가 된다.

BFF를 사용하면 클라이언트가 필요로 하는 데이터만 정확하게 전달할 수 있어, 불필요한 데이터 전송을 줄이고 네트워크 트래픽을 최적화할 수 있다. 또한 클라이언트별로 요구사항이 다른 경우, BFF를 통해 프런트엔드에 맞춤형 데이터를 제공해 개발 효율성과 사용자 경험(UX)을 동시에 향상시킬 수 있다. 또한 각 BFF가 특정 클라이언트를 위한 백엔드 역할을 수행하기 때문에, 클라이언트와 백엔드 간의 데이터 처리 로직에 대한 책임이 분명해진다. 구체적으로 BFF는 클라이언트에 맞춘 데이터 포맷팅, 응답 최적화, 필요한 데이터의 집계 및 가공 등을 처리한다.
패턴: BFF(프런트엔드를 위한 백엔드)
각 클라이언트 종류마다 API 게이트웨이를 따로 구현한다.
http://microservices.io/patterns/apigateway.html
API게이트웨이도 다양한 장/단점을 가지고 있다.
API 게이트웨이에서 동기I/O를 사용할지, 아니면 비동기I/O를 사용할지는 성능과 확정성에 큰 설계 사항이다. 동기I/O 모드는 네트워크 접속건마다 thread를 하나씩 배정하는 형태로 개발이 용이하다. 그러나 동기I/O를 사용한다면 OS의 thread를 사용하기 때문에 OS의 한계에 따른 제약이 발생하며, 동시접속 가능 개수도 제한이 된다. 반면에 비동기I/O를 사용하면 비동기 호출 후 콜백 형태로 동작하여 프로그래밍 모델이 복잡하고, 유지보수와 디버깅이 어려운 단점이 있지만, 비동기I/O를 사용하면 multi-thread를 사용하는 오버헤드가 없기 때문에 확장성에 장점을 갖는다.
API게이트웨이가 조합을 위해 서비스를 호출할때 병렬 호출과 순차 호출을 모두 사용하여 개발해야 한다. 그러나 동시성 코드는 주로 콜백 기반으로 작성(서블릿 기반 조합기도 모두 콜백 활용) 되었다. 그러나 이러한 형태로 개발하다 보면 콜백 지옥(callback hell)에 빠지게 되고, 특히 병렬 호출과 순차 호출이 혼재되면 오류가 발생될 가능성이 높아지고 유지보수도 어려워진다. 따라서 API 조합 코드는 리액티브한 선언형 스타일로 작성하는 것이 유리하다.
리액티브 프로그래밍 추상체는 비동기 데이터 흐름과 변화의 전파를 다루기 위한 프로그래밍 방식으로, 특히 MSA(Microservices Architecture) 패턴에서 API 게이트웨이를 사용해 여러 서비스 호출을 관리할때 효율적으로 사용할 수 있다. 리액티브 프로그래밍은 데이터가 발생하거나 변경될 때 해당 이벤트를 구독(subscribe)하고, 데이터를 비동기적으로 처리하여 반응하는 방식으로, 리액티브 프로그래밍 추상체는 이러한 비동기 데이터 흐름을 다루기 위한 인터페이스나 클래스 집합이다. API 게이트웨이가 클라이언트 요청을 받아 여러 마이크로서비스로 라우팅할때 각 서비스는 서로 다른 데이터 처리 시간을 가질 수 있고, 비동기적으로 작동할 가능성이 높으므로 리액티브 프로그래밍 추상체를 사용하는 것이 유리하다.
API 게이트웨이의 안정성을 위해서는 L4 등 부하 분산기를 활용할 수 있다. 추가로 API게이트웨이는 실패한 요청 또는 지연이 너무 긴 요청에 대한 적절한 처리가 필요하다. 실패 혹은 지연되는 호출이 늘어나게 되면 리소스를 지속 점유하거나 서비스에 과도한 부하를 야기하는 등의 문제가 발생되기 때문에 회로 차단기 패턴 등을 통해 처리 상태를 제어해야 한다.
API 게이트웨이를 구현하기 위해서는 API 게이트웨이 프레임워크 또는 웹 프레임워크를 기반으로 API 게이트웨이를 직접 개발할 수 있다. 개발에 많은 자원이 투입되어야 하지만, 유연하게 필요한 요구사항을 모두 달성할 수 있다. 반면에 기성(off the shelf) API 게이트웨이 제품이나 서비스 활용하여 라우팅과 엣지 기능 등을 개발하는 것이다. 다만 대체로 기성 API 게이트웨이 제품은API 조합을 지원하지 않아 필요한 부분이 있으면 직접 구현해야 하는 단점이 있다.
[부록] 퍼사드 패턴 - 위키백과
퍼사드(프랑스어: façade[fəˈsɑːd] 영어: facade) 패턴(외관 패턴)은 소프트웨어 공학 디자인 패턴 중 하나이다. 객체 지향 프로그래밍 분야에서 자주 쓰인다. Facade (외관)는 "건물의 정면"을 의미한다.퍼사드는 클래스 라이브러리 같은 어떤 소프트웨어의 다른 커다란 코드 부분에 대한 간략화된 인터페이스를 제공하는 객체이다.
퍼사드는 소프트웨어 라이브러리를 쉽게 사용할 수 있게 해준다. 또한 퍼사드는 소프트웨어 라이브러리를 쉽게 이해할 수 있게 해 준다. 퍼사드는 공통적인 작업에 대해 간편한 메소드들을 제공해준다.
퍼사드는 라이브러리를 사용하는 코드들을 좀 더 읽기 쉽게 해준다.
퍼사드는 라이브러리 바깥쪽의 코드가 라이브러리의 안쪽 코드에 의존하는 일을 감소시켜 준다. 대부분의 바깥쪽의 코드가 퍼사드를 이용하기 때문에 시스템을 개발하는 데 있어 유연성이 향상된다.
퍼사드는 좋게 작성되지 않은 API의 집합을 하나의 좋게 작성된 API로 감싸준다.
래퍼(wrapper)가 특정 인터페이스를 준수해야 하며, 폴리모픽 기능을 지원해야 할 경우에는 어댑터 패턴을 쓴다. 단지 쉽고 단순한 인터페이스를 이용하고 싶을 경우에는 퍼사드를 쓴다.퍼사드 구조
- 퍼사드: 퍼사드 클래스는 패키지 1,2,3 및 그림에 나오지 않은 그 밖의 응용 프로그램 코드와 상호 동작한다.
- 클라이언트: 패키지 내의 리소스들을 접근하기 위해 퍼사드 클래스를 쓰는 객체들이다.
- 패키지: 소프트웨어 라이브러리 / API 집합이다. 퍼사드 클래스를 통해 접근된다.