Day07-流量限制(二)

前言

昨天介绍了在 Node.js 跟 Go 里面要怎麽用 middleware 来做限流,虽然看似方便,但这样做其实不是个好方法,因为限制流量并不是业务逻辑的一部分。而且如果同时开了多台机器跑 Node/Go server 做分流,因为预设情况下统计次数是储存在各 process 自己的记忆体中,在不知道其他 process 的请求数量的情况下,就没办法做到真正的限流

load balancer

所以如果你不是写个 side project 玩玩而已,而是真的要上 production,那比较好的方式是由前面的 load balancer 来做分流及限流,如果某个 IP 在时间内的流量已经超标了,那就不要再往後送到 API server,如此一来不只可以节省资源,後面的 API server 也不需要考虑流量有没有超过,反正请求来了赶快处理便是

基本的 load balancer

在众多用来做 reverse proxy 的工具中,nginx 应该是最多人在用的,所以这边先示范一下怎麽用 nginx 做简单的分流

一般来说我们要用 nginx 做分流时,会先宣告一个 upstream 叫 backend,并在里面写上可以把流量分配到哪些 server。紧接着再到 location /api 里面把所有流量都用 proxy_pass 转送到多台 API server,如此一来外来的请求就会被平均分散到各台 server 做处理

http {    
    # 告诉 nginx 有三台 API server 可以接受流量
    upstream backend {
        server 192.0.0.1:8000;
        server 192.0.0.2:8000;
        server 192.0.0.3:8000;
    }

    server {
        listen 80;
        
        location /api {
            # 把所有流量都转送到 backend 的三台 server
            proxy_pass http://backend;
        }
    }
}

加上限流

有这个基本的分流之後,要怎麽在这个设定档加上限流的功能呢?

首先要用 limit_req_zone 宣告一个新的 limiter,他这边的参数有点复杂,我稍微解释一下:

  • $binary_remote_addr 指的是 client 端的 IP,意思是我想要根据 client 端的 IP 进行限流
  • zone=limit:10m 的意思是我这个 limiter(zone) 要叫做 limit,并且最多可以使用 10MB 的 memory 来储存每个 IP 的请求次数(10MB 可以存十几万个 IP,一定够用的~)
  • rate=100r/m 还满直观的,就每分钟一百个请求。但要注意的是 nginx 会帮你换算成多少毫秒可以接受一个新请求,譬如说每分钟一百个,他就会帮你换算成 600 毫秒一个,因此如果你在 600 毫秒内同时发了十个请求,那就只有第一个会被接受,其他九个都会直接被拒绝掉

有了这个 limiter 之後,只要再到 location /api 里面用 limit_req zone=limit 把他套用上去就可以了~

http {
    # 宣告一个 limiter(zone) 叫 limit,限制每分钟最多 100 个请求
    limit_req_zone $binary_remote_addr zone=limit:10m rate=100r/m;
    
    # 拒绝请求时的 status code 用 429 Too Many Requests
    limit_req_status 429;

    server {
        location /api {
            # 把刚刚宣告好的 limit 套用到 /api 开头的请求上
            limit_req zone=limit;
            proxy_pass http://backend;
        }
    }
}

如此一来,每当有 /api 开头的请求进来时,nginx 就会根据你设定的上限帮你做限流,而後端的 API server 们也只需要认真处理请求,不用管前端有多少请求想要进来,非常完美的分工合作~

小结

今天介绍了如何在 nginx 里面做分流及限流,因为大部分的服务在 production 上通常不会只有一台机器,所以直接在 nginx 把这些事情做好会让程序写起来更简单,也是业界很常用的做法哦~

关於今天的内容有问题欢迎在下方留言,没问题的话明天会继续讲一些更进阶的限流方式,就这样,明天见罗~


<<:  [Day22] CH11:刘姥姥逛物件导向的世界——封装性、继承性

>>:  Day7 用python写UI-聊聊标签Label方法(二)

[Day 16] 资料产品生命周期管理-预测模型的部署与管理(MLOps)

昨天提到了怎麽开发预测模型,但模型绝对不是开发完就好,後续还有非常多的事情得做。 Deploymen...

第二十二天:为测试产生覆盖率报告

每当我们为专案写测试的时候,其实就是拿另一个程序来执行我们写的程序,看看是不是能将程序码里所有可能的...

菜鸡用 Phaser 拾起童年游戏 28

哈罗哈罗~我们的铁人赛也快到了尾声,今天要给大家介绍一个 template,可以让我们在制作的时候更...

[常见的自然语言处理技术] 文本相似度(I): Word Embeddings

前言 在我们每日使用的语言当中,我们经常能根据单词所表的意义区分出同义词与反义词,例如英文中形容词 ...

[Day06] 自动转型

两等号与三等号( == 与 === )的差别 在 JavaScript 里一个等号 = 代表的意思是...