Spring Cloud

calis_ws·2023년 8월 8일
0

클라우드 (Cloud)

클라우드는 컴퓨터 자원을 인터넷을 통해 제공하는 모델을 말한다.

  • 컴퓨터의 가상화를 통해 필요로 하는 컴퓨터 자원을 웹 서비스를 사용하듯이 쉽고 빠르게 구비할 수 있도록 해주는 기술을 클라우드 컴퓨팅이라고한다.

  • 클라우드 컴퓨팅 기술을 사용하면 컴퓨터 자원을 필요한 시점에 즉시 사용 가능해지고, 언제 어디서든 접근 할 수 있게 된다.

  • 클라우드 컴퓨팅을 통해 사용자에게 쉽게 컴퓨터 자원을 제공하는 것을 클라우드 서비스라고 한다.

  • 클라우드 서비스는 단순 저장 공간, 웹 기반 업무 도구, 접속 가능한 서버 컴퓨터 등을 제공한다.

클라우드 서비스의 종류

  • IaaS ( Infrastructure as a Service )

    가상화된 컴퓨터 인프라를 인터넷을 통해 제공해서 사용자가 필요한 운영체제, 애플리케이션, 데이터 등을 설치 및 관리/운용 할 수 있도록 해준다.

    IaaS 를 사용하면 자체적으로 하드웨어 인프라를 구축 할 필요 없이 클라우드를 통해 쉽게 이용 할 수 있다.

    예시로 AWS EC2, RDS, GCP Compute Engine등이 있다.

  • Paas ( Platform as a Service )

    개발된 산출물을 테스트 및 배포하기 위한 플랫폼을 제공한다.

    배포 및 테스트를 쉽게 할 수 있는 서비스를 제공해서 개발에 집중 할 수 있도록 해주는 서비스이다.

    예시로 AWS Elastic Beanstalk, GCP App Engine 등이 있다.

  • Saas( Software as a Service )

    인터넷을 통해 애플리케이션을 제공하는 형태로 웹 브라우저나 모바일 앱을 통해 소프트웨어를 사용할 수 있도록 하는 서비스

    소프트웨어의 설치 없이 클라우드를 통해 애플리케이션을 사용할 수 있게 해서 편의성과 접근성을 높여준다.

    예시로 Google Docs, Google Sheet 등이 있다.

스프링 클라우드 ( Spring Cloud )

하나의 큰 서비스를 개발하게 되면 여러 작은 서비스 (서버) 가 합쳐져서 하나의 큰 서비스를 이루게 되는데 이러한 분산된 시스템 개발에 도움이 되는 기능을 모아 놓은 라이브러리

  • 에러 상황을 작은 서비스 단위로 격리하여 안정성을 확보할 수 있다.

  • 여러 서비스가 하나의 큰 서비스를 구성할 때 작은 서비스 간의 통신이 필요한데 이 때 자동으로 서비스의 위치 정보를 동적으로 검색해서 통신 할 수 있게 하는 서비스 디스커버리 기능을 제공해서 서비스 간 결합도를 낮추고 확장성을 높인다.

  • Spring Cloud Config 를 사용해서 프로그램의 환경 설정을 중앙에서 관리하여 환경 설정 관리를 편리하게 한다.

  • 각각의 서비스는 별도의 Endpoint 를 구성하는데 이 때 API Gateway 를 사용해서 모든 Endpoint 에 대한 요청을 한 곳에서 받아서 알맞은 서비스로 전달해준다.

스프링 게이트웨이 ( Spring Gateway )

스프링 게이트웨이는 스프링 클라우드 프로젝트의 일부로 API 게이트웨이의 기능을 한다.

  • 요청의 조건에 따라 조건에 맞는 서비스로 요청을 전달하는 라우팅의 기능을 한다. (서비스 디스커버리를 제공)

  • 요청과 응답에 필터를 적용 시켜 인증, 인가, 로깅 등의 추가 작업을 할 수 있도록 필터링 기능을 제공한다.

게이트웨이 ( Gateway ) 란?

  • 서로 다른 두 개의 네트워크 사이에서 데이터 흐름을 제어하고 중개하는 역할을 하는 장치

  • 다른 네트워크로부터 요청을 받아서 내부 네트워크로 전달하고, 요청에 대한 응답을 다시 외부 네트워크로 반환하는 역할을 한다.

  • 게이트웨이와 리버스 프록시의 차이

    • 게이트웨이
      • 다른 네트워크에 있는 컴퓨터와의 통신일 때 사용 (라우팅)
      • 게이트웨이는 HTTP와 다른 통신 프로토콜을 지원
    • 프록시
      • 같은 네트워크에 있는 컴퓨터와의 통신일 때 사용
      • 프록시는 오직 HTTP만을 지원

gateway 프로젝트 생성

article 라우팅

