컨퍼런스 감상문

[SLASH 23] '토스는 Gateway 이렇게 씁니다'를 보고

자바생 2023. 11. 17. 13:43
728x90

토스 SLASH 23 중 ‘토스는 Gateway 이렇게 씁니다’ 발표를 보고 정리한 내용입니다.

토스에서는 gateway를 어떻게 사용하고 있고, 발표에서 사용되는 키워드를 중심으로 학습을 진행했습니다.
또한, 제 생각을 적어놓은 것들이 많아 틀린 부분에 대해서 말씀해 주시면 감사하겠습니다.

 

 

 

Gateway란?

 

 

라우팅 및 프로토콜 변환을 담당하며 마이크로 서비스의 중개자 역할을 하는 서버로써 보안, 모니터링 등을 위한 단일 제어 지점으로 사용된다.

 

서버가 적을 때는 Client에서 서비스를 직접 호출하고, 인증이나 유저 정보 호출과 같은 공통 로직을 각 서비스에서 처리해도 큰 부담이 되지 않을 수 있다. 하지만 서버가 많아지면 위 방법처럼 수행하기 어렵다. 왜냐하면 공통 로직에 변경이 생기면 모든 서버에 적용하고 배포하는 것도 매우 큰 일이기 때문이다.

 



결국 모든 서비스에 필요한 유저 정보나 인증 등 gateway에서 통합하여 처리하게 되면 변경에도 편하고, 배포도 편하기 때문에 사용하는 것 같다.

만약 서버1, 2, 3, 4가 있다고 가정해 보자.
서버 2, 3에만 공통 로직이 있다면 이는 gateway에 넣는 것이 좋은 방법일까?

아직 MSA, gateway를 경험해보진 않았지만, 내 생각에는 넣지 않을 것 같다. gateway는 모든 서버를 지나가기 위한 단일 지점인데, 특정 서버에만 존재하는 로직을 gateway에 넣는 것이 다른 개발자들에게 오해를 불러일으킬 수 있을 것 같다는 생각이다.

 

 

Gateway는 요청이 오면 정의된 설정에 따라 요청을 라우팅하고, 사전에 설정된 필터들을 작동시킨다.

 

설정은 Route 단위로 하고, Route는 Predicate, Filter로 다시 구성된다.

 

Predicate는 요청을 구분할 때 사용하는 값으로 Path, Method, Host 등으로 요청 매칭,

필터는 매칭된 요청에 대한 전처리나 서비스의 응답에 대한 후처리를 구현한다.

 

하나의 라우트 안에서 여러 개의 필터가 선언될 수 있고, 순서에 따라 필터를 처리한다.

 

 

Backend For Frontend(BFF)

 

 

만약 Web, App 용 로직이 따로 있을 경우에는 어떻게 해야 할까?

위와 같이 여러 플랫폼이 존재할 경우, gateway에서는 Web, App 용 로직을 가지고 있어야 한다.

 

이 문제를 해결하기 위해 사용되는 것이 Backend For Frontend(BFF) 패턴이라고 한다. BFF는 Client에 맞는 하나의 백엔드를 사용하는 패턴이다.



kakao FE 기술블로그에서는 API로 예를 들었지만, Gateway와 비교해도 같은 문제가 발생할 수 있다고 생각한다.
CORS, 플랫폼 별로 다를 수 있는 인증 방식 등과 같이 달라질 수 있기 때문에 분리할 수 있으면 분리하는 게 좋아 보인다.

 

 

위 블로그에서 카카오페이지는 iOS, Android, Web을 지원하고 있고, Web에서만 BFF를 적용하고 있다.

 



아마 iOS, Android는 앱으로써 분리하지 않은 것 같다

 

 

토스에서는 BFF를 통해 Client 별로 관심사를 분리하고, Client에 맞는 전략을 가져갈 수 있다.

 

 

Ingress/Egress

 

 

