본문 바로가기

컨테이너/쿠버네티스 네트워크

API Gateway란 무엇인가? (Spring Cloud Gateway)



목표:

MSA 아키텍처에서 API Gateway를 사용하는 이유가 무엇일까?

1. API Gateway가 무엇일까? 

2. 관심사의 분리란?

3. API Gateway의 필요성

4. Spring Cloud Gateway 실습

 

 


관문 역할을 하는 API GATEWAY를 통해 클라이언트와 백엔드 서비스 사이에 필요한 인증, 속도제어, 장애시 트래픽 절단, 모니터링 등 여러 공동 모듈을 API GATWAY에서 구현하여 공통 관심사를 처리해줄수 있다.

 

꽤 많은 회사에서 사용하고 있습니다.

 

https://www.youtube.com/watch?v=ECS1UAo2s00

 

API GATEWAY를 사용하고 있는 대부분의 고객사가 대부분이 SPRING CLOUD 스택을 사용합니다.

 

 

1. API GATEWAY란?


  • 리버스 프록시 역할을 하는 관문 역할
  • 비즈니스 로직이 아닌 기타 관심사들을 처리하는 역할

정말 간단하게 정의하자면, API GATEWAY는 클라이언트와 백엔드 서비스 사이에 위치하는 리버스 프록시 역활을 하는 서비스 입니다. 더불어 인증, 속도제어, 서킷브레이커, 모니터링등 여러 공동 모듈 및 관리포인트들을 추가하여 모든 API들의 관문(GATEWAY)의 역할을 하는 서비스 입니다.

 

관문 역할 뿐만 아니라, 관심사의 분리를 위해서도 API Gateway는 필요합니다. 비즈니스 로직과 분리하기 위하여 AOP라는 개념을 떠올리면 이해를 도울수 있을것 같다. 왜냐하면 AOP와 마찬가지로 API Gateway 역시 비즈니스 로직과 분리 하여 기타 관심사들을 API Gateway를 통해 처리하겠다는 의미로 나는 이해한다.

 

2. AOP ( 관점 지향형 프로그래밍 ) - 관심사의 분리란? 


| 스프링 AOP ( Aspect Oriented Programming )

AOP는 스프링 3대 기반기술 중 하나이다. AOP Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 불린다. 관점 지향은 쉽게 말해 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화하겠다는 것이다. 여기서 모듈화란 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것을 말한다. 

 

예로들어 핵심적인 관점은 결국 우리가 적용하고자 하는 핵심 비즈니스 로직이 된다. 또한 부가적인 관점은 핵심 로직을 실행하기 위해서 행해지는 인증 , 인가 , 트랜잭션 처리 등이 있다. AOP에서 각 관점을 기준으로 로직을 모듈화한다는 것은 코드들을 부분적으로 나누어서 관리 하겠다는 의미이다. 이때, 소스 코드상에서 다른 부분에 계속 반복해서 쓰는 코드들을 발견할 수 있는 데 이것을 흩어진 관심사 (Crosscutting Concerns)라 부른다. 이러한 흩어진 관심사들을 모듈화 하여 중복된 코드를 제거하고 필요한 모듈만 꺼내어 쓰는 형태로 프로그래밍을 하게 하는 전략들을 AOP (관점지향 프로그래밍) 이라고 부른다.

이러한 개발 방법론과 Cloud Native의 어플리케이션을 만드는 원칙 자체가 유사한 것은 어플리케이션 생산성에 있어서 이러한 형태의 방법 자체가 구분없이 코딩하는 것보다 훨씬 더 개발 생산성과 가독성을 증진시키는데 큰 영향을 주기 때문이다. 본론으로 돌아와서 API Gateway를 활용하여 아키텍처를 만드는것은 AOP의 관점과도 부합하는 아키텍처를 구축 할수 있다고 생각한다.

 

그 이유는, 모든 어플리케이션에 접근하기 위해서는 인증,인가와 같은 부가적인 기능들 을 꼭 필요로 하는데, 이를 각 어플리케이션에 적용하는 코드를 포함하는 경우에는 불필요한 코드가 지속적으로 중복이 되는것이고 이러한 코드들을 어플리케이션들의 관문인 API Gateway에서 처리할수 있다면, 관심사의 분리를 할 수 있으며 개발생산성에 크게 영향을 줄수 있다.

  • 부가적인 기능들 
    • 인증
    • 속도 제한
    • 캐싱
    • 부하 분산
    • 로깅
    • 모니터링

