Resilience4j

Resilience4j 是一个轻量级容错库,受Netflix Hystrix启发,但专为Java 8和函数式编程而设计。

轻量级,因为库只使用Vavr(以前称为Javaslang),它没有任何其他外部库依赖项。

相比之下,Netflix Hystrix对Archaius具有编译依赖性,Archaius具有更多外部库依赖性,例如Guava和Apache Commons Configuration。

使用Resilience4j,你不必全押,你可以选择你需要的东西。

其他

Hystrix 已经停止更新了。(2018-11-29)

快速开始

maven 引入

  [xml]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<dependencies> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-circuitbreaker</artifactId> <version>0.13.1</version> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-ratelimiter</artifactId> <version>0.13.1</version> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-retry</artifactId> <version>0.13.1</version> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-bulkhead</artifactId> <version>0.13.1</version> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-cache</artifactId> <version>0.13.1</version> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-timelimiter</artifactId> <version>0.13.1</version> </dependency> </dependencies>

基础案例

  • BackendService.java

简单的服务类。

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.concurrent.TimeUnit; /** * @author binbin.hou * @date 2018/12/18 */ public class BackendService { public String doSomethingSlowly() { try { TimeUnit.SECONDS.sleep(10); return "result"; } catch (InterruptedException e) { e.printStackTrace(); return e.getMessage(); } } public String doSomething() { return "hello world"; } public String doSomethingThrowException() { String name = null; return name.trim(); } }
  • Resilienece4jTest.java

测试案例

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import io.github.resilience4j.bulkhead.Bulkhead; import io.github.resilience4j.bulkhead.BulkheadConfig; import io.github.resilience4j.circuitbreaker.CircuitBreaker; import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; import io.github.resilience4j.ratelimiter.RateLimiter; import io.github.resilience4j.ratelimiter.RateLimiterConfig; import io.github.resilience4j.retry.Retry; import io.github.resilience4j.timelimiter.TimeLimiter; import io.github.resilience4j.timelimiter.TimeLimiterConfig; import io.vavr.control.Try; import org.junit.Test; import java.time.Duration; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.function.Supplier; import java.util.stream.IntStream; /** * @author binbin.hou * @date 2018/12/18 */ public class Resilienece4jTest { /** * CircuitBreaker主要是实现针对接口异常的断路统计以及断路处理 */ @Test public void testCircuitBreaker(){ // Create a CircuitBreaker (use default configuration) CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig .custom() .enableAutomaticTransitionFromOpenToHalfOpen() .build(); CircuitBreaker circuitBreaker = CircuitBreaker .of("backendName",circuitBreakerConfig); String result = circuitBreaker.executeSupplier(() -> "Hello"); System.out.println(result); } /** * 主要是实现超时的控制 */ @Test public void testTimelimiter(){ BackendService backendService = new BackendService(); ExecutorService executorService = Executors.newSingleThreadExecutor(); TimeLimiterConfig config = TimeLimiterConfig.custom() .timeoutDuration(Duration.ofMillis(600)) .cancelRunningFuture(true) .build(); TimeLimiter timeLimiter = TimeLimiter.of(config); Supplier<Future<String>> futureSupplier = () -> { return executorService.submit(backendService::doSomethingThrowException); }; Callable<String> restrictedCall = TimeLimiter.decorateFutureSupplier(timeLimiter,futureSupplier); Try.of(restrictedCall::call) .onFailure(throwable -> System.out.println("We might have timed out or the circuit breaker has opened.")); } /** * A Bulkhead can be used to limit the amount of parallel executions * Bulkhead目前来看是用来控制并行(parallel)调用的次数 */ @Test public void testBulkhead(){ BackendService backendService = new BackendService(); Bulkhead bulkhead = Bulkhead.of("test", BulkheadConfig.custom() .maxConcurrentCalls(1) .build()); Supplier<String> decoratedSupplier = Bulkhead.decorateSupplier(bulkhead, backendService::doSomethingSlowly); IntStream.rangeClosed(1,2) .parallel() .forEach(i -> { String result = Try.ofSupplier(decoratedSupplier) .recover(throwable -> "Hello from Recovery").get(); System.out.println(result); }); } /** * 主要用来做流控 */ @Test public void testRateLimiter(){ BackendService backendService = new BackendService(); // Create a custom RateLimiter configuration RateLimiterConfig config = RateLimiterConfig.custom() .timeoutDuration(Duration.ofMillis(100)) .limitRefreshPeriod(Duration.ofSeconds(1)) .limitForPeriod(1) .build(); // Create a RateLimiter RateLimiter rateLimiter = RateLimiter.of("backendName", config); // Decorate your call to BackendService.doSomething() Supplier<String> restrictedSupplier = RateLimiter .decorateSupplier(rateLimiter, backendService::doSomething); IntStream.rangeClosed(1,5) .parallel() .forEach(i -> { Try<String> aTry = Try.ofSupplier(restrictedSupplier); System.out.println(aTry.isSuccess()); }); } /** * fallback基本上是高可用操作的标配 */ @Test public void testFallback(){ BackendService backendService = new BackendService(); // Execute the decorated supplier and recover from any exception String result = Try.ofSupplier(backendService::doSomethingThrowException) .recover(throwable -> "Hello from Recovery").get(); System.out.println(result); } @Test public void testCircuitBreakerAndFallback(){ BackendService backendService = new BackendService(); CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("backendName"); Supplier<String> decoratedSupplier = CircuitBreaker .decorateSupplier(circuitBreaker, backendService::doSomethingThrowException); String result = Try.ofSupplier(decoratedSupplier) .recover(throwable -> "Hello from Recovery").get(); System.out.println(result); } /** * 代码重试 */ @Test public void testRetry(){ BackendService backendService = new BackendService(); CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("backendName"); // Create a Retry with at most 3 retries and a fixed time interval between retries of 500ms Retry retry = Retry.ofDefaults("backendName"); // Decorate your call to BackendService.doSomething() with a CircuitBreaker Supplier<String> decoratedSupplier = CircuitBreaker .decorateSupplier(circuitBreaker, backendService::doSomething); // Decorate your call with automatic retry decoratedSupplier = Retry .decorateSupplier(retry, decoratedSupplier); // Execute the decorated supplier and recover from any exception String result = Try.ofSupplier(decoratedSupplier) .recover(throwable -> "Hello from Recovery").get(); System.out.println(result); } }