Ingress gateway는 App, Web, mTLS, SSR, 망분리로부터 받은 API 요청들을 처리하고, 계열사별 Outbound 트래픽 처리를 담당하는 egress gateway가 있다고 한다.

 

 

Ingress, egress vs inbound, outbound

 

 

xxxgress와 xxxbound가 비슷한 느낌이어서 어떤 점이 다른지 궁금했다.

 



xxxbound는 데이터 흐름의 방향을 나타내는 용어이고,
xxxgress는 데이터 흐름의 진입 지점 또는 출구 지점에 초점을 맞춘 용어라고 이해하면 좋을 것 같다.

 

 

 

 

Gateway에서 사용되는 공통 로직

 

토스에서 사용하는 공통 로직은 크게

Request에 대한 전후처리, 유저 정보를 이용한 로직 수행, 보안, 서비스 안정화를 위한 설정이 있다.

 

 

 

Request에 대한 전후처리

 

 

sanitize

 

Sanitize는 클라이언트로부터 올바르지 않은 요청이 올 경우 이를 지워주거나 올바른 값으로 바꿔주는 것을 의미한다고 한다.

그래서 요청이 들어올 경우 gateway에서 sanitize를 해준다고 한다.

 

로깅

 

Gateway는 서비스의 진입점으로써 마이크로서비스 내의 트랜잭션을 구분할 수 있는 trace id를 생성하여 전파한다. 이렇게 생성한 trace id는 각자의 서비스에서 MDC 컨텍스트에 저장되어 로깅을 한다.

 

 

불필요한 중복 요청 제거


기존에 모든 서비스가 공통 API를 요청하면서 불필요한 중복 요청이 생기게 된다.

 

예를 들어, 사용자 약관 동의 여부 같은 것들이 있는데 모든 서비스에서 약관 동의 정보를 얻으려면 API 요청을 보내야 한다. 이때, 중복 요청이 생길 수 있기 때문에 gateway에서 약관 동의 API를 요청하여 internal header에 넣어서 서비스에 전달한다. 당연히 각 서비스들은 약관 동의 API를 호출하지 않고, internal header를 통해 약관 동의 여부를 알 수 있게 된다.

 

 



GPT internal header 설명

'내부 헤더'는 애플리케이션의 내부 아키텍처 내에서 사용되지만 일반적으로 외부 클라이언트에 노출되거나 사용되지 않는 HTTP 헤더를 의미합니다. 이러한 헤더는 마이크로서비스와 같은 분산 시스템의 여러 구성 요소 간 또는 프록시 서버와 애플리케이션 서버 간의 통신에 자주 사용됩니다.

 

 

 

유저 정보를 이용한 로직 수행

 

netflix passport

 

모든 서비스에서 유저 정보가 필요할 때, 유저 API를 호출하는 방식으로 유저 정보를 가져온다. 이는 tx내에 불필요한 중복 요청을 유발하고, 서버 리소스의 낭비로 이어지게 된다.

 

본 영상에서는 이를 개선하기 위해 넷플릭스 passport 구조를 참고하여 토스 방식으로 변형했다고 한다.

passport의 자세한 내용은 넷플릭스 블로그를 통해 확인하면 좋을 것 같다.

 

 



간단히 설명해 보자면 기존 넷플릭스 시스템에서는 로그인 과정에서 여러 단계가 존재하고, 이 단계에서 토큰이 잘못 관리될 가능성과 일관되지 않은 ID 데이터 구조 등 여러 가지 문제가 있었다. 이는 넷플릭스 생태계에 안전성을 보장하지 못하기 때문에 이를 개선하려고 서비스 전반에서 사용할 수 있는 passport라는 외부 토큰에 구애받지 않는 구조를 만들었다.

passport는 사용자 기기정보와 유저 정보를 담았고, 넷플릭스 내부적으로 안전하고 일관된 ID를 나타낼 수 있게 합니다. 그리고 passport에 관한 처리는 EAS(Edge Authentication Services)에서 진행한다.

