React SSR 之为什么要进行限流
source link: https://www.fly63.com/article/detial/11717
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
扫一扫分享
当对 react 应用进行页面加载或 seo 优化时,我们一般绕不开 React SSR。但 React SSR 毕竟涉及到了服务端,有很多服务端特有的问题需要考虑,而限流就是其中之一。
所谓限流,就是当我们的服务资源有限、处理能力有限时,通过对请求或并发数进行限制从而保障系统正常运行的一种策略。本文会通过一个简单的案例来说明,为什么服务端需要进行限流。
如下所示是一个简单的 nodejs 服务端项目:
const express = require('express')
const counter = require('./counter')
const app = express()
app.get('/', async (req, res) => {
// 模拟 SSR 会大量的占用内存
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)
})
其中,我们通过 Buffer 来模拟 SSR 过程会大量的占用内存的情况。
然后,通过 docker build -t ssr . 指定将我们的项目打包成一个镜像,并通过以下命令运行一个容器:
docker run \
-it \
-m 512m \ # 限制容器的内存
--rm \
-p 2048:2048 \
--name ssr \
--oom-kill-disable \
ssr
我们将容器内存限制在 512m,并通过 --oom-kill-disable 指定容器内存不足时不关闭容器。
接下来,我们通过 autocannon 来进行一下压测:
autocannon -c 10 -d 1000 http://localhost:2048
通过, docker stats 可以看到容器的运行情况:
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
此时,容器内存已经全部被占用,服务对外失去了响应,通过 curl -m 5 http://localhost:2048 访问,收到了超时的错误提示:
curl: (28) Operation timed out after 5001 milliseconds with 0 bytes received
我们改造一下代码,使用 sliding-window-counter 来统计 QPS,并限制为 2:
const express = require('express')
const counter = require('sliding-window-counter')
const app = express()
const limit = 2
let cnt = counter(1000)
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)
})
此时,容器运行正常:
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
虽然此时访问 / 路由会收到错误:
curl -m 5 http://localhost:2048
exceed limit
但是 /another 却不受影响:
curl -m 5 http://localhost:2048/another
another api
由此可见,限流确实是系统进行自我保护的一个比较好的方法。不过当 QPS 超过限流值时返回错误给用户不太好,如果此时可以降级到 CSR 就完美了,这里暂时就不讨论了。
来自:http://www.paradeto.com/2022/06/12/react-ssr-rate-limit/
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK