nodejs 过载保护

| 导语 过载保护对于to c业务的服务来讲是很是重要的。试想一下,若是有一个运营活动或者特殊的日子致使流量暴增,用户每秒请求数远远超出了咱们的服务所能处理的最大值,假如咱们没有作过载保护,很快这个服务所能利用的资源将会被耗尽,没法处理任何请求,若是这个服务所在机器的其余服务没有和这个服务资源隔离,也会影响到其余正常的服务,那么一次严重的事故就发生了。node

什么是过载保护

过载

什么是过载? 简单来讲,就是当前负载超过了系统的最大处理能力,如:git

系统实际每秒能处理的请求量为1000个,但实际每秒的请求量却远大于1000个,能够断定系统过载。github

过载保护

对于web应用,就是对请求量的控制问题,控制请求量不要超过系统的最大处理能力。web

过载保护怎么作

经过请求数计数控制

直接的作法就是控制当前服务同时处理的请求数,这个很好控制,请求来一个就计数+1, 处理完请求回包就减1,若是当前在处理的请求总数超过了设置的最大值,那么就直接回包503错误。 nodejs koa 代码实现:算法

// 写一个中间件 overloadProtection.js
const maxCount = 1000;
let totalCount = 0;

moudle.exports = async(ctx, next) => {
	totalCount += 1;
	 // TODO 这里能够加一些监控上报
	 
	if (totalCount > maxCount) {  // 直接丢弃
		ctx.status = 503;
		ctx.body = 'Service heavy load!!!';
		return;
	}
	await next();
	totalCount -= 1;
}
复制代码

而后koa 服务在最开始的时候使用这个中间件便可。api

这种方法有个前提条件: 必需要知道这个服务同时能处理的最大请求数(maxCount),通常状况下这个服务会有多个api,处理每一个api请求所消耗的资源可能不同,咱们很难模拟真实场景获得准确的maxCount。你若是想说咱们能够限制每一个接口的最大请求数啊,并不必定要限制这个服务的最大请求数,那你就要考虑到一种极端场景,全部的接口都达到最大请求数的时候你的服务可否抗住,这可能须要更高性能或更多的服务器才能知足这种场景。bash

经过实时查cpu使用率控制请求数

在web服务的场景,CPU是服务最主要的瓶颈,因此咱们能够在处理请求以前首先判断下当前CPU负载是否达到了咱们设置的CPU最大使用率,而后丢弃或者随机丢弃。 咱们须要的是当前服务的进程占用的cpu百分比,github上找到一个 node-usage 。 稍微改造一些,思路以下: 首先node-usage,若是实时获取当前进程cpu利用率,会增长系统的负载,咱们能够本身控制采样cpu使用率的评率,获得cpu利用率。服务器

nodejs koa 代码实现:dom

// 写一个中间件 overloadProtection.js
const usage = require('usage');
const pid = process.pid;    // 当前node服务的进程pid
let sampleCpuInterval = 1000;  // 采样cpu使用率的频率
let cpuUsedLimit = 85;         // cpu使用率上限

let getCupUsed = function getCupUsed() {
        setInterval(() => {
            usage.lookup(pid, {keepHistory: true}, (err, result) => {
                if (result) {
                    global.cpuUsed = result.cpu || 0;
                }
            })
        }, sampleCpuInterval);
};

getCupUsed();

module.exports = async(ctx, next) => {
    // TODO 这里能够加一些监控上报
    if (cpuUsedLimit && global.cpuUsed > cpuUsedLimit) {
	   // 这里是随机丢弃的算法,能够思考下为何这么作
        let rejectRate = Math.pow((global.cpuUsed - cpuUsedLimit) / (100 - cpuUsedLimit), 2);
        if (Math.random() > rejectRate) {
            ctx.status = 503;
		    ctx.body = 'Service heavy load!!!';
		   return;
        }
    }
    await next();
};
复制代码

压测很顺利, 可是若是请求量特别特别大的时候,即便node服务没有作任何逻辑处理,只是简单回包cpu都能耗尽的场景下,咱们要考虑在上层或系统层作过载保护。koa

利用nodejs event-loop的机制控制请求数

github上找到一个overload-protection,使用很是容易。可是我本身压测后发下有很大问题。我我的理解做者意图以下: 处理请求以前,先设置一个setInterval, 经过计算setInterval里的回调函数执行延时来预估当前cpu负载。能够预见的是延迟越高,cpu负载越高。延迟在某个值时多是咱们指望限制的cpu最大使用率。 咱们看下源码

var xtend = require('xtend')
var EE = require('events').EventEmitter

var defaults = {
  limit: 42,   // 默认延迟是42,
  sampleInterval: 5
}

function loopbench (opts) {
  opts = xtend(defaults, opts)

  var timer = setInterval(checkLoopDelay, opts.sampleInterval)
  timer.unref()   // 参考 https://zhuanlan.zhihu.com/p/38091559

  var result = new EE();  // EventEmitter实例

  result.delay = 0
  result.sampleInterval = opts.sampleInterval
  result.limit = opts.limit
  result.stop = clearInterval.bind(null, timer)

  var last = now()

  return result

  function checkLoopDelay () {
    var toCheck = now()
    var overLimit = result.overLimit
    result.delay = toCheck - last - result.sampleInterval  // 实际执行的延时,系统负载越高(越忙)延时越大
    last = toCheck

    result.overLimit = result.delay > result.limit

    if (overLimit && !result.overLimit) {
      result.emit('unload');   // 由过载变成正常,外面监听这个事件而后告诉服务变成正常状态了,正常处理请求
    } else if (!overLimit && result.overLimit) {
      result.emit('load');     // 由正常变为过载,外面监听这个事件而后告诉服务变成过载状态了,要丢弃请求
    }
  }

  function now () {
    var ts = process.hrtime()
    return (ts[0] * 1e3) + (ts[1] / 1e6)
  }
}
复制代码

可是我持续压测了几分钟,cpu全层使用率是98%-100%,并无触发到它的过载机制,我试着打印了下 result.delay 发现特别小:

而且还有比较小的负数,我想拌一个黑人问号脸表情,整个压测过程当中只零星出现了几个503(触发过载)。不知是我压测的姿式不对仍是其余因素,这种方法宣告失败。

可是我以为做者的是思想是能够借鉴的,能够用于其余的应用场景。

总结

上面描述了过载保护的三种实践方法,前两种均可以应用于特定的场景下,第三种方法实践失败。我的认为第二种经过判断cpu实时使用率的方法,更具备通用性。

参考资料:

zhuanlan.zhihu.com/p/30342671

github.com/arunoda/nod…

github.com/davidmarkcl…

zhuanlan.zhihu.com/p/38091559

本文首发在掘金转载请注明原做者,若是你以为这篇文章对你有帮助或启发,也能够来请我喝咖啡。 利益相关:本篇文章全部涉及到的软件均为笔者平常所用工具,无任何广告费用。

相关文章
相关标签/搜索