[스프링 마이크로서비스 코딩 공작소] 교재를 통해 마이크로서비스를 처음 학습하게 되었다.

 

최근 팀 프로젝트에서 마이크로서비스 구조를 적용해보자는 논의가 있었지만, 프로젝트 일정이 지연되면서 그 아이디어는 자연히 사라지게 되었다. 그렇지만 마이크로서비스를 알지 못한 채 개발자로 성장하는 것은 원치 않아 학습을 시작하게 되었다.

 

학습을 시작하면서 크게 두 가지를 느꼈다. 첫째, 마이크로서비스를 너무 가볍게 생각했다는 것이다. 이전 프로젝트에서도 MSA 도입을 논의했지만, 단순히 서비스를 분리하고 통신하는 수준에서 그쳤던 것이다. 마이크로서비스 환경은 서비스 간 복잡한 통신으로 인해 예상보다 더 큰 복잡도를 동반하며, 이를 해결하기 위한 노력이 필요하다는 것을 깨달았다.

둘째, 마이크로서비스를 위해 이미 많은 기술들이 준비되어 있다는 것이다. 특히 Spring Cloud는 config server, gateway server 등 마이크로서비스에 필요한 다양한 기술들을 쉽게 제공하고 있어, 내가 그동안 경험하지 못한 부분이 많음을 느꼈다.

 

이번 글에서는 [스프링 마이크로서비스 코딩 공작소] 교재에서 다룬 마이크로서비스 환경의 기본 기술들이 각각 어떤 역할을 하는지 간단히 정리해보도록 하겠다.

 

* 첨언하자면 이번 교재에서는 Spring Cloud를 중심으로 다루었지만, 2025년 기준으로는 Spring Cloud와 K8S를 함께 활용하는 프로젝트가 많다고 한다. K8S를 함께 활용할 경우 이번 글에서 다루는 일부 기술을 K8S 쪽 기술로 대체할 수 있다.해당 내용은 별도로 다룰 예정이다.



Spring Cloud

Spring Cloud는 마이크로서비스 환경을 쉽게 구축하고 관리할 수 있도록 다양한 도구와 기능을 제공하는 프레임워크다.

마이크로서비스 간의 통신, 서비스 디스커버리, 보안, 로드 밸런싱 등 MSA의 필수 요소들을 쉽게 구현할 수 있게 해준다.

Spring Cloud는 Config Server, Eureka Server, Gateway Server 등의 기능을 제공하여 서비스 간의 연결과 데이터 교환을 쉽게 할 수 있도록 도와준다. 이를 통해 서비스 간의 결합도를 낮추고, 시스템의 확장성을 확보할 수 있다.

 

Config Server

Config Server는 중앙 집중식 설정 관리 서버로, Spring Cloud Config를 활용해 각 마이크로서비스의 설정을 중앙에서 관리할 수 있다. 각 서비스가 개별적으로 application.properties 또는 application.yml 파일을 작성하는 대신, 모든 설정을 Config Server에 작성하고 각 서비스가 이를 가져오는 방식이다. 또한, 설정 변경 사항을 실시간으로 반영할 수 있어 서비스 간 일관된 구성을 유지하는 데 도움이 된다. 보통 Git 저장소와 연동하여 설정 파일을 관리하며, 이를 통해 설정 관리의 효율성과 일관성을 높일 수 있다.

 

아래와 같이 설정을 통해 Config Server는 Git 저장소에서 설정 파일을 가져와 관리할 수 있다.

server:
  port: 8888
spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://github.com/my-repo/config-repo

 

Gateway Server

Spring Cloud Gateway는 API Gateway 역할을 수행하는 서버다.

API Gateway는 클라이언트의 요청을 적절한 마이크로서비스로 라우팅하는 중앙 진입점 역할을 하며, 인증/인가, 로드 밸런싱, 로깅, 트래픽 제어 등 다양한 기능을 제공한다.

 

API Gateway를 사용하면 여러 마이크로서비스가 각기 다른 포트를 사용할 때 클라이언트는 하나의 단일 진입점을 통해 모든 요청을 처리할 수 있다. 즉, 여러 서비스가 있을 때 service1.com과 service2.com으로 개별적으로 접근하는 것이 아니라, gateway.com/service1과 gateway.com/service2로 접근하게 되어 gateway.com이라는 단일 진입점을 제공한다. 이를 통해 API Gateway는 서비스 간의 결합도를 낮추고, 다양한 부가 기능을 중앙에서 관리할 수 있도록 도와준다.

 

아래 설정은 /users/** 경로의 요청을 user-service로 전달하도록 하는 설정을 보여준다.

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: http://localhost:8081
          predicates:
            - Path=/users/**

 

Eureka Server

Eureka Server는 서비스 디스커버리를 위한 서버다.

서비스 디스커버리란, 마이크로서비스들이 서로의 위치를 동적으로 찾을 수 있도록 지원하는 메커니즘을 말한다. Eureka 서버에 각 마이크로서비스들이 등록되면, 다른 서비스들은 Eureka를 통해 필요한 서비스의 위치를 조회할 수 있다. 이를 통해 부하 분산, 장애 대응, 동적 서비스 인스턴스 관리 등을 보다 쉽게 구현할 수 있다.

 

서비스 디스커버리는 MSA에서 중요한 요소로, 서비스 간의 통신을 효율적으로 처리하고, 서비스가 추가되거나 제거될 때도 다른 서비스에 미치는 영향을 최소화할 수 있다.

 

아래처럼 Eureka Server를 설정하고, 다른 마이크로서비스들이 이를 사용하도록 할 수 있다.

server:
  port: 8761
spring:
  application:
    name: eureka-server
  eureka:
    client:
      register-with-eureka: false
      fetch-registry: false

 

Kafka / Zookeeper

Kafka는 대량의 데이터를 빠르게 처리하고, 서비스 간의 비동기 이벤트를 전달하는 메시지 브로커다.

Kafka는 MSA 환경에서 서비스 간의 비동기적이고 효율적인 통신을 위해 사용된다. 각 서비스는 Kafka를 통해 이벤트를 발행하고, 다른 서비스들은 이를 소비하여 처리할 수 있다. 이를 통해 서비스 간의 결합도를 낮추고, 시스템의 확장성을 높일 수 있다.

 

또한 Kafka는 로그, 이벤트 스트림, 데이터 파이프라인 등 다양한 용도로 활용된다. 예를 들어, Kafka는 마이크로서비스들 간의 실시간 이벤트를 처리하거나, 데이터 흐름을 분리하여 처리하는 데 적합하다.

Zookeeper는 Kafka의 클러스터 노드 관리 및 리더 선출 등의 역할을 수행하는 코디네이션 서비스다. Kafka와 함께 사용하면 클러스터 관리가 용이해지고, 서비스의 장애 대응 및 복구가 간편해진다.

 

아래는 my-topic라는 kafka topic에 메시지를 발행하는 java 코드 예시이다.

@KafkaTemplate("my-topic")
public void sendMessage(String message) {
    kafkaTemplate.send("my-topic", message);
}

 

Keycloak

Keycloak은 오픈소스 인증 및 권한 부여 솔루션으로, OAuth 2.0, OpenID Connect, JWT 등의 표준을 지원한다. MSA 환경에서는 각 서비스가 독립적으로 보안 인증을 처리하는 대신, Keycloak을 통해 중앙에서 모든 인증과 권한 부여를 관리할 수 있다.

 

Keycloak을 활용하면 사용자 로그인, 액세스 토큰 발급 등을 쉽게 처리할 수 있다. 또한, Keycloak은 사용자 인증뿐만 아니라, 역할 기반 접근 제어(RBAC)와 같은 기능을 제공하여 서비스 간의 보안을 효과적으로 관리할 수 있다.

 

ELK 스택

ELK 스택은 Elasticsearch, Logstash, Kibana의 세 가지 오픈소스 도구로 구성된 시스템으로, 대량의 로그와 데이터를 수집, 처리, 검색, 분석 및 시각화하는 데 유용하다. 마이크로서비스 아키텍처(MSA)에서 각 서비스가 로그를 별도로 처리하고 관리하는 것은 매우 복잡할 수 있기 때문에, ELK 스택을 활용하면 모든 로그를 중앙에서 수집하고 분석할 수 있어 효율적인 모니터링과 디버깅을 할 수 있다.

 

Elasticsearch
Elasticsearch는 분산형 검색 엔진으로, 데이터를 빠르게 검색하고 분석할 수 있다. 로그 데이터를 저장하고, 인덱싱하여 검색 성능을 극대화한다. Elasticsearch는 RESTful API를 통해 다른 시스템과 쉽게 통합될 수 있어 MSA 환경에서 로그 데이터를 빠르게 검색하고 실시간으로 분석할 수 있는 강력한 도구로 사용된다.

예를 들어, 서비스 로그 데이터를 Elasticsearch에 저장한 후, Kibana를 사용해 시각적으로 대시보드를 구성하거나, 로그를 검색해 문제를 해결할 수 있다.


Logstash
Logstash는 데이터를 수집, 변환하고 저장소로 전송하는 데이터 파이프라인 도구다. 여러 다양한 소스(파일, DB, 메시지 큐 등)로부터 데이터를 수집하여 변환하고 Elasticsearch로 전송한다. Logstash는 로그 데이터를 수집하면서 로그의 형식을 변환하거나, 데이터를 필터링하고, 정규화하는 작업을 처리한다. 예를 들어, 다양한 포맷의 로그를 하나의 일관된 포맷으로 변환하고, 불필요한 로그를 제외하는 등의 처리가 가능하다.

 

Kibana
Kibana는 Elasticsearch 데이터를 시각화하는 도구로, 로그 데이터를 대시보드 형태로 시각화하여 직관적으로 모니터링할 수 있도록 돕는다. Kibana를 사용하면 실시간으로 서비스의 상태를 모니터링하고, 로그를 쉽게 검색하고 분석할 수 있다. 대시보드에서 데이터를 그래프나 차트로 시각화하여 문제가 발생한 지점을 빠르게 찾아낼 수 있다.

 

Zipkin

Zipkin은 분산 트레이싱 시스템으로, 마이크로서비스 간의 요청 흐름을 추적하여 성능 병목 현상 및 지연 문제를 분석하는 데 사용된다. Zipkin을 활용하면 서비스 간의 요청이 어떤 경로를 통해 전달되는지, 어느 지점에서 문제가 발생하는지 명확하게 파악할 수 있다.

 

Resilience4j

Resilience4j는 마이크로서비스의 장애 대응을 위한 라이브러리다. 마이크로서비스는 서로 의존성이 있기 때문에, 한 서비스의 장애가 다른 서비스로 전파될 수 있다. Resilience4j는 Circuit Breaker, Retry, Rate Limiter, Timeout 등 다양한 패턴을 통해 이러한 장애를 예방하고 복구하는 데 도움을 주며, 마이크로서비스의 신뢰성을 높여준다.

 

대표적으로 Circuit Breaker 패턴만 다뤄보도록 하겠다.

 

Circuit Breaker 패턴

Circuit Breaker(서킷 브레이커) 패턴은 특정 서비스가 장애를 겪을 경우, 다른 서비스로 영향을 전파하지 않도록 차단하는 기법이다. Resilience4j와 같은 라이브러리를 활용하여 이 패턴을 구현할 수 있다. 서킷 브레이커는 서비스가 실패한 경우, 잠시 동안 해당 서비스를 호출하지 않도록 하여, 시스템이 복구될 수 있는 시간을 준다.

 

아래 코드는 Circuit Breaker 예시로, getData() 실행 중 오류 발생 시 별도 작성된 fallbackMethod()를 수행하도록 한다.

@CircuitBreaker(name = "backendA", fallbackMethod = "fallbackMethod")
public String getData() {
    // 외부 API 호출
}

public String fallbackMethod(Exception e) {
    return "서비스가 현재 이용할 수 없습니다.";
}

 

끝!

+ Recent posts