成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

解析React SSR 中的限流案例

3403771864 / 502人閱讀

  本篇文章主要為大家講述關(guān)于ReactSSR之限流,其實(shí)我們都知道React SSR是涉及到服務(wù)端的,因此,我們先需要考慮到很多的服務(wù)器端問(wèn)題,下面就為大家舉例說(shuō)明。

  當(dāng)簡(jiǎn)單來(lái)說(shuō), React 的應(yīng)用進(jìn)行頁(yè)面加載或 SEO 優(yōu)化時(shí),都會(huì)想到React SSR。也就會(huì)想到服務(wù)器端,這是必須考慮到的。

  現(xiàn)在我們來(lái)說(shuō)下所謂限流,其實(shí)是在我們的服務(wù)資源有限、處理能力有限時(shí),通過(guò)對(duì)請(qǐng)求或并發(fā)數(shù)進(jìn)行限制從而保障系統(tǒng)正常運(yùn)行的一種策略。但為何要限流那。

  為什么要限流

  如下所示是一個(gè)簡(jiǎn)單的 nodejs 服務(wù)端項(xiàng)目:

  const express = require('express')
  const app = express()
  app.get('/', async (req, res) => {
  // 模擬 SSR 會(huì)大量的占用內(nèi)存
  const buf = Buffer.alloc(1024 * 1024 * 200, 'a')
  console.log(buf)
  res.end('end')
  })
  app.get('/another', async (req, res) => {
  res.end('another api')
  })
  const listener = app.listen(process.env.PORT || 2048, () => {
  console.log('Your app is listening on port ' + listener.address().port)
  })

  其中,我們通過(guò)Buffer來(lái)模擬 SSR 過(guò)程會(huì)大量的占用內(nèi)存的情況。

  然后,通過(guò)docker build -t ssr .指定將我們的項(xiàng)目打包成一個(gè)鏡像,并通過(guò)以下命令運(yùn)行一個(gè)容器:

  docker run \
  -it \
  -m 512m \ # 限制容器的內(nèi)存
  --rm \
  -p 2048:2048 \
  --name ssr \
  --oom-kill-disable \
  ssr

  我們將容器內(nèi)存限制在 512m,并通過(guò)--oom-kill-disable指定容器內(nèi)存不足時(shí)不關(guān)閉容器。

  接下來(lái),我們通過(guò)autocannon來(lái)進(jìn)行一下壓測(cè):

  autocannon -c 10 -d 1000 http://localhost:2048

  通過(guò),docker stats可以看到容器的運(yùn)行情況:

  CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
  d9c0189e2b56 ssr 0.00% 512MiB / 512MiB 99.99% 14.6kB / 8.65kB 41.9MB / 2.81MB 40

  此時(shí),容器內(nèi)存已經(jīng)全部被占用,服務(wù)對(duì)外失去了響應(yīng),通過(guò)curl -m 5 http://localhost:2048訪問(wèn),收到了超時(shí)的錯(cuò)誤提示:

  curl: (28) Operation timed out after 5001 milliseconds with 0 bytes received

  我們改造一下代碼,使用counter.js來(lái)統(tǒng)計(jì) QPS,并限制為 2:

  const express = require('express')
  const counter = require('./counter.js')
  const app = express()
  const limit = 2
  let cnt = counter()
  app.get(
  '/',
  (req, res, next) => {
  cnt(1)
  if (cnt() > limit) {
  res.writeHead(500, {
  'content-type': 'text/pain',
  })
  res.end('exceed limit')
  return
  }
  next()
  },
  async (req, res) => {
  const buf = Buffer.alloc(1024 * 1024 * 200, 'a')
  console.log(buf)
  res.end('end')
  }
  )
  app.get('/another', async (req, res) => {
  res.end('another api')
  })
  const listener = app.listen(process.env.PORT || 2048, () => {
  console.log('Your app is listening on port ' + listener.address().port)
  })
  // counter.js
  module.exports = function counter(interval = 1000) {
  let arr = []
  return function cnt(number) {
  const now = Date.now()
  if (number > 0) {
  arr.push({
  time: now,
  value: number,
  })
  const newArr = []
  // 刪除超出一秒的數(shù)據(jù)
  for (let i = 0, len = arr.length; i < len; i++) {
  if (now - arr[i].time > interval) continue
  newArr.push(arr[i])
  }
  arr = newArr
  return
  }
  // 計(jì)算前一秒的數(shù)據(jù)和
  let sum = 0
  for (let i = arr.length - 1; i >= 0; i--) {
  const {time, value} = arr[i]
  if (now - time <= interval) {
  sum += value
  continue
  }
  break
  }
  return sum
  }
  }

  此時(shí),容器運(yùn)行正常:

  CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
  3bd5aa07a3a7 ssr 88.29% 203.1MiB / 512MiB 39.67% 24.5MB / 48.6MB 122MB / 2.81MB 40

  雖然此時(shí)訪問(wèn)/路由會(huì)收到錯(cuò)誤:

  curl -m 5 http://localhost:2048
  exceed limit

  但是/another卻不受影響:

  curl -m 5 http://localhost:2048/another
  another api

  由此可見(jiàn),限流確實(shí)是系統(tǒng)進(jìn)行自我保護(hù)的一個(gè)比較好的方法。

  令牌桶算法

  常見(jiàn)的限流算法有“滑動(dòng)窗口算法”、“令牌桶算法”,我們這里討論“令牌桶算法”。在令牌桶算法中,存在一個(gè)桶,容量為burst。該算法以一定的速率(設(shè)為rate)往桶中放入令牌,超過(guò)桶容量會(huì)丟棄。每次請(qǐng)求需要先獲取到桶中的令牌才能繼續(xù)執(zhí)行,否則拒絕。根據(jù)令牌桶的定義,我們實(shí)現(xiàn)令牌桶算法如下:

  export default class TokenBucket {
  private burst: number
  private rate: number
  private lastFilled: number
  private tokens: number
  constructor(burst: number, rate: number) {
  this.burst = burst
  this.rate = rate
  this.lastFilled = Date.now()
  this.tokens = burst
  }
  setBurst(burst: number) {
  this.burst = burst
  return this
  }
  setRate(rate: number) {
  this.rate = rate
  return this
  }
  take() {
  this.refill()
  if (this.tokens > 0) {
  this.tokens -= 1
  return true
  }
  return false
  }
  refill() {
  const now = Date.now()
  const elapse = now - this.lastFilled
  this.tokens = Math.min(this.burst, this.tokens + elapse * (this.rate / 1000))
  this.lastFilled = now
  }
  }

  然后,按照如下方式使用:

  const tokenBucket = new TokenBucket(5, 10)
  if (tokenBucket.take()) {
  // Do something
  } else {
  // refuse
  }

  簡(jiǎn)單解釋一下這個(gè)算法,調(diào)用take時(shí),會(huì)先執(zhí)行refill先往桶中進(jìn)行填充。填充的方式也很簡(jiǎn)單,首先計(jì)算出與上次填充的時(shí)間間隔elapse毫秒,然后計(jì)算出這段時(shí)間內(nèi)應(yīng)該補(bǔ)充的令牌數(shù),因?yàn)榱钆蒲a(bǔ)充速率是rate個(gè)/秒,所以需要補(bǔ)充的令牌數(shù)為:

  elapse * (this.rate / 1000)

  又因?yàn)榱钆茢?shù)不能超過(guò)桶的容量,所以補(bǔ)充后桶中的令牌數(shù)為:

  Math.min(this.burst, this.tokens + elapse * (this.rate / 1000))

  注意,這個(gè)令牌數(shù)是可以為小數(shù)的。

  令牌桶算法具有以下兩個(gè)特點(diǎn):

  當(dāng)外部請(qǐng)求的 QPSM大于令牌補(bǔ)充的速率rate時(shí),長(zhǎng)期來(lái)看,最終有效的 QPS 會(huì)趨向于rate。這個(gè)很好理解,拉的總不可能比吃的多吧。

  因?yàn)榱钆仆翱梢源嫦耣urst個(gè)令牌,所以可以允許短時(shí)間的激增流量,持續(xù)的時(shí)間為:

  T = burst / (M - rate) // rate < M

  可以理解為一個(gè)水池里面有burst的水量,進(jìn)水的速率為rate,出水的速率為M,則凈出水速率為M-rate,則水池中的水放空的時(shí)間即為激增流量的持續(xù)時(shí)間。

     本文內(nèi)容到此都講述完畢,歡迎大家關(guān)注后續(xù)更多精彩內(nèi)容。




