节点断路器
以 本·纳德尔 联 合 国 谷歌+ (韩语)(中文(简体) )
这是一个 节点.js 执行情况 断路器 大众化模式 内 迈克尔·T·尼加德的书——发行!。用于断路器 用于代用上游资源的消耗,以致上游资源的失败 以可预测的方式向现有系统进行宣传。 清楚一点,断路器 无法防止失败;相反,它帮助您的应用程序主动管理失败, 未快速和/或酌情提供倒数.
断路器代表上游资源的消耗;但是,它没有 熟悉上游资源。 因此,断路器的范围 可以是路线,也可以是颗粒体,只要你认为合适。 比如,你可以拥有 一个代表整个上游资源的断路器。 或者,你可以创建一个 单个断路器 每种方法 在上游资源。 颗粒越多 你的断路器,你得到假阳性的可能性越小.
默认使用
每个断路器是由数个物体组成的,它们共同提供 跟踪和故障快速功能。 幸运的是,你不必知道 除非您正在构建自定义执行。 你只需要问 带有指定设置的断路器厂实例 .
创建断路器最简单的方式是创建一个完全没有设置的断路器. 这样做将创建一个带有"好"默认的断路器:
var CircuitBreakerFactory = require( "@bennadel/circuit-breaker" ).CircuitBreakerFactory;
var circuitBreaker = CircuitBreakerFactory.create();
// Invoke as closure.
circuitBreaker.execute(
function() {
return( upstreamResource.load() );
}
);
// Invoke as closure with context and arguments.
circuitBreaker.executeInContext(
upstreamResource,
function( param1, param2 ) {
return( this.load( param1, param2 ) );
},
[ "arg1", "arg2" ]
);
// Invoke as method on an object.
circuitBreaker.executeMethod( upstreamResource, "load", [ "arg1", "arg2" ] );
如您所见,通过断路器运行命令有三种方式:
execute( command [, fallback ] )executeInContext( context, command [, args [, fallback ] ] )executeMethod( context, methodName [, args [, fallback ] ] )
每个 execute* 方法返回一个承诺,如果解析
执行是成功的;或者,如果执行错误(或
根据断路器的状态绕行。 基本方法/函数
正在被引用的,应当返回承诺或同步值。 或者,它可以省略一个
如果不需要,则返回.
配置用途
这个 .create() 电路断路器制造厂的方法毫无争议,
您可以提供用于生成断路器的散列设置.
以下每个设置都是 选项数字 :
id- 基本国家实例的独特标识,用于 伐木业.requestTimeout- 允许悬吊待决请求的时间(以毫秒计) 在错误中被超时之前( 未完成 ) .volumeThreshold- 需要完成的请求数量(在 滚动度量衡窗口),然后才能计算出失败百分比.failureThreshold- 可能发生的故障的百分比(全部数字) 在断路器开关状态前滚动参数窗口 打开。 。 。 .activeThreshold- 可挂起的并行请求数量(即,不完全) 在断路器切换到 打开。 。 。 .isFailure- 确定给定失败是否为错误的函数;或 它应被归类为成功(例如404个答复).fallback- 用于断路器所有处决的全球倒计时 (每次处决都可以在当地推翻).monitor- 外部记录(前StatsD记录)的显示器 -- -- 函数或实例.bucketCount- 用于收集滚动统计数据的桶数 滚动度量衡窗口.bucketDuration- 滚动内每桶的长度(以毫秒计) 度量衡窗口.
页:1:滚动度量衡窗口的持续时间为 bucketCount * bucketDuration。 。 。 .
这也是断路器需要的时间 继续打开 之后
在允许执行“ 健康检查” 请求之前失败 .
var CircuitBreakerFactory = require( "@bennadel/circuit-breaker" ).CircuitBreakerFactory;
var circuitBreaker = CircuitBreakerFactory.create({
id: "Remote API",
requestTimeout: 5000,
volumeThreshold: 10,
failureThreshold: 10, // Percent (as in 1 failure in 10 responses trips the circuit).
activeThreshold: 50,
isFailure: function( error ) {
return( ! is404( error ) );
},
fallback: { /* Fallback value. */ },
monitor: function( eventType, eventData ) {
console.log( eventType, eventData );
},
bucketCount: 30,
bucketDuration: 1000
});
倒计时值
电路断路器的首要目标是 如果上游资源"失效" 看起来不健康 然而,"断路器"的次要目标是提供 一个更好的用户体验。 这意味着,如果能够提供有意义的回落值 如果出现错误,电路断路器将促进这一办法.
倒置值可以是函数值,承诺值,也可以是任何静态值. 如果是一个函数, 它应该返回一个承诺或一个静态值。 当 创建断路器 :
var CircuitBreakerFactory = require( "@bennadel/circuit-breaker" ).CircuitBreakerFactory;
var circuitBreaker = CircuitBreakerFactory.create({
id: "Remote API",
fallback: { /* Fallback value. */ }
});
但是,它们也可以在处决时提供(无论是否提供) 提供了全球回落值 :
var CircuitBreakerFactory = require( "@bennadel/circuit-breaker" ).CircuitBreakerFactory;
var circuitBreaker = CircuitBreakerFactory.create({
id: "Remote API",
fallback: { /* Fallback value. */ }
});
circuitBreaker
.execute(
function() {
throw( new Error( "Network Error" ) );
},
{ /* Local fallback value. */ }
)
.then(
function( result ) {
console.log( result ); // Will be LOCAL fallback value.
}
)
;
如果倒计时值是函数,则执行提供了 上下文 财务报告和审定财务报表 参数,同样的 上下文 财务报告和审定财务报表 参数 将用来引用后退.
断路器很吓人 - 如果我弄错了怎么办?
老实说,它可能是可怕的 - 将一些东西投入生产的想法 故意阻断代理系统的通话 如果你选择一个错误阈值,那就是 太低了, 你可能会太快地开始屏蔽请求 。 如果选择活动阈值 那太高了,你可能会把上游资源挖出来.
幸运的是,你不必直接潜入深端。 相反,你可以部署一个 被动断路器 它将记录所有的交通, 永远不会失败打开, (中文(简体) ), 不管上游资源变得多么不健康 这样的话,你可以花点时间 被动收集有关您 API 使用情况( 包括计数、 持续时间和 错误),在切换到带有特制设置的活性断路器之前.
由于这是一个被动电路断路器(从不打开),设置较少:
id- 基本国家实例的独特标识,用于 伐木业.isFailure- 确定给定失败是否为错误的函数;或 它应被归类为成功(例如404个答复).fallback- 用于断路器所有处决的全球倒计时 (每次处决都可以在当地推翻).monitor- 外部记录的显示器 -- -- 函数或实例(前StatsD) 伐木).
var CircuitBreakerFactory = require( "@bennadel/circuit-breaker" ).CircuitBreakerFactory;
var circuitBreaker = CircuitBreakerFactory.createPassive({
id: "Remote API",
monitor: function logEvent( eventType, eventData ) {
// Log statsD metrics about count and duration.
// Log errors.
}
});
// This error will result in a rejected promise; but, the Circuit Breaker will always
// remain closed, allowing requests to be executed.
circuitBreaker.execute(
function() {
throw( new Error( "Network Error" ) );
}
);
一旦你有机会 监视你的断路器, 你可以开始切换你的
.createPassive() 工厂电话 .create() 使用您设置的厂房呼叫
知与所收集的度量基准相对应。 你可以晚上好好睡一觉.
记录和监测
默认情况下,"断路器"悄悄地丢弃了所有内部事件. 不过,你会
可能想要在您的应用程序中日志错误并记录 StatsD 参数 。 为了做到这一点,
您可以提供一个日志函数作为 monitor 参数 :
var CircuitBreakerFactory = require( "@bennadel/circuit-breaker" ).CircuitBreakerFactory;
var circuitBreaker = CircuitBreakerFactory.create({
id: "Remote API",
monitor: function logEvent( eventType, eventData ) {
console.log( eventType, eventData );
}
});
此日志函数将调用如下 eventType值 :
closed过eventData属性{ stateSnapshot }execute过eventData属性{ stateSnapshot }emit过eventData属性{ stateSnapshot }failure过eventData属性{ stateSnapshot, duration, error }fallbackEmit过eventData属性{ stateSnapshot }fallbackFailure过eventData属性{ stateSnapshot, error }fallbackMissing过eventData属性{ stateSnapshot }fallbackSuccess过eventData属性{ stateSnapshot }opened过eventData属性{ stateSnapshot }shortCircuited过eventData属性{ stateSnapshot, error }success过eventData属性{ stateSnapshot, duration }timeout过eventData属性{ stateSnapshot, duration, error }
盖子下面,这实际上是用你的 logEvent() 完成混凝土的功能
执行情况 AbstractLoggingMonitor。如果不提供函数,则可以
提供扩展 Monitor 类或 AbstractLoggingMonitor
课。 如果你延长 AbstractLoggingMonitor 基础类,您只需覆盖
页:1 logEvent() 方法 :
var AbstractLoggingMonitor = require( "@bennadel/circuit-breaker" ).AbstractLoggingMonitor;
var CircuitBreakerFactory = require( "@bennadel/circuit-breaker" ).CircuitBreakerFactory;
class MyMonitor extends AbstractLoggingMonitor {
constructor( statsD ) {
super();
this._statsD = statsD;
}
logEvent( eventType, eventData ) {
stats.increment( `circuit-breaker.${ eventType }` );
}
}
// ....
var circuitBreaker = CircuitBreakerFactory.create({
id: "Remote API",
monitor: new MyMonitor( stats )
});
但是,如果你延长 Monitor 类,可以覆盖任意一个 log* 方法:
var CircuitBreakerFactory = require( "@bennadel/circuit-breaker" ).CircuitBreakerFactory;
var Monitor = require( "@bennadel/circuit-breaker" ).Monitor;
class MyMonitor extends Monitor {
logClosed( stateSnapshot ) {
/* ... */
}
logOpened( stateSnapshot ) {
/* ... */
}
}
// ....
var circuitBreaker = CircuitBreakerFactory.create({
id: "Remote API",
monitor: new MyMonitor()
});
这个 Monitor class 提供了以下默认, 不操作( no Operation) 方法, 该方法
表示您只需覆盖对您的应用程序有意义的程序 :
logClosed( stateSnapshot )我记录了断路器的状态 从打开到关闭.logExecute( stateSnapshot )- 我记录了死刑执行地点 电路断路器的状态和基础命令即将被引用.logEmit( stateSnapshot )我记录请求输入时点 断路器尚未被批准执行.logFailure( stateSnapshot, duration, error )- 我记录一下.. 执行已以错误结束 。 这只反映了非循环断路器出错 (参见日志Timeout()和日志Short Circuted()事件).logFallbackEmit( stateSnapshot )我记录了一个失败者 执行(由于错误、超时或短路) 反击.logFallbackFailure( stateSnapshot, error )- 我记录了一个存在 返回函数在错误中解析 .logFallbackMissing( stateSnapshot )我记录了一次失败的行刑地点 没有定义后退.logFallbackSuccess( stateSnapshot )我记录了一个倒数值的倒数点 成功支持失败或绕过执行 .logOpened( stateSnapshot )我记录了断路器的状态 从关闭到打开.logShortCircuited( stateSnapshot, error )-我记录了处决地点 绕行是因为电路断路器目前处于打开状态.logSuccess( stateSnapshot, duration )- 我记录了处决地点 成功解决.logTimeout( stateSnapshot, duration, error )- 我记录到一个很长的时间 运行中的执行已明确在错误中超时.
这个 stateSnapshot 对象传递到 Monitor 方法(以及
AbstractLoggingMonitor logEvent() 方法) 包含识别和计量
关于利用国家为断路器提供动力的信息。 由于一个电路
断路器可以和另一个断路器共享状态,在
因此,国家成为有意义的国家
用于伐木和监测的信息。 每个 stateSnapshot 默认提供的
采用下列结构:
{
"id": "Circuit Breaker for API",
"closed": true,
"settings": {
"requestTimeout": 0,
"volumeThreshold": 0,
"failureThreshold": 0,
"activeThreshold": 0
},
"metrics": {
"emit": 0,
"execute": 0,
"success": 0,
"failure": 0,
"timeout": 0
},
"totalMetrics": {
"emit": 0,
"execute": 0,
"success": 0,
"failure": 0,
"timeout": 0
},
"current": {
"activeRequestCount": 0
}
}
建设你自己 State 执行情况
电路断路器被设计成由多个不同类别组成的复合体
共同努力实现一个目标。 这种构成的原因是允许
如果需要,将设计自定义执行。 理想的,如果你想习惯
执行,你应该提供的唯一类是 State 课。 这个
CircuitBreaker 类管理控制流;但是,它使用 State 执行
使控制流动的力量。 如果你想提供自己的 State 执行,你
必须提供一种能暴露以下方法的类:
canPerformHealthCheck()getSnapshot()isOpened()isClosed()getTimeout()trackExecute()trackEmit()trackFailure( duration, error )trackFallbackEmit()trackFallbackFailure( error )trackFallbackMissing()trackFallbackSuccess()trackShortCircuited( error )trackSuccess( duration )trackTimeout( duration, error )
这些方法中你的行为完全由你决定。 但是,它们必须存在
页:1 CircuitBreaker 会打电话给他们。 用于控制
CircuitBreaker 根据这项计划:
- 顶级
execute*()方法被称为. - 打电话
trackEmit()。 。 。 . - 检查是否
isOpened()。 。 。 . - 如果打开 :
-
- 检查是否
canPerformHealthCheck()
- 检查是否
-
-
- 如果能够进行健康检查,则执行.
-
- 如果能够执行命令 :
-
- 打电话
trackExecute()。 。 。 .
- 打电话
-
- 使用设置超时计时器
getTimeout()。 。 。 .
- 使用设置超时计时器
-
- 启动基本命令.
- 关于决议:
-
- 打电话
trackSuccess()。 。 。 .
- 打电话
- 关于拒绝:
-
- 检查出错类型 :
-
-
- 若为
OpenError调用trackShortCircuited()。 。 。 .
- 若为
-
-
-
- 若为
TimeoutError调用trackTimeout()。 。 。 .
- 若为
-
-
-
- 否则打电话
trackFailure()。 。 。 .
- 否则打电话
-
-
- 打电话
trackFallbackEmit()。 。 。 .
- 打电话
-
- 检查是否提供了倒计时(当地或全球) .
-
-
- 如果提供退后:
-
-
-
-
- 执行倒计时.
-
-
-
-
-
- 关于决议:
-
-
-
-
-
-
- 打电话
trackFallbackSuccess()。 。 。 .
- 打电话
-
-
-
-
-
-
- 关于拒绝:
-
-
-
-
-
-
- 打电话
trackFallbackFailure()。 。 。 .
- 打电话
-
-
-
-
-
- 如不提供回扣:
-
-
-
-
- 打电话
trackFallbackMissing()。 。 。 .
- 打电话
-
-
一旦你习惯了 State ,您可以构建一个 CircuitBreaker数字 :
var CircuitBreaker = require( "@bennadel/circuit-breaker" ).CircuitBreaker;
var state = new CustomStateImplementation();
var circuitBreaker = new CircuitBreaker( state [, globalFallback] );
围绕同步状态跟踪的保证
由于电路断路器 生成并返回承诺 围绕执行黑色 -
框式命令,许多方法 State 将引用实例
一个同步。 然而,以下一系列方法是: 保证可以援引
同步 在节点.js事件回路的同一勾选内 :
trackEmit()isOpened()canPerformHealthCheck()- 只有在isOpened()返回时true。 。 。 .trackExecute()
由于Node.js运行在一个单一的过程中,你可以假设这四种方法将是 没有任何种族条件.
所有计量应该存储在记忆中
如果你正在建造自己的 State 执行中,您可能会尝试共享度量衡
跨越不同的节点.js进程(或机器). 例如,你可能会被诱惑
在共享的 Redis 实例中存储可消耗的度量衡是每个实例
代表单一资源的断路器. 不要这样做。不仅
需要断路器 State 同步运行的方法;但是,试图共享状态
没有提供真正的增值。 由于故障跟踪基于 百分比共享
状态不会使百分比更准确。 事实上,跨进程共享状态
如果某一程序或机器出现问题(例如:
作为不影响其他进程或机器的配置问题).
软件包导出
此断路器包输出以下公共成员:
OpenErrorStateErrorTimeoutErrorMetricsAbstractLoggingMonitorMonitorStateCircuitBreakerCircuitBreakerFactory