3. API Gateway 의 필요성 


  • 각각의 서버들에 Request를 보낼 때 인증을 거쳐야 하는데, 마이크로서비스가 늘어날수록 서비스의 수 만큼 인증을 받아야 하는 번거로움이 있다 , 인증을 위해 반복되는 작업을 줄여주고, 한번의 인증으로 여러서비스를 한번에 사용 할 수 있도록 도와주는 Spring Cloud Gateway를 사용 해 보도록 하겠다.
  • URI에 따라 서비스 엔드포인트를 다르게 가져가는 동적 라우팅이 가능해진다. 예를 들면 도메인 변경없이 레거시 시스템을 신규 시스템으로 점진적으로 교체해 나가는 작업을 쉽게 진행할 수 있다.
  •  모든 트래픽이 통하기 때문에 모니터링 시스템 구성이 단순해진다.
  •  동적 라우팅이 가능하므로 신규 스팩을 서비스 일부에만 적용하거나 트래픽을 점진적으로 늘려나가는 테스트를 수행하기에 수월해진다. ( 롤링 업데이트, 카나리 업데이트 , 블루그린 업그레이드)

4. Spring Cloud Gateway 특징

  • Netty 사용 ( Spring boot는 tomcat을 사용하지만, SCG는 Netty를 사용함 비동기 성능 때문 )
Netty란? 

기존의 서블릿 기반의 Spring Boot 는 Tomcat을 기반으로 동작합니다. 하지만 Tomcat 자체가 동기방식을 사용하기 때문에 
비동기 방식을 지원하는 Netty라는 네트워크 프레임워크가 존재함.
기존의 비동기방식의 Tomcat은 한 번에 한 연결만 처리한다. 다수의 동시 클라이언트를 관리하려면 새로운 클라이언트 Socket마다 새로운 Thread를 할당해야한다. 이런식의 블로킹 처리는 어떠한 결과를 초래하게 될 것인가? 여러 스레드가 입력이나 출력 데이터가 들어오기를 기다리며 무한정 대기 상태로 유지될 수 있고, 이것은 고로 리소스의 낭비로 이어진다.

하지만,  네티의 논블로킹 네트워크 연결은 작업 완료를 기다릴 필요가 없다. 완전 비동기 입출력은 이 특징을 바탕으로 한 단계 더 나아간다.  비동기 메서드는 즉시 반환하며 작업이 완료되면 직접 또는 나중에 이를 통지한다. 셀렉터는 적은 수의 스레드로 여러 연결에서 이벤트를 모니터링할 수 있게 해준다
  • 사용하기 쉬운 Predicate 방식, Filter 방식
Predicates : 일종의 조건문

1. Path
2. After, Before, Between
3. Cookie , Header 

 

 

4. 실습하기 Architecture


  • service 1 : local api 서버 테스트용 ( 호출형 프로젝트 ) 
  • service31 : kubernetes / docker / local api 서버 테스트용 ( 응답형  프로젝트 )

 

 

 

 

5. Spring Cloud Gateway 구현하기 실습

 

 

5-1. Spring initializer 프로젝트 생성

 

5-2. application.yml 작성

  • spring.cloud.gateway.routes.id= Eureka Server에 등록된 name
  • spring.cloud.gateway.routes.uri= Eureka Client의 url
  • spring.cloud.gateway.routes.predicates= Gateway의 인입되는 endpoint와 최종 목적지인 서비스의 endpoint를 매핑시키는 역할을 하는 조건값
server:
  port: 9001

spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
        - id: service1
          uri: http://localhost:8015
          predicates:
          - Path=/services/**
        - id: service31
          uri: http://client.taskoo.net
          predicates:
            - Path=/client/**
        - id: gateway
          uri: http://localhost:9001
          predicates:
            - Path=/gateway/**

eureka:
  instance:
    prefer-ip-address: true
  client:
    register-with-eureka: true # 유레카 서비스에 (자신을) 등록 여부
    fetch-registry: true
    serviceUrl:
      defaultZone: http://eureka.taskoo.net/eureka

management:
  endpoints:
    web:
      exposure:
        include: "*"

 

5-3. 최종 목적지  서비스의 엔드포인트 호출 메서드를 만들어준다.

 

  • predicates.Path 부분의  게이트웨이와 서비스의 엔드포인트가 같아야 호출이 가능함

  • gateway를 통해 service1을 호출 시
    • predicates Path = /services/ 이하로 호출 되는 URL은 모두 localhost:8015로 라우팅

  • gateway를 통해 service31을 호출 시  
    • localhost:9001이 게이트웨이 라우팅 주소이고 
    • predicates를 보면 /client 아래로의 URL 주소는 모두 client.taskoo.net으로 라우팅 되도록 설정
    • 모든 라우팅 설정은 application.yaml에서 적용
... 중략 
- id: service31
  uri: http://client.taskoo.net
  predicates:
     - Path=/client/**