그 결과, 여러 곳에 걸쳐져 있던 인증/인가 로직을 EAS로 중앙 집중화함으로써 해당 로직의 복잡성을 크게 감소했다. 또한, 표준화된 passport가 존재하기 때문에 다양한 토큰 형식을 관리할 필요가 없어지게 된다.

 

 

 

 

서비스 안정화 파트

 

토스의 MSA 패턴은 많은 서비스들이 거미줄처럼 서로 상호작용하고 있다.

 

만약 하나의 서비스에서 응답 지연이 발생하면, 이 서비스에 의존하는 수많은 서비스들에게 응답 지연이 전파되고, 이렇게 퍼져나간 응답 지연이 시스템의 자원을 점유하여 모든 시스템이 먹통이 되는 상황이 발생하게 된다.

 

이를 방지하기 위해 응답 지연을 유발하는 서비스에게 더 이상 요청 보내지 않고, 빠르게 실패하여 부하를 겪고 있는 서비스가 회복할 수 있게 돕고 , 응답 지연이 전체 서비스로 확산되지 않게 하는 것이 중요하다.

 

circuit breaker 패턴

 

위에서 설명한 내용을 해결하는 디자인 패턴을 서킷 브레이커 패턴이라고 한다. 즉, 장애 전파를 방지하는 방법이다.

 

 



이번 커디 프로젝트를 진행하면서 장애 전파에 대한 생각을 해보았다. 이때는 단일 서버여서 그런지 트랜잭션 분리를 통해서 장애 전파를 막을 수 있었다. 하지만 MSA 구조에서는 어떤 서비스에서 장애가 발생한 지 알기 어렵고, 트랜잭션 관리 또한 어렵기 때문에 장애 전파를 방지하는데 많은 리소스가 들지 않을까 싶다.

 

 

내부 서비스 간 서킷 브레이킹도 중요하지만 근원적인 트래픽을 발생시키는 클라이언트에게 백프래셔를 빠르게 주기 위해서는 게이트웨이에서 서킷 브레이킹을 거는 것이 중요하다.

 

 



호출되는 서비스가 오래 걸려 서킷 브레이커가 open 될 때, 그것에 관한 에러 핸들링이 중요할 것 같다. 서비스가 에러 나는 것보다 오래 걸리는 게 사용자 경험을 더 악화시킨다고 하지만, 둘 다 비슷할 것 같아서 결국 에러 핸들링이 매우 중요할 것 같다.

조대협 님 을 보면 상품 전시에서 상품 추천 서비스를 호출할 때, 추천 서비스의 장애로 인해 문제가 생길 경우 상품 전시에서는 기존 상품 진열자들이 미리 추천 상품 목록을 반환한다고 한다. 이 글을 보고 나니, 더더욱 에러 핸들링이 중요하다고 느껴졌다.

 

 

본 영상에서는 서킷 브레이킹하는 방법 두 가지를 설명한다.

 

Istio을 활용한 인프라 레이어의 서킷 브레이킹, 라이브러리를 이용한 애플리케이션의 서킷 브레이킹이 있다.

 

두 방법 각각 장단점을 가지고 있다.

 

Istio를 활용한다면 호스트 단위로 쉽고 빠르게 전체 적용이 가능하며, 애플리케이션 개발 주기와 독립적으로 관리될 수 있으나 istio는 호스트 단위로만 서킷 브레이킹 설정이 가능하고 설정할 수 있는 룰에도 한계가 있다.

 

그래서 토스는 각 애플리케이션이나 게이트웨이에 서킷 브레이킹을 적용함으로써 호스트나 route 단위 혹은 기능단위로 정교하게 서킷 브레이킹을 걸고 있다.

 

 



