当对 React 应用进行页面加载或 SEO 优化时,我们一般绕不开 React SSR。但 React SSR 毕竟涉及到了服务端,有很多服务端特有的问题需要考虑,而限流就是其中之一。
所谓限流,就是当我们的服务资源有限、处理能力有限时,通过对请求或并发数进行限制从而保障系统正常运行的一种策略。本文会通过一个简单的案例来说明,为什么服务端需要进行限流。
如下所示是一个简单的 nodejs 服务端项目:
1 | const express = require('express') |
其中,我们通过 Buffer
来模拟 SSR 过程会大量的占用内存的情况。
然后,通过 docker build -t ssr .
指定将我们的项目打包成一个镜像,并通过以下命令运行一个容器:
1 | docker run \ |
我们将容器内存限制在 512m,并通过 --oom-kill-disable
指定容器内存不足时不关闭容器。
接下来,我们通过 autocannon
来进行一下压测:
1 | autocannon -c 10 -d 1000 http://localhost:2048 |
通过,docker stats
可以看到容器的运行情况:
1 | CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS |
此时,容器内存已经全部被占用,服务对外失去了响应,通过 curl -m 5 http://localhost:2048
访问,收到了超时的错误提示:
1 | curl: (28) Operation timed out after 5001 milliseconds with 0 bytes received |
我们改造一下代码,使用 sliding-window-counter
来统计 QPS,并限制为 2:
1 | const express = require('express') |
此时,容器运行正常:
1 | CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS |
虽然此时访问 /
路由会收到错误:
1 | curl -m 5 http://localhost:2048 |
但是 /another
却不受影响:
1 | curl -m 5 http://localhost:2048/another |
由此可见,限流确实是系统进行自我保护的一个比较好的方法。不过当 QPS 超过限流值时返回错误给用户不太好,如果此时可以降级到 CSR 就完美了,这里暂时就不讨论了。