이책은 스프링으로 하는 마이크로서비스 구축(스프링 부트와 스프링 클라우드를 이용한 도커/쿠버네티스 마이크로서비스) 책을 읽고 학습한 내용을 정리한 글입니다.
- Spring Boot를 사용한 마이크로서비스 구축 및 소개(1부) 에서 정리한 마이크로서비스 문제를 완화하기 위해 디자인 패턴을 사용할 수 있다. 스프링 부트, 스프링 클라우드, 쿠버네티스를 사용해 디자인 패턴을 구현할 방법을 추후에 정리할 예정입니다.
✏️ 문제점: 클라이언트가 마이크로서비스와 그 인스턴스를 찾을 수 있어야 한다. 컨테이너 등에서 실행되는 마이크로서비스 인스턴스는 시작하면서 동적 IP주소를 할당 받는게 일반적이다. 이런 상황은 마이크로서비스가 노출하는 HTTP 기반의 REST API를 클라이언트에서 호출하는 것을 어렵게한다.
💡 해결책: 현재 사용 가능한 마이크로서브와 그 인스턴스를 추적하는 새 컴포넌트(서비스 검색 서비스)를 시스템 환경에 추가한다.
✏️ 문제점: 마이크로서비스 시스템 환경에선 일부 바이크로서비스만 시스템 환경 외부에 공개하고, 그 외의 마이크로서비스는 외부에서 접근하지 못하도록 숨기는 게 바람직하다. 공개된 마이크로서비스는 악의적인 클라이언트의 요청으로부터 보호해야한다.
💡 해결책: 모든 요청이 거치는 시스템 환경에 새 컴포넌트(에지 서버)를 추가한다.
✏️ 문제점: 관례적으로 자바 개발자는 HTTP기반의 RESTful JSON API와 같은 블로킹 I/O모델을 사용해 동기식 통신을 구현해 왔다. 블로킹 I/O를 사용하면 요청을 처리하는 동안 운영체제의 스레드를 점유하게 된다. 동시 요청 수가 증가하거나 요청과 관려된 컴포넌트가 증가하면 운영체제의 가용 스레드가 부족해 응답 시간이 늦어지거나 서버가 중단되는 문제가 발생할 수 있다.
💡 해결책: 논블로킹 I/O를 사용해 데이터베이스나 다른 마이크로서비스가 처리하길 기다리는 동안 스레드가 할당되지 않게 한다.
✏️ 문제점: 일반적으로 애플리케이션은 여러 환경변수나 파일에 담긴 구성정보와 함께 배포되는데, 다수의 마이크로서비스 인스턴스가 배포된 마이크로서비스 아키텍처 기반의 시스템 환경에선 문제가 있다.
💡 해결책: 시스템 환경에 모든 마이크로서비스의 구성 정보를 젖장하는 새 컴포넌트(구성 서버)를 추가한다.
✏️ 문제점: 보통 애플리케이션을 실행하고 있는 로컬 머신에 애플리케이션 로그 이벤트를 기록하는데, 여러 개의 소규모 서버에 다수의 마이크로서비스 인스턴스를 배포하는 마이크로서비스 아키텍처 기반의 시스템 환경에선 다음과 같은 문제가 있다.
💡 해결책: 로그를 중앙화해 관리하고 다음과 같은 기능을 갖춘 새 컴포넌트를 추가한다.
✏️ 문제점: 시스템 환경에 대한 외부 호출을 처리하는 동안 마이크로서비스 사이에서 흐르는 요청 및 메시지를 추적할 수 있어야 한다.
예:
💡 해결책: 공조 마이크로서비스 사이의 처리 과정을 추적하려면 관련된 모든 요청 및 메시지에 상관 ID(correlation ID)를 넣어야 하고, 모든 로그 이벤트에 상관 ID가 있어야한다. 중앙화된 로깅 서비스에서 상관 ID를 검색하면 관련된 로그 이벤트를 모두 찾을 수 있다. 비즈니스 관련 식별자(예: 고객, 제품, 주문 등)가 포함된 로그 이벤트를 찾은 다음 상관 ID로 검색하면 해당 비즈니스 식별자와 관련된 모든 로그 이벤트를 찾을 수 있다.
✏️ 문제점: 동기 방식으로 상호 통신하는 마이크로서비스 시스템 환경은 연쇄 장애가 발생할 여지가 있다. 하나의 마이크로서비스가 응답하지 않으면 이 마이크로서비스의 클라이언트 또한 클라이언트의 요청에 응답하지 않게 된다. 이 문제는 시스템 환경 전체에 재귀적으로 전파돼 중요한 부분까지 중단시킬 수 있다. (이런 문제는 블로킹 I/O를 사용해 동기식 요청을 실행하는 경우에 자주 발생한다.)
💡 해결책: 대상 서비스에 문제가 있다는 것을 감지해 새 요청을 보내지 않도록 차단하는 서킷 브레이커를 추가한다.
✏️ 문제점: 다수의 마이크로서비스 인스턴스가 여러 서버에 분산돼 있는 시스템 환경에선 중단되거나 지연된 마이크로서비스 인스턴스를 수동으로 감지하고 대처하는 것이 어렵다.
💡 해결책: 시스템 환경의 상태를 관찰하는 새 컴포넌트(제어 루프)를 시스템 환경에 추가한다. 이 컴포넌트는 운영자가 지정한 상태와 실제 상태를 지속적으로 관찰하며, 두 상태가 다른 경우에는 현재 상태가 지정한 상태와 일치하도록 조치를 취한다.
✏️ 문제점: 동기 방식으로 상호 통신하는 마이크로서비스 시스템 환경은 연쇄 장애가 발생할 여지가 있다. 하나의 마이크로서비스가 응답하지 않으면 이 마이크로서비스의 클라이언트 또한 클라이언트의 요청에 응답하지 않게 된다. 이 문제는 시스템 환경 전체에 재귀적으로 전파돼 중요한 부분까지 중단시킬 수 있다. (이런 문제는 블로킹 I/O를 사용해 동기식 요청을 실행하는 경우에 자주 발생한다.)
💡 해결책: 대상 서비스에 문제가 있다는 것을 감지해 새 요청을 보내지 않도록 차단하는 서킷 브레이커를 추가한다.
✏️ 문제점: 응답 시간이 하드웨어 자원 사용량이 지나치게 높은 경우 문제의 근본 원인을 찾는 게 매우 어렵다. 마이크로서비스별 하드웨어 자원 사용량을 분석할 수 있어햔다.
💡 해결책: 마이크로서비스 인스턴스가 사용하는 하드웨어 자원 사용량에 대한 메트릭을 수집하는 새 컴포넌트(모니터 서비스)를 시스템 환경에 추가한다.
프로메테우스에서 가져온 메트릭을 시각화한 그라파나 화면
디자인 패턴 | 스프링 부트 | 스프링 클라우드 | 쿠버네티스 | 이스티오 |
---|---|---|---|---|
서비스 검색 | 넷플리스, 유레카(Eureka)와 넷플릭스 리본(Ribbon) | 쿠버네트스의 kube-proxy와 서비스 리소스 | ||
에지서버 | 스프링 클라우드와 스프링 시큐리티, OAUTH(Spring Security OAuth) | 쿠버네트스의 인그레스 컨트롤러(Ingress Controller) | 이스티오의 인그레스 게이트웨이 | |
리액티브 마이크로서비스 | 스프링 리액터(Spring Reactor)와 스프링 웹 플럭스(Spring WebFlux) | |||
구성 중앙화 | 스프링 컨피그 서버(Spring Config Server) | 쿠버네트스의 컨피그 맵(ConfigMap)과 시크릿(Secret) | ||
로그 분석 중앙화 | 일래스틱 서치(Elasticsearch), 플루언티드(Fluentd), 키바나(Kibana) | |||
분산추적 | 스프링 클라우드 슬루스(Sleuth)와 집킨(Zipkin) | 예거(Jaeger) | ||
서킷 브레이커 | Resilience4j | 이상감지(Outlier detection) | ||
제어 루프 | 쿠버네이스의 컨트롤러 매니저(controller manager) | |||
모니터링 및 경고 중앙화 | 그라파나와 프로메테우스 | 키알리(Kiali), 그라파나, 프로메테우스 |