@Configuration
public class RoutingConfig {
    @Bean
    //  라우팅
    //  어떤식으로 요청을 사용자에게 다른 서버로 잘 보낼 것인지
    public RouteLocator gatewayRoutes(RouteLocatorBuilder builder) {
        return builder.routes()
                //  http://localhost:8080/articles/**
                //  (/articles, /articles/{id}, /articles/{id}/comments)
                //  -> http://localhost:8082/articles/**
                .route("articles", predicate -> predicate
                        .path("/articles/**")
                        .uri("http://localhost:8082")
                )
                .build();
    }
}

  • gateway 애플리케이션에서 GET /articles 요청을 받고, 8082포트의 articles 애플리케이션으로 라우팅을 한 모습

auth 라우팅

@Configuration
public class RoutingConfig {
    @Bean
    //  라우팅
    //  어떤식으로 요청을 사용자에게 다른 서버로 잘 보낼 것인지
    public RouteLocator gatewayRoutes(RouteLocatorBuilder builder) {
        return builder.routes()
                //  http://localhost:8080/articles/**
                //  (/articles, /articles/{id}, /articles/{id}/comments)
                //  -> http://localhost:8082/articles/**
                .route("articles", predicate -> predicate
                        //  사용자가 보낸 요청의 Path
                        .path("/articles/**")
                        //  사용자의 요청을 전달할 Host
                        .uri("http://localhost:8082")
                )
                //  http://localhost:8080/auth/**
                //  -> http://localhost:8081/**
                .route("auth", predicate -> predicate
                        .path("/auth/**")
                        .filters(filter -> filter
                                //  정규표현식을 이용해 경로의 일부분을 추출
                                .rewritePath("/auth/(?<path>.*)", "/${path}")
                        )
                        .uri("http://localhost:8081/")
                )
                .build();
    }
}

  • gateway 애플리케이션에서 POST /auth/token/issue 요청을 받고, 8081포트의 auth 애플리케이션으로 라우팅을 한 모습

Filter 작성

  • Gateway가 모든 요청을 받아주는 만큼, 모든 요청에 대해 공통적으로 넣고 싶은 기능이 있다면 Filter 추가

  • GlobalFilter 인터페이스 구현 후, Bean 객체로 등록하면 Gateway에 자동 등록

GlobalFilter란?

Spring Cloud Gateway에서 제공되는 인터페이스로 API 게이트웨이를 구축하기 위해 사용되는 프레임워크

모든 라우팅 요청에 적용되는 전역 필터로 모든 요청에 공통적으로 적용되어야 하는 전역적인 로직이나 처리 구현 가능

PreLoggingFilter

요청이 Gateway에 먼저 전달되고, 사용자에게 도달하기 전에 실행
chain.filter()의 결과를 메소드의 반환값으로 전달해야 함

@Slf4j
@Component
public class PreLoggingFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(
            // HttpServletRequest & Response 대신
            // exchange
            ServerWebExchange exchange,
            // FilterChain
            GatewayFilterChain chain
    ) {
        // 사용자가 보낸 HTTP 요청을 받았다.
        ServerHttpRequest httpRequest = exchange.getRequest();
        // PreLoggingFilter에서 요청을 식별할 수 있는 HTTP Header를 작성
        // 나중에 PostLoggingFilter에서 해당 Header를 바탕으로
        // 실행에 걸린 시간 측정
        String requestId = UUID.randomUUID().toString();
        // 사용자가 보낸 요청을 조작(변형)하겠다.
        httpRequest.mutate()
                // 헤더를 변형한다.
                .headers(httpHeaders -> {
                    httpHeaders.add(
                            "x-gateway-request-id",
                            requestId
                    );
                    httpHeaders.add(
                            "x-gateway-request-time",
                            String.valueOf(Instant.now().toEpochMilli())
                    );
                });
        log.info("start transaction: {}", requestId);
        
        // filterChain.doFilter() 대신
        return chain.filter(exchange);
    }
}

POST /auth/token/issue 요청

PostLoggingFilter

요청이 전달된 뒤, 사용자에게 응답이 보내지기 전 실행
then() : 호출한 객체의 동작이 끝난 뒤, 실행

@Slf4j
@Component
public class PostLoggingFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 사용자에게 응답이 돌아가고 난 뒤에 실행하는 필터
        return chain.filter(exchange)
                .then(Mono.fromRunnable(() -> {
                    // 사용자가 보낸 HTTP 요청을 받았다.
                    ServerHttpRequest httpRequest = exchange.getRequest();
                    // PreLoggingFilter에서 만든 Header의 값을 받아 왔다.
                    String requestId = httpRequest.getHeaders()
                            .getFirst("x-gateway-request-id");
                    String requestTimeString = httpRequest.getHeaders()
                            .getFirst("x-gateway-request-time");
                    // 현재 시각
                    long timeEnd = Instant.now().toEpochMilli();
                    // PreLoggingFilter에서 기록한 시각
                    long timeStart = Long.parseLong(requestTimeString);
                    // 기록한다.
                    log.info("Execution Time id: {}, timediff(ms): {}",
                            requestId, timeEnd - timeStart);
                }));
    }
}

POST /auth/token/issue 요청

네이버 지도 API 사용해보기

NCP 앱 등록

Reverce Geocoding

Postman id key 추가

params gc 추가

Direction 5

params 강사님 예시 추가

출처 : 멋사 5기 백엔드 위키 10팀 유난히 내성적이었던 10팀

profile
반갑습니다람지

0개의 댓글