모든 요청이 서킷 브레이커를 통해서 가야 하는데, gateway는 요청에 대한 단일 지점이기 때문에 gateway에서 서킷 브레이킹을 적용하는 게 좋은 생각인 것 같다. 애플리케이션 성격에 따라 다르겠지만 토스에서는 fallback 메시징은 어떻게 처리할지 궁금하다.

 

 

Gateway 운영

 

장애가 발생하면 토스 전체 서비스에 영향이 있을 정도로 굉장히 중요하다.

 



gateway 하나만 있을 경우 SPOF인데 이를 해결해야 하지 않을까?

해당 에 따르면 gateway가 SPOF인 상황에서 제대로 동작하지 않는다면 전체 서버가 중단될 수 있기 때문에 특정 요구 사항을 충족하도록 특별히 설계된 여러 개의 API 게이트웨이를 보유하는 것이라 한다.
또한, 다른 에서는 여러 개의 API 게이트웨이를 사용한다고 한다.

 

https://priyalwalpita.medium.com/api-gateways-how-to-use-it-properly-d0535571f9c2

 

기존에는 mono repo 형태로 모든 게이트웨이 구현코드, route 설정 코드가 들어있었다.

 

 

금융 서비스이기 때문에 서비스 배포 시 증적을 남겨야 한다.

하지만 모든 게이트웨이가 하나의 레포에 있기 때문에 하나의 게이트웨이를 배포할 때 다른 게이트웨이의 코드 변경 사항이 함께 반영되어 증적 관리가 어렵다고 한다.

 

이를 개선하기 위해 게이트웨이 별로 레포를 분리하고, 공통 로직은 라이브러리화를 시켜서, 각 게이트웨이에서 임포트하여 사용하도록 변경했다.

 

그 결과 하나의 게이트웨이 작업이 다른 게이트웨이의 리뷰 및 배포 시에 방해가 되지 않게 되었다. 또한, route 설정을 모두 java코드에서 yaml로 변경하고, 별도의 라우트 설정 리포지토리로 분리하였다. 그 이유는 java를 사용하면서 가끔 잘못된 route 설정으로 배포된 경우가 많았다고 한다. yaml로 변경한 후에는 가독성이 높아졌다고 한다.

 



발표에서는 java → yaml 변환 전후 사진이 존재한다. 확실히 가독성이 좋아지는 게 느껴진다.

 

 

각 게이트웨이는 라우트 설정을 Spring Cloud Config를 통해서 임포트 할 수 있게 되어, 게이트웨이 코드와 라우트 설정을 완전히 분리하여 관리할 수 있게 됐다.

 

서비스 개발자를 위해 게이트웨이의 라우트를 설정할 수 있는 사내 웹서비스를 개발도 했다고 한다.

 

 

결론

 

최근에 면접준비를 하며 다중 서버일 경우에는 인증/인가를 어떻게 처리할지 의문을 가지면서 gateway를 알게 됐다.

gateway에서 인증/인가만을 처리하는 게 아니라 본 영상에서 공통된 로직, 전파 방지 등 다양한 기능을 할 수 있다는 것을 알았다. 또한, 처음 들어보는 단어들이 많아져서 하나하나 찾아보며 학습했다.

 

그 과정에서 netflix passport, 서킷 브레이커, BFF 등 새로운 키워드들을 많이 알게 됐다. 많은 블로그들을 참고하여, 완벽하게 이해하기에는 경험이 많이 부족하지만 단어를 들으면 이런 거지라고 느낌은 올 것 같다.

 

해당 발표를 듣고 많은 인사이트를 얻을 수 있었다. 아직 해당 기술들을 사용할 곳이 없지만 미리 지식을 쌓는 느낌이 재밌었다.

 

 

REFERENCES

 

 

카카오 FE 블로그 - BFF 패턴

ingress vs egress

netflix passport 방식

서킷 브레이커 조대협 님

서킷 브레이커 우아한 기술블로그

서킷 브레이커 마틴 파울러

서킷 브레이커 medium

API Gateway SPOF 문제 medium

API Gateway Usecase

 

 

 

728x90