您好,欢迎访问一九零五行业门户网

深入浅析Node.js中的断路器机制

本篇文章带大家了解一下node.js中的断路器机制,希望对大家有所帮助!
架构演变带来的问题当我们使用传统的 cs 架构时,服务端由于故障等原因将请求堵塞,可能会导致客户端的请求失去响应,进而在一段时间后导致一批用户无法获得服务。而这种情况可能影响范围是有限,可以预估的。
然而,在微服务体系下,您的服务器可能依赖了若干其他微服务,而这些微服务又依赖其它更多的微服务,这种情况下,某个服务对于下游的堵塞,可能会瞬间(数秒内)因为级联的资源消耗造成整条链路上灾难性的后果,我们称之为“服务血崩”。【推荐学习:《nodejs 教程》】
解决问题的几种方式熔断模式:顾名思义,就如同家用电路一样,如果一条线路电压过高,保险丝会熔断,防止火灾。在使用熔断模式的系统中,如果发现上游服务调用慢,或者有大量超时的时候,直接中止对于该服务的调用,直接返回信息,快速释放资源。直至上游服务好转时再恢复调用。
隔离模式:将不同的资源或者服务的调用分割成几个不同的请求池,一个池子的资源被耗尽并不会影响其它资源的请求,防止某个单点的故障消耗完全部的资源。这是非常传统的一种容灾设计。限流模式:熔断和隔离都是一种事后处置的方式,限流模式则可以在问题出现之前降低问题出现的概率。限流模式可以对某些服务的请求设置一个最高的 qps 阈值,超出阈值的请求直接返回,不再占用资源处理。但是限流模式,并不能解决服务血崩的问题,因为往往引起血崩并不是因为请求的数量大,而是因为多个级联层数的放大。断路器的机制和实现断路器的存在,相当于给了我们一层保障,在调用稳定性欠佳,或者说很可能会调用失败的服务和资源时,断路器可以监视这些错误并且在达到一定阈值之后让请求失败,防止过度消耗资源。并且,断路器还拥有自动识别服务状态并恢复的功能,当上游服务恢复正常时,断路器可以自动判断并恢复正常请求。
让我们看一下一个没有断路器的请求过程: 用户依赖 servicea 来提供服务,servicea 又依赖 serviceb 提供的服务,假设 serviceb 此时出现了故障,在 10 分钟内,对于每个请求都会延迟 10 秒响应。
那么假设我们有 n 个 user 在请求 servicea 的服务时,几秒钟内,servicea 的资源就会因为对 serviceb 发起的请求被挂起而消耗一空,从而拒绝 user 之后的任何请求。对于用户来说,这就等于 servicea 和 serviceb 同时都出现了故障,引起了整条服务链路的崩溃。
而当我们在 servicea 上装上一个断路器后会怎么样呢?
断路器在失败次数达到一定阈值后会发现对 serviceb 的请求已经无效,那么此时 servicea 就不需要继续对 serviceb 进行请求,而是直接返回失败,或者使用其他fallback 的备份数据。此时,断路器处于 开路 状态。
在一段时间过后,断路器会开始定时查询 serviceb 是否已经恢复,此时,断路器处于 半开 状态。
如果 serviceb 已经恢复,那么断路器会置于 关闭 状态,此时 servicea 会正常调用 serviceb 并且返回结果。
断路器的状态图如下:
由此可见,断路器的几个核心要点如下:
超时时间:请求达到多久,算引起了一次失败
失败阈值:即断路器触发开路之前,需要达到的失败次数
重试超时:当断路器处于开路状态后,隔多久开始重新尝试请求,即进入半开状态
有了这些知识,我们可以尝试创建一个断路器:
class circuitbreaker { constructor(timeout, failurethreshold, retrytimeperiod) { // we start in a closed state hoping that everything is fine this.state = 'closed'; // number of failures we receive from the depended service before we change the state to 'open' this.failurethreshold = failurethreshold; // timeout for the api request. this.timeout = timeout; // time period after which a fresh request be made to the dependent // service to check if service is up. this.retrytimeperiod = retrytimeperiod; this.lastfailuretime = null; this.failurecount = 0; }}
构造断路器的状态机:
async call(urltocall) { // determine the current state of the circuit. this.setstate(); switch (this.state) { case 'open': // return cached response if no the circuit is in open state return { data: 'this is stale response' }; // make the api request if the circuit is not open case 'half-open': case 'closed': try { const response = await axios({ url: urltocall, timeout: this.timeout, method: 'get', }); // yay!! the api responded fine. lets reset everything. this.reset(); return response; } catch (err) { // uh-oh!! the call still failed. lets update that in our records. this.recordfailure(); throw new error(err); } default: console.log('this state should never be reached'); return 'unexpected state in the state machine'; } }
补充剩余功能:
// reset all the parameters to the initial state when circuit is initialized reset() { this.failurecount = 0; this.lastfailuretime = null; this.state = 'closed'; } // set the current state of our circuit breaker. setstate() { if (this.failurecount > this.failurethreshold) { if ((date.now() - this.lastfailuretime) > this.retrytimeperiod) { this.state = 'half-open'; } else { this.state = 'open'; } } else { this.state = 'closed'; } } recordfailure() { this.failurecount += 1; this.lastfailuretime = date.now(); }
使用断路器时,只需要将请求包裹在断路器实例中的 call 方法里调用即可:
...const circuitbreaker = new circuitbreaker(3000, 5, 2000);const response = await circuitbreaker.call('http://0.0.0.0:8000/flakycall');
成熟的 node.js 断路器库red hat 很早就创建了一个名叫 opossum 的成熟 node.js 断路器实现,链接在此:opossum 。对于分布式系统来说,使用这个库可以极大提升你的服务的容错能力,从根本上解决服务血崩的问题。
原文地址:https://juejin.cn/post/7019217344601948173
作者:es2049 / 寻找奇点
更多编程相关知识,请访问:编程视频!!
以上就是深入浅析node.js中的断路器机制的详细内容。
其它类似信息

推荐信息