Open ChuChencheng opened 2 years ago
有关限流的知识可以参考 5 种限流算法,7 种限流方式,挡住突发流量?
https://github.com/nestjs/throttler/blob/v3.0.0/src/throttler.guard.ts#L77
核心代码应该是这行开始了, Guard 中的 handleRequest
handleRequest
https://github.com/nestjs/throttler/blob/v3.0.0/src/throttler.service.ts#L17
以及 ThrottlerStorageService 的 addRecord 方法
ThrottlerStorageService
addRecord
const ttls = await this.storageService.getRecord(key); const nearestExpiryTime = ttls.length > 0 ? Math.ceil((ttls[0] - Date.now()) / 1000) : 0; // Throw an error when the user reached their limit. if (ttls.length >= limit) { res.header('Retry-After', nearestExpiryTime); this.throwThrottlingException(context); }
当 ttls.length 大于等于 limit (ttl 中允许的请求数量,如果 ttl 是 1秒 ,则 limit 就是 QPS 的意思),则会被限流。
ttls.length
那么, ttls 里面存放的东西就很关键
ttls
深入 ThrottlerStorageService 的 addRecord 方法,可以看到 ttls 数组存的是什么
const ttlMilliseconds = ttl * 1000; if (!this.storage[key]) { this.storage[key] = []; } this.storage[key].push(Date.now() + ttlMilliseconds);
从代码中可以看出, ttls 存的是请求过期的时间点
也就是说,当一个请求过来,会往 ttls 数组中 push 一个时间点,代表到这个时间点之后,允许多放行一个新的请求。
知道了 ttls 存放的是时间点,那么假设一位用户被限流了,他想知道多久后才会解除限流,就可以从 ttls 数组中得到这个信息,只需要取数组的第一项,减去现在的时间。
const nearestExpiryTime = ttls.length > 0 ? Math.ceil((ttls[0] - Date.now()) / 1000) : 0;
NestJS 自带限流其实就是采用滑动日志的方式。
优点就是限流比较精确,可以防止流量突刺
缺点也很明显,比较占用内存,假设 ttl 为 1 ,限制 QPS 为 1000 , ttls 最大就会有 1000 个元素
在 addRecord 中, ttls 数组是通过 setTimeout 的方式去清理的,那么 ttls 有多少个元素,就会有多少个 setTimeout 在排队
setTimeout
本来是想着把 setTimeout 给优化掉,但是好像意义并不大,因为这种限流算法本来就是一种用空间妥协换取限流精确度的做法。
背景
有关限流的知识可以参考 5 种限流算法,7 种限流方式,挡住突发流量?
代码地址
https://github.com/nestjs/throttler/blob/v3.0.0/src/throttler.guard.ts#L77
核心代码应该是这行开始了, Guard 中的
handleRequest
https://github.com/nestjs/throttler/blob/v3.0.0/src/throttler.service.ts#L17
以及
ThrottlerStorageService
的addRecord
方法代码分析
ThrottlerGuard
当
ttls.length
大于等于 limit (ttl 中允许的请求数量,如果 ttl 是 1秒 ,则 limit 就是 QPS 的意思),则会被限流。那么,
ttls
里面存放的东西就很关键ThrottlerStorageService
深入
ThrottlerStorageService
的addRecord
方法,可以看到ttls
数组存的是什么从代码中可以看出,
ttls
存的是请求过期的时间点也就是说,当一个请求过来,会往
ttls
数组中 push 一个时间点,代表到这个时间点之后,允许多放行一个新的请求。还有多久可以放行请求
知道了
ttls
存放的是时间点,那么假设一位用户被限流了,他想知道多久后才会解除限流,就可以从ttls
数组中得到这个信息,只需要取数组的第一项,减去现在的时间。优缺点
NestJS 自带限流其实就是采用滑动日志的方式。
优点
优点就是限流比较精确,可以防止流量突刺
缺点
缺点也很明显,比较占用内存,假设 ttl 为 1 ,限制 QPS 为 1000 ,
ttls
最大就会有 1000 个元素在
addRecord
中,ttls
数组是通过setTimeout
的方式去清理的,那么ttls
有多少个元素,就会有多少个setTimeout
在排队优化
本来是想着把
setTimeout
给优化掉,但是好像意义并不大,因为这种限流算法本来就是一种用空间妥协换取限流精确度的做法。