![[17.0.0.3 and later]](../ng_v17003plus.gif)
Liberty에서 마이크로서비스 복원력 향상
MicroProfile 결함 허용 기능을 사용하여 서비스 호출의 복원력을 향상시킬 수 있습니다. 이 기능은 Eclipse MicroProfile 결함 허용 스펙 1.0의 구현입니다. 이 기능은 Failsafe 개방형 소스 라이브러리를 사용하여 재시도, 회로 차단기, 벌크헤드, 제한시간 및 폴백을 포함하는 패턴을 통해 복원력 있는 마이크로서비스를 지원하는 프로그래밍 모델을 제공합니다.
시작하기 전에
프로시저
- server.xml 파일의 featureManager 요소에
mpFaultTolerance-1.0 기능을 추가하십시오.
<featureManager> <feature>mpFaultTolerance-1.0</feature> </featureManager>
- 마이크로서비스 복원력을 향상시키기 위한 코드 스니펫을 사용하십시오. 결함 허용 회로 차단기는 시스템이 오류를 빠르게 처리할 수 있는 방법을 제공합니다. 이 방법은 시스템의 과부하를 방지하기 위해 일시적으로 서비스를 실행할 수 없도록 합니다.결함 허용 재시도 정책은 서비스를 재시도하는 시점을 구성하는 방법을 제공합니다. 기본 서비스가 실패하면 결함 허용 폴백은 사용할 서비스를 지정할 수 있습니다.결함 허용 벌크헤드는 서비스에 대한 동시 호출 수를 제한합니다. 벌크헤드는 서비스 호출에서 사용할 수 있는 시스템 자원의 양을 제한합니다. 이 코드 스니펫을 사용하려면 server.xml 파일에 mpFaultTolerance-1.0은 물론 Libertyconcurrent-1.0 기능도 지정되어 있어야 합니다.
회로 차단기 코드 스니펫 1: CircuitBreaker 및 제한시간이 구성되어 있는 CircuitBreakerBean 작성
@RequestScopedpublic class CircuitBreakerBean { private int executionCounterA = 0; // The combined effect of the specified requestVolumeThreshold and failureRatio is that 3 // failures will trigger the circuit to open. // After a 1 second delay the Circuit will allow fresh attempts to invoke the service. @CircuitBreaker(delay = 1, delayUnit = ChronoUnit.SECONDS, requestVolumeThreshold = 3, failureRatio = 1.0) // A service is considered to have timed out after 3 seconds @Timeout(value = 3, unit = ChronoUnit.SECONDS) public String serviceA() { executionCounterA++; if (executionCounterA <= 3) { //Sleep for 10 secs to force a timeout try { Thread.sleep(10000); } catch (InterruptedException e) { System.out.println("serviceA interrupted"); } }
CircuitBreaker 코드 스니펫 2: CircuitBreakerBean 작성
@Inject CircuitBreakerBean bean; // FaultTolerance bean with circuit breaker, should fail 3 times for (int i = 0; i < 3; i++) { try { bean.serviceA(); throw new AssertionError("TimeoutException not caught"); } catch (TimeoutException e) { //expected } } // The CircuitBreaker should be open, so calling serviceA should generate a // CircuitBreakerOpenException. try { bean.serviceA(); throw new AssertionError("CircuitBreakerOpenException not caught"); } catch (CircuitBreakerOpenException e) { //expected } //allow time for the circuit to re-close Thread.sleep(3000); // The CircuitBreaker should be closed and serviceA should now succeed. String res = bean.serviceA(); if (!"serviceA: 4".equals(res)) { throw new AssertionError("Bad Result: " + res); }
폴백 및 재시도 코드 스니펫 1: FallbackHandler 및 재시도 정책이 구성되어 있는 FTServiceBean
@RequestScopedpublic class FTServiceBean { // Annotate serviceA with a named FallbackHandler and a Retry policy specifying the // number of retries. @Retry(maxRetries = 2) @Fallback(StringFallbackHandler.class) public String serviceA() { throw new RuntimeException("Connection failed"); return null; } }
폴백 및 재시도 코드 스니펫 2: 기본 서비스가 실패할 경우 구동되는 코드인 FallbackHandler
@Dependentpublic class StringFallbackHandler implements FallbackHandler<String> { @Override public String handle(ExecutionContext context) { return "fallback for " + context.getMethod().getName(); } }
폴백 및 재시도 코드 스니펫 3: FTServiceBean 사용
private @Inject FTServiceBean ftServiceBean; try { // Call serviceA, which will be retried twice in the event of failure, after which // the FallbackHandler will be driven. String result = ftServiceBean.serviceA(); if(!result.contains("serviceA")) throw new AssertionError("The message should be \"fallback for serviceA\""); } catch(RuntimeException ex) { throw new AssertionError("serviceA should not throw a RuntimeException"); }
벌크헤드 코드 스니펫 1: 벌크헤드가 구성되어 있는 BulkheadBean 작성
@RequestScoped@Asynchronous public class BulkheadBean { private final AtomicInteger connectATokens = new AtomicInteger(0); // Configure a Bulkhead that supports at most 2 concurrent threads. @Bulkhead(maxThreads = 2) public Future<Boolean> connectA(String data) throws InterruptedException { System.out.println("connectA starting " + data); int token = connectATokens.incrementAndGet(); try { if (token > 2) { throw new RuntimeException("Too many threads in connectA[" + data + "]: " + token); } Thread.sleep(5000); return CompletableFuture.completedFuture(Boolean.TRUE); } finally { connectATokens.decrementAndGet(); System.out.println("connectA complete " + data); } } }
벌크헤드 코드 스니펫 2: BulkheadBean 사용
@Inject BulkheadBean bean; // connectA has a poolSize of 2 // The first two calls to connectA should be run straight away, in parallel, each around // 5 seconds Future<Boolean> future1 = bean.connectA("One"); Thread.sleep(100); Future<Boolean> future2 = bean.connectA("Two"); Thread.sleep(100); // The next two calls to connectA should wait until the first 2 have finished Future<Boolean> future3 = bean.connectA("Three"); Thread.sleep(100); Future<Boolean> future4 = bean.connectA("Four"); Thread.sleep(100); //total time should be just over 10s Thread.sleep(11000); if (!future1.get(1000, TimeUnit.MILLISECONDS)) { throw new AssertionError("Future1 did not complete properly"); } if (!future2.get(1000, TimeUnit.MILLISECONDS)) { throw new AssertionError("Future2 did not complete properly"); } if (!future3.get(1000, TimeUnit.MILLISECONDS)) { throw new AssertionError("Future3 did not complete properly"); } if (!future4.get(1000, TimeUnit.MILLISECONDS)) { throw new AssertionError("Future4 did not complete properly"); }
상위 주제: Liberty 튜닝

파일 이름: twlp_microprofile_fault_tolerance.html