文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/130341.html

相關(guān)文章

  • 這個(gè)注解一次搞定限流與熔斷降級(jí):@SentinelResource

    摘要:實(shí)現(xiàn)熔斷降級(jí)注解除了可以用來(lái)做限流控制之外,還能實(shí)現(xiàn)與類似的熔斷降級(jí)策略。函數(shù)簽名要求返回值類型必須與原函數(shù)返回值類型一致方法參數(shù)列表需要為空,或者可以額外多一個(gè)類型的參數(shù)用于接收對(duì)應(yīng)的異常。若未配置和,則被限流降級(jí)時(shí)會(huì)將直接拋出。 在之前的《使用Sentinel實(shí)現(xiàn)接口限流》一文中,我們僅依靠引入Spring Cloud Alibaba對(duì)Sentinel的整合封裝spring-clo...

    Lionad-Morotar 評(píng)論0 收藏0
  • spring cloud gateway 之限流

    摘要:常見(jiàn)的限流方式,比如適用線程池隔離,超過(guò)線程池的負(fù)載,走熔斷的邏輯。在令牌桶算法中,存在一個(gè)桶,用來(lái)存放固定數(shù)量的令牌。,令牌桶每秒填充平均速率。 轉(zhuǎn)載請(qǐng)標(biāo)明出處: https://www.fangzhipeng.com本文出自方志朋的博客 在高并發(fā)的系統(tǒng)中,往往需要在系統(tǒng)中做限流,一方面是為了防止大量的請(qǐng)求使服務(wù)器過(guò)載,導(dǎo)致服務(wù)不可用,另一方面是為了防止網(wǎng)絡(luò)攻擊。 常見(jiàn)的限流方式,...

    joy968 評(píng)論0 收藏0
  • Spring Cloud Gateway 擴(kuò)展支持動(dòng)態(tài)限流

    摘要:以流量為切入點(diǎn),從流量控制熔斷降級(jí)系統(tǒng)負(fù)載保護(hù)等多個(gè)維度保護(hù)服務(wù)的穩(wěn)定性分布式系統(tǒng)的流量防衛(wèi)兵。歡迎關(guān)注我們獲得更多的好玩實(shí)踐 之前分享過(guò) 一篇 《Spring Cloud Gateway 原生的接口限流該怎么玩》, 核心是依賴Spring Cloud Gateway 默認(rèn)提供的限流過(guò)濾器來(lái)實(shí)現(xiàn) 原生RequestRateLimiter 的不足 配置方式 spring: clou...

    妤鋒シ 評(píng)論0 收藏0
  • Spring Cloud Gateway 擴(kuò)展支持動(dòng)態(tài)限流

    摘要:以流量為切入點(diǎn),從流量控制熔斷降級(jí)系統(tǒng)負(fù)載保護(hù)等多個(gè)維度保護(hù)服務(wù)的穩(wěn)定性分布式系統(tǒng)的流量防衛(wèi)兵。歡迎關(guān)注我們獲得更多的好玩實(shí)踐 之前分享過(guò) 一篇 《Spring Cloud Gateway 原生的接口限流該怎么玩》, 核心是依賴Spring Cloud Gateway 默認(rèn)提供的限流過(guò)濾器來(lái)實(shí)現(xiàn) 原生RequestRateLimiter 的不足 配置方式 spring: clou...

    beanlam 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<