JavaScript负鼠中的断路器

A request could hog up your resource from 30 to 120 seconds if it isn't given a response. In a 2 tier architecture of a client and server, this might not be as disastrous, but if your server relies on many other microservice which in turn depend on other microservices this persistent connection can cascadingly consume resource across your network. This catastrophic cascade could be easily saved by Circuit Breaker pattern.

如果请求未得到响应,则请求会将您的资源从30秒增加到120秒 。 在客户端和服务器的2层体系结构中,这可能不会造成灾难性的后果,但是,如果您的服务器依赖于许多其他微服务,而这些微服务又依赖于其他微服务,则该持久连接可以在网络上级联消耗资源。 断路器模式可轻松保存此灾难性级联。

Broadly looking, a Circuit Breaker is a wrapper over a function that watches for errors and fails the request gracefully after a certain threshold is reached. The function also keeps a count of errors and *trips* the circuit breaker blocking further requests to call the unresponsive server. Let us dive a bit more on this.

从广义上讲,断路器是一个函数的包装,该函数监视错误并在达到特定阈值后优雅地使请求失败。 该功能还保留错误计数,并且“跳闸”断路器阻止进一步的请求以调用无响应的服务器。 让我们进一步探讨一下。

断路:了解负鼠库 (Circuit Breaking: Understanding Opossum library)

Image for post

初始变量 (Initial variables)

// snippet from line 54-67 and 170-173
//https://github.com/nodeshift/opossum/blob/bd59b4860ce412608c520c757af1bf2b9398577b/lib/status.js#L146// number of buckets in which the CB window should be divided this[BUCKETS] = options.rollingCountBuckets; // DEFAULT: 10// window length of the CBthis[TIMEOUT] = options.rollingCountTimeout; // DEFAULT: 10000// Bucket where all the calculations will be storedthis[WINDOW] = new Array(this[BUCKETS]); //QUEUE datastructure// rotating interval for the bucketconst bucketInterval = Math.floor(this[TIMEOUT] / this[BUCKETS]);// rotate the window bucketthis[BUCKET_INTERVAL] = setInterval(nextBucket(this[WINDOW]), bucketInterval);// rotating logicconst nextBucket = window => _ => { window.pop(); window.unshift(bucket());};

Here are the key points of the code1. Make a WINDOW with 10 buckets2. Rotate the bucket every 1 second3. Queue initializing variables (default variables of opossum) to WINDOW and dequeue the oldest value4. Store the interval reference in a variable for further use

这是code1的重点。 制作一个包含10个存储桶的WINDOW。2.每1秒钟 旋转存储桶3.将初始化变量( opossum的默认变量 )排队到WINDOW并取出最旧的值4。 将区间参考存储在变量中以备将来使用

负鼠射击 (Firing in Opossum)

//very very very stripped down overview of call function line 442https://github.com/nodeshift/opossum/blob/master/lib/circuit.jscall (context, ...rest) {
//emit('fire');if (CACHE.get(this) !== undefined) {
// emit('cacheHit') and return cache value
} else if (this.options.cache) {
// emit('cacheMiss');
}if (!this.closed && !this.pendingClose) {
// CB is closed emit('reject', error);
}
// emit ('success') if done
// emit ('timeout') if not done
// emit ('failure') if not done }

The following key points happen in the code.1. emit the fire event as soon as we enter the function2. If caching is enabled and we hit the cache we return the cached value3. If we miss the cache emit the cacheMiss event4. If the circuit breaker is not closed emit the rejected event5. If the function succeeds, increase the succeed counter for the current window.6. If a timeout or failure occurs emit the failure and timeout event,

以下关键点发生在代码中1。 进入function2时立即发出fire事件。 如果启用了缓存并且我们命中了缓存,则返回缓存的value3。 如果我们错过了缓存,则发出cacheMiss event4。 如果断路器未关闭,则发出被拒绝的事件5。 如果函数成功执行,请增加当前窗口的成功计数器6。 如果发生超时或故障,则发出故障和超时事件,

收集窗口统计 (Gathering Window Statistics)

//copied from line 93
// https://github.com/nodeshift/opossum/blob/master/lib/circuit.js// Function that return the default values for a bucket
const bucket = _ => ({
failures: 0,
fallbacks: 0,
successes: 0,
rejects: 0,
fires: 0,
timeouts: 0,
cacheHits: 0,
cacheMisses: 0,
semaphoreRejections: 0,
percentiles: {},
latencyTimes: []});get stats () {
const totals = this[WINDOW].reduce((acc, val) => {
if (!val) { return acc; }
Object.keys(acc).forEach(key => (acc[key] += val[key] || 0));
return acc;
}, bucket());return totals;
}

Requesting for statistics form opossum makes aggregates the statistic from the bucket that has been set by the rollingCountBuckets option. It just adds all the value in the window and returns a single object with all the sum.

