Bulkhead 예제

2021. 8. 15. 23:24SpringBoot Monitoring/SpringBoot Resilience4j

반응형

소개

Resilience4j는 동시 수행의 제한을 두기 위해 두 가지 bulkhead pattern을 제공합니다.

  • SemaphoreBulkhead
  • FixedThreadPoolBulkhead

 

SemaphoreBulkhead

동시 요청 수를 제한을 두고 요청 수에 도달한 이후 요청에 대해서는 BulkheadFullException이 발생한다.

 

FixedThreadPoolBulkhead

시스템 자원과 별도로 thread pool을 설정하고 설정된 thread pool은 서비스를 제공하기 위한 용도로만 사용한다. 그리고 thread pool과 별도로 waiting queue를 설정할 수 있다. 만약 thread pool과 waiting queue 가 full 인 경우 BulkheadFullException이 발생한다.

 

Bulkhead 예제

소개에서 Resilience4j는 두 가지 bulkhead pattern을 제공한다고 했습니다. SemaphoreBulkhead와 FxedThreadPoolBulkhead에 대한 예제를 살펴보도록 하겠습니다.

 

SemaphoreBulkhead

SemaphoreBulkhead 예제에서는 두 가지 방식의 예제를 살펴보도록 하겠습니다. 예제 작성 전에 속성에 대해 살펴보도록 하겠습니다.

Config property Default value Description
maxConcurrentCalls 25 bulkhead에서 최대로 허용할 병렬 실행 수
maxWaitDuration 0 bulkhead가 포화 상태일 때 진입하려는 쓰레드를 블로킹할 최대 시간

설정은 두 가지 방식의 예제를 보도록 하겠습니다.

 

maxConcurrentCalls 만 설정

 

application.yml

spring:
  application.name: order-service
  output.ansi.enabled: always

server:
  port: 7070

management.endpoints.web.exposure.include: '*'
management.endpoint.health.show-details: always

# Spring actuator 에 circuitbreaker 정보를 표시하기 위한 설정
management.health.circuitbreakers.enabled: true

#------------------------------------------------------------
# SemaphoreBulkhead Configuration
#------------------------------------------------------------
resilience4j:
  bulkhead:
    instances:
      orderService:
        maxConcurrentCalls: 5

 

BulkheadServiceImpl.java

package com.roopy.service.impl;

import com.roopy.service.OrderService;
import io.github.resilience4j.bulkhead.annotation.Bulkhead;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
@Qualifier("bulkheadService")
public class BulkheadServiceImpl implements OrderService {

    Logger logger = LoggerFactory.getLogger(OrderService.class);

    @Autowired
    private RestTemplate restTemplate;

    @Override
    @Bulkhead(name = "orderService", fallbackMethod = "bulkheadFallback")
    public ResponseEntity<String> makeOrder() {
        return new ResponseEntity<>(restTemplate.getForObject("http://localhost:7071/pay", String.class), HttpStatus.OK);
    }

    public ResponseEntity<String> bulkheadFallback(Throwable t) {
        logger.error("Fallback Execution For Bulkhead, cause - {}", t.toString());

        return new ResponseEntity<>("결제 처리 중 오류가 발생하였습니다.", HttpStatus.SERVICE_UNAVAILABLE);
    }
}

결제 서비스 요청이 6번째부터 bulkheadFallback 메서드가 실행될 것입니다.

 

JMeter를 이용한 테스트

→ Test Plan 설정

Test Plan

→ Thread Group 설정

Thread Group

→ HTTP Reqeust 설정

HTTP Request

위의 설정은 동시 접속자 10명이 주문 서비스를 호출하는 테스트이다.

예상되는 결과는 maxConCurrentCalls: 5이고 maxWaitDuration: 0 이기 때문에 6번째 접속자가 서비스 호출 시 오류가 날것이다.

 

→ 테스트 결과

테스트겨로가

위의 결과를 보면 5명의 사용자 가는 서비스 호출에 성공하였고 5명의 사용자는 서비스 호출 실패한 것을 볼 수 있다.

 

maxWaitDuration 정보 설정

application.yml

spring:
  application.name: order-service
  output.ansi.enabled: always

server:
  port: 7070

management.endpoints.web.exposure.include: '*'
management.endpoint.health.show-details: always

# Spring actuator 에 circuitbreaker 정보를 표시하기 위한 설정
management.health.circuitbreakers.enabled: true

#------------------------------------------------------------
# SemaphoreBulkhead Configuration
#------------------------------------------------------------
resilience4j:
  bulkhead:
    instances:
      orderService:
        maxWaitDuration: 5000
        maxConcurrentCalls: 5

설정 파일에 maxWaitDuration을 5초로 설정한다.

 

PaymentController.java

package com.roopy.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PaymentController {

    @GetMapping(value = "/pay")
    public String makePay() throws InterruptedException {
        // Bulkhead maxWaitDuration 설정시 사용
        Thread.sleep(4000);
        return "주문 결제가 정상적으로 처리 되었습니다.";
    }

}

결제 서비스 처리가 4초가 걸린다고 가정하고 Thread.sleep 설정을 4초로 설정한다.

 

→ 테스트 결과

maxWaitDuration

위의 테스트 결과를 보면 동시접속 10명의 주문 서비스 요청이 정상적으로 수행된 것을 확인할 수 있다.

 

FixedThreadPoolBulkhead

예제 작성 전에 속성에 대해 살펴보도록 하겠습니다.

Config property Default value Description
maxThreadPoolSize Runtime.getRuntime()
.availableProcessors()
스레드 풀의 최대 사이즈를 설정한다.
coreThreadPoolSize Runtime.getRuntime()
.availableProcessors() - 1
스레드 풀의 코어 사이즈를 설정한다.
queCapacity 100 큐 용량을 설정한다.
KeepAliveDuaration 20 [ms] 스레드 수가 코어보다 많을때 초과분 만큼의 스레드가 유휴 상태로
새 태스크를 기다리는 최대 시간으로, 이 시간이 지나면 유휴 스레드는 종료된다.

 

application.yml 

spring:
  application.name: order-service
  output.ansi.enabled: always

server:
  port: 7070

management.endpoints.web.exposure.include: '*'
management.endpoint.health.show-details: always

# Spring actuator 에 circuitbreaker 정보를 표시하기 위한 설정
management.health.circuitbreakers.enabled: true

#------------------------------------------------------------
# SemaphoreBulkhead Configuration
#------------------------------------------------------------
resilience4j:
  bulkhead:
    instances:
      orderService:
        maxThreadPoolSize: 4
        coreThreadPoolSize: 3
        queueCapacity: 8

maxThreadPoolSize 값은 java 프로그램에서 Runtime.getRuntime(). availableProcessors() 실행해보았을 때 나온 값이다.

 

테스트 시나리오

  • 동시접속자 수 200명을 설정하고 동시에 서비스를 호출하였을 때
  • 총사용자수는 500명으로 설정하고 1초당 50명씩 서비스를 호출하였을 때

 

TC1. 동시접속자 수 200명을 설정하고 동시에 서비스를 호출하였을 때

 

→ Thread Group 설정

동시접속자 200명이 동시에 서비스 요청 설정

 

→ 테스트 결과

테스트결과

테스트 결과를 보면 Error 값이 0% 인 것을 확인할 수 있다.

 

TC2. 총사용자수는 500명으로 설정하고 1초당 50명씩 서비스를 호출하였을 때

 

→ Thread Group 설정

동시접속자 200명이 동시에 서비스 요청 설정

Ramp-up period 설정 값이 10으로 되어 있는데 이 의미는 500명의 사용자를 생성할 때까지 10초가 걸린다는 의미인데, 다시 말하면 1초 동안 50명의 사용자가 주문 서비스를 요청한다는 의미입니다.

 

→ 테스트 결과

테스트결과

테스트 결과를 보면 Error 값이 0% 인 것을 확인할 수 있다.

 

소스는 아래 사이트에서 받을 수 있습니다.

https://github.com/roopy1210/spring-boot-resilience4j

 

GitHub - roopy1210/spring-boot-resilience4j

Contribute to roopy1210/spring-boot-resilience4j development by creating an account on GitHub.

github.com

 

반응형

'SpringBoot Monitoring > SpringBoot Resilience4j' 카테고리의 다른 글

RateLimiter 예제  (0) 2021.08.22
Retry 예제  (0) 2021.08.07
CircuitBreaker 예제  (0) 2021.07.31
CircuitBreaker 개념  (0) 2021.07.31