CircuitBreaker--熔断器设计模式
熔断器模式可以防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费CPU时间去等到长时间的超时产生。熔断器模式也可以使应用程序能够诊断错误是否已经修正,如果已经修正,应用程序会再次尝试调用操作。
翻译:Kyle 作者:Abhinav Dhasmana 原文:https://itnext.io/understand-circuitbreaker-design-pattern-with-simple-practical-example-92a752615b42
问题描述
我们有一个serviceA
有两个API
-
/data
依赖于 serviceB
-
/data2
不依赖于外部服务
让我们尝试实现这个场景,看看它如何影响我们的整个系统。完整的源代码可以在Github上找到。
没有断路器
serviceB
实施如下。API对前5分钟的请求,将延迟5s响应。它在端口8000上运行。
server.route({
method: 'GET',
path: '/flakycall',
handler: async (request, h) => {
const currentTime = Date.now();
if ((currentTime - serverStartTime) < (1000 * 60 * 5)) {
const result = await new Promise((resolve) => {
setTimeout(() => {
resolve('This is a delayed repsonse');
}, 5000);
});
return h.response(result);
}
return h.response('This is immediate response');
},
});
serviceB:模拟延迟响应
serviceA
将向serviceB
发出http请求
server.route({
method: 'GET',
path: '/data2',
handler: (request, h) => {
try {
return h.response('data2');
} catch (err) {
throw Boom.clientTimeout(err);
}
},
});
server.route({
method: 'GET',
path: '/data',
handler: async (request, h) => {
try {
const response = await axios({
url: 'http://0.0.0.0:8000/flakycall',
timeout: 6000,
method: 'get',
});
return h.response(response.data);
} catch (err) {
throw Boom.clientTimeout(err);
}
},
});
ServiceA:调用受影响的serviceA
我们将使用jMeter模拟负载 。在几秒钟内,serviceA将资源短缺。所有请求都在等待http请求完成。第一个API会开始抛出错误,它最终将会崩溃,因为它会达到最大堆的上限。
jMeter报告API失败
<---最后几个GC --->
[90303:0x102801600] 90966 ms:标记扫描1411.7(1463.4) - > 1411.3(1447.4)MB,1388.3 / 0.0 ms(自标记开始以0步开始+ 0.0 ms,最大步长0.0 ms,标记开始后的停机时间1388 ms)旧空间GC请求
[90303:0x102801600] 92377 ms:标记扫描1411.3(1447.4) - > 1411.7(1447.4)MB,1410.9 / 0.0 ms最后请求旧空间GC
<--- JS stacktrace --->
==== JS堆栈跟踪=========================================
安全上下文:0x2c271c925ee1
1:clone [/Users/abhinavdhasmana/Documents/Personal/sourcecode/circuitBreaker/client/node_modules/hoek/lib/index.js:~20] [pc = 0x10ea64e3ebcb](this = 0x2c2775156bd9