请求以负数形式进行统计,将汇总由rollingCountBuckets选项设置的存储桶中的统计信息。 它只是将窗口中的所有值相加,并返回包含所有和的单个对象。

失败 (Failing)

//this code looks almost same lol from line 678 -703https://github.com/nodeshift/opossum/blob/master/lib/circuit.jsfunction fail (circuit, err, args, latency) {circuit.emit('failure');const stats = circuit.stats;
if ((stats.fires < circuit.volumeThreshold) && !circuit.halfOpen) return;
const errorRate = stats.failures / stats.fires * 100;
if (errorRate > circuit.options.errorThresholdPercentage ||
circuit.halfOpen) {
circuit.open();
}
}

When the code fails we ask from stats() and check if the error rate is less than the threshold set by us. If the threshold is crossed we open the circuit breaker. Which then emits the ‘open’ event.

当代码失败时,我们从stats()询问并检查错误率是否小于我们设置的阈值。 如果超过阈值,则打开断路器。 然后发出“打开”事件。

半开 (Half opening)

//again a little stripped down code from line 178 -197https://github.com/nodeshift/opossum/blob/master/lib/circuit.jsfunction _startTimer (circuit) {
return _ => {
const timer = circuit[RESET_TIMEOUT] = setTimeout(() => {
circuit[STATE] = HALF_OPEN;
circuit[PENDING_CLOSE] = true;
circuit.emit('halfOpen', circuit.options.resetTimeout);
}, circuit.options.resetTimeout);};
}this.on('open', _startTimer(this));
this.on('success', _ => {
if (this.halfOpen) {
this.close();
}
});
}

Half opening if the state when the circuit breaker tries to revive. Here we listen for the open event and starts a timer as soon as the event is fire. After the timeout completes we check if the changes the state of the circuit breaker to half-open. If the call succeeds we close the circuit breaker and reset all the values.

断路器试图恢复时的状态为半开。 在这里,我们监听打开事件,并在事件触发后立即启动计时器。 超时完成后,我们检查是否将断路器的状态更改为半开状态。 如果调用成功,则合上断路器并重置所有值。

TLDR:断路器 (TLDR: Circuit Breaker)

Image for post

A circuit breaker revolves between 3 states:Closed: When the circuit breaker is functioning normally.Open: When the circuit breaker has tripped. Half Open: When the circuit breaker tries to recover.

断路器在3种状态之间旋转: 闭合:断路器正常工作时。 开路:断路器跳闸时。 半开:断路器尝试恢复时。

The execution of the events are as follows:1: The breaker remains closed as long as the events are successful.2. Increase the number of error count in the window as soon as a call timeouts or fails.3. If the threshold of errors in the window increases a certain limit then we trip the circuit breaker.4. After a certain interval, the circuit breaker tries to recover and enters the half-open state.5. If the subsequent call fails the circuit breaker goes back to open state.6. If the subsequent call succeeds the circuit breaker goes to the open state.

事件的执行过程如下:1:只要事件成功,断路器就保持闭合状态。2。 一旦呼叫超时或失败,增加窗口中的错误计数数量。3。 如果窗口中的错误阈值增加了某个极限,则我们使断路器跳闸4。 在一定间隔后,断路器将尝试恢复并进入半开状态5。 如果后续呼叫失败,则断路器将返回到打开状态6。 如果后续调用成功,则断路器将进入断开状态。

在JavaScript项目中使用负鼠 (Using Opossum in your JavaScript Project)

const CircuitBreaker = require('opossum');
function asyncFunctionThatCouldFail (x, y) {
return new Promise((resolve, reject) => {
// Do something, maybe on the network or a disk
});
}
const options = {
timeout: 3000, // If our function takes longer than 3 seconds, trigger a failure
errorThresholdPercentage: 50, // When 50% of requests fail, trip the circuit
resetTimeout: 30000 // After 30 seconds, try again.
};const breaker = new CircuitBreaker(asyncFunctionThatCouldFail, options);
breaker.fire(params)
.then(console.log)
.catch(console.error);

Footnote: Every npm install is a cost added to your server’s memory and CPU utilization. Deeply understanding the library you install can not only help you save on the cost but also find bottlenecks and let you use the library effectively.

脚注:每次npm install都会增加服务器内存和CPU利用率。 深入了解所安装的库不仅可以帮助您节省成本,还可以找到瓶颈,并让您有效地使用库。

普通英语JavaScript (JavaScript In Plain English)

Did you know that we have three publications and a YouTube channel? Find links to everything at plainenglish.io!

您知道我们有三个出版物和一个YouTube频道吗? 在plainenglish.io上找到所有内容的链接!

翻译自: https://medium.com/@aesher9o1/circuit-breakers-in-javascript-opossum-bcd65c2ce9bd

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值