Sentinel을 활용한 마이크로서비스 안정성 보장

Sentinel 개요

Sentinel은 Alibaba에서 개발한 분산 시스템의 유량 제어 도구로, 유량 제어, 회로 차단, 시스템 부하 보호 등 여러 차원에서 서비스 안정성을 유지합니다.

설치 및 실행

릴리즈 페이지에서 JAR 파일 다운로드: 다운로드 링크

java -jar sentinel-dashboard-1.8.5.jar

실행 후 브라우저에서 http://192.168.56.102:8080/#/login 접속

  • 사용자명: sentinel
  • 비밀번호: sentinel
  • 주의: 기본 포트는 8080이며, 사용 전 해당 포트가 점유되지 않았는지 확인해야 합니다.

프로젝트 통합

Nacos 시작

먼저 Nacos 서버를 시작합니다.

Maven 의존성 설정

Spring Cloud 프로젝트에 다음 의존성을 추가합니다:

<!-- Sentinel Core -->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<!-- Nacos 데이터 소스 -->
<dependency>
  <groupId>com.alibaba.csp</groupId>
  <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

애플리케이션 속성 구성

# Sentinel 대시보드 주소
spring.cloud.sentinel.transport.dashboard=localhost:8080

# 클라이언트 통신 포트 (기본값: 8719)
spring.cloud.sentinel.transport.port=8719

샘플 컨트롤러 작성

@RestController
public class GameCharacterController {

    @GetMapping("/hero/yase")
    public String yaseHero(){
        return "야스오 영웅 정보...";
    }

    @GetMapping("/hero/daji")
    public String dajiHero(){
        return "다지 영웅 정보...";
    }
}

유량 제어 규칙

QPS 기반 제어

"/hero/yase" 엔드포인트에 대해 초당 최대 1회 요청만 허용하는 규칙을 설정합니다.

스레드 수 제한

@GetMapping("/hero/yase")
public String yaseHero() throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + " 처리 중 - " + LocalDateTime.now());
    Thread.sleep(5000); // 5초 지연
    return "야스오 영웅 정보...";
}

이 경우 스레드 수를 1로 제한하면 동시 접근이 불가능해집니다.

관련 리소스 모드

"/hero/daji" 리소스의 QPS가 임계치를 초과할 때 "/hero/yase" 리소스에 대한 접근을 제한합니다.

링크 모드

@Service
public class HeroService {

    @SentinelResource("acquireHero")
    public void acquireHero(){
        System.out.println("영웅 획득 로직");
    }
}

@RestController
public class GameController {
    
    @Autowired
    private HeroService heroService;

    @GetMapping("/game/battle")
    public String startBattle() {
        heroService.acquireHero();
        return "전투 시작";
    }

    @GetMapping("/game/shop")
    public String visitShop() {
        heroService.acquireHero();
        return "상점 방문";
    }
}

워밍업(Warm Up)

시스템이 장시간 저부하 상태일 때 갑작스러운 트래픽 증가를 부드럽게 처리하기 위한 방식입니다.

  • 임계치: 10
  • 워밍업 시간: 5초
  • 초기 임계치: 10/3 ≈ 3

대기열 큐

고르게 요청을 처리하도록 하여 시스템 과부하를 방지합니다.

규칙 영속화

Nacos 연동 설정

# Nacos 서버 주소
spring.cloud.sentinel.datasource.ds1.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.ds1.nacos.data-id=game-sentinel-rules
spring.cloud.sentinel.datasource.ds1.nacos.group-id=SENTINEL_GROUP
spring.cloud.sentinel.datasource.ds1.nacos.data-type=json
spring.cloud.sentinel.datasource.ds1.nacos.rule-type=flow

Nacos 데이터 예시

[
  {
    "resource":"/hero/yase",
    "limitApp":"default",
    "grade":1,
    "count":1,
    "strategy":0,
    "controlBehavior":0,
    "clusterMode":false
  }
]

서킷브레이커 규칙

느린 호출 비율

@GetMapping("/hero/yase")
public String yaseHero() throws InterruptedException {
    Thread.sleep(300); // 300ms 지연
    return "야스오 정보";
}

예외 발생 비율

private static int errorCounter = 0;

@GetMapping("/hero/yase")
public String yaseHero() {
    if(errorCounter++ < 3) {
        throw new RuntimeException("임시 오류");
    }
    return "야스오 정보";
}

@GetMapping("/reset")
public String resetError() {
    errorCounter = 0;
    return "카운터 초기화";
}

핫스팟 규칙

@GetMapping("/hero/detail")
@SentinelResource("heroDetail")
public String getHeroDetail(@RequestParam int heroId) {
    return "영웅 ID: " + heroId + " 상세 정보";
}

특정 파라미터(heroId)에 대해 유량 제어를 적용할 수 있습니다.

사용자 정의 예외 처리

@SentinelResource 활용

@GetMapping("/hero/detail")
@SentinelResource(value = "heroDetail", blockHandler = "handleBlockedRequest")
public String getHeroDetail(@RequestParam int heroId) {
    return "영웅 ID: " + heroId + " 상세 정보";
}

public String handleBlockedRequest(int heroId, BlockException ex) {
    return "요청이 너무 많습니다. 잠시 후 다시 시도해주세요. (ID: " + heroId + ")";
}

전역 예외 핸들러

@Component
public class GlobalSentinelExceptionHandler implements BlockExceptionHandler {
    
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        String jsonResponse = "{\"status\":429,\"message\":\"서비스 과부하. 잠시 후 재시도 바랍니다.\"}";
        response.getWriter().write(jsonResponse);
    }
}

태그: Sentinel microservices spring-cloud traffic-control circuit-breaker

8월 1일 03:54에 게시됨