노드에서 확장 가능한 API 속도 제한기를 설계합니다.js 응용 프로그램

본고에서 우리는 노드의 API를 위해 확장 가능한 속도 제한기를 구축하는 방법을 이해할 것이다.js 응용 프로그램.노드에 확장 가능한 API 속도 제한기를 구축합니다.js 응용 프로그램.

장면 1:


예를 들어 사용자가 이 API를 사용하여 이 서비스에 접근할 수 있는 공공 API 서비스를 구축하고 있습니다.또한 이 공용 API 서비스의 보안을 보호해야 합니다DDOS Attack.

장면 2:


만약 우리가 하나의 제품을 구축했다고 가정하자.우리는 제품 서비스를 얻기 위해 사용자에게 무료 시용을 제공해야 한다.

솔루션:


이 두 가지 상황에서 속도 제한 알고리즘은 문제를 해결하는 방법이다.

속도 제한 알고리즘:


우선, 속도 제한 알고리즘은 API에 대한 액세스를 제한하는 방법입니다. 예를 들어, 사용자가 초당 100개의 요청 속도로 API를 요청한다고 가정합니다.이로 인해 서버 과부하 문제가 발생할 수 있습니다.
이 문제를 피하기 위해서 우리는 API에 대한 접근을 제한할 수 있습니다. 예를 들어 한 사용자가 분당 20개의 요청을 할 수 있습니다.

다른 속도 제한 알고리즘:


소프트웨어 응용 프로그램 개발의 속도 제한 알고리즘 유형을 살펴보겠습니다.

토큰통:


그것은 분당 a 요청에 제공할 수 있는 최대 영패 수를 저장합니다.예를 들어 사용자에게 API 속도 제한기는 분당 5개의 영패를 설정한다.따라서 사용자는 분당 최대 5개의 요청을 서버에 보낼 수 있다.그러면 서버에서 요청이 무시됩니다.
Redis는 요청 데이터에 신속하게 액세스할 수 있도록 정보를 저장하는 데 주로 사용됩니다.

작업 원리


User1이 서버에 요청을 보내는 것으로 가정합니다.서버는 요청 시간과 이전 요청 시간이 1분보다 큰지 확인합니다.1분도 안 걸리면 지정한 사용자의 남은 영패를 검사합니다.
0이면 서버에서 요청을 무시합니다.

누통 알고리즘


이것은 고급 프런트 아웃(FIFO) 방식으로 요청을 받는 대기열입니다.

일단 대열이 채워지면서버는 대기열이 더 많은 요청을 받아들일 수 있을 때까지 다가오는 요청을 버립니다.
예를 들어 서버 요청 1, 2, 3, 4를 가져옵니다.대기열 크기를 기준으로 합니다.그것은 요청을 받아들인다.대기열의 크기를 4로 가정합니다.1, 2, 3, 4를 요청해야 합니다.
이후 서버에서 요청 5를 받았습니다.떨어질 거야.

고정 창 카운터


그것은 특정 시간 내에 사용자의 요청 계수기를 추가합니다.계수기가 한도값을 초과하면서버가 요청을 무시합니다.요청 정보를 저장하기 위해redis를 사용합니다.
예를 들어 서버는 사용자로부터 요청을 받는다.사용자 요청 정보가redis에 존재하고 요청 시간이 이전 요청 시간보다 적으면 계수기가 추가됩니다.
임계값에 도달하면서버는 지정된 시간 내에 다가오는 요청을 버립니다.

속이다


서버가 1분 55초에 대량의 요청을 받았다고 가정하십시오.이것은 예상한 대로 작용하지 않을 것이다

슬라이딩 원목



모든 요청한 로그와 시간 스탬프를 Redis나 메모리에 저장합니다.요청마다 1분 동안 사용자가 사용할 수 있는 로그 수를 검사합니다.
또한 한도값을 초과하면 서버에서 다가오는 요청을 버립니다.
다른 한편, 이런 방법은 결점이 거의 없다.프로그램이 백만 개의 요청을 받았다고 가정하면, 메모리에서 모든 요청의 로그를 유지하는 것은 매우 비싸다.

슬라이딩 창 카운터


이런 방법은 약간 슬라이딩 로그와 유사하다.여기서 유일한 차이점은 우리가 모든 로그를 저장하는 것이 아니라 시간 스탬프에 따라 사용자가 요청한 데이터를 그룹으로 나누어 저장하는 것이다.
예를 들어 서버가 사용자의 요청을 받으면우리는 메모리에 있는 요청 시간 스탬프를 검사합니다.만약 그것이 사용할 수 있다면, 우리는 그것의 계수기를 증가시킬 것이다.사용할 수 없으면 새 레코드로 삽입합니다.
이렇게 하면 모든 요청을 단독 항목으로 저장할 필요가 없습니다. 시간 스탬프에 따라 그룹을 나누고 계수기를 유지할 수 있습니다.

노드에서 슬라이딩 창 계수기를 실현합니다.js 응용 프로그램


전체 소스 코드를 찾을 수 있습니다 here

선결 조건

  • Node.js
  • Redis
  • 디렉터리를 만들고 패키지를 초기화합니다.json은 다음 명령을 사용합니다
    npm init --yes
    이후 다음 명령을 사용하여 응용 프로그램에 Express와 redis를 설치합니다
    npm i express redis moment
    Redis 클라이언트는 Redis 서버를 연결하는 데 사용됩니다.moment 요청 스탬프를 저장하는 데 사용됩니다.
    먼저 파일 서버를 만듭니다.js와 다음 코드를 추가합니다.
    const express = require('express');
    const rateLimiter = require('./slidingWindowCounter');
    const app = express();
    
    const router = express.Router();
    
    router.get('/',(req,res) => {
        res.send('<h1>API response</h1>')
    })
    
    app.use(rateLimiter);
    app.use('/api',router);
    
    app.listen(5000,() => {
        console.log('server is running on port 5000');
    })
    그 다음에 파일 슬라이딩 창 카운터를 만듭니다.js와 다음 코드를 추가합니다.
    const redis = require('redis');
    const moment = require('moment');
    const redisClient = redis.createClient();
    
    module.exports = (req,res,next) => {
        
        redisClient.exists(req.headers.user,(err,reply) => {
            if(err){
                console.log("problem with redis");
                system.exit(0);
            }
    
            if(reply === 1) {
    
                redisClient.get(req.headers.user,(err,redisResponse) => {
                    let data = JSON.parse(redisResponse);
                    
                    let currentTime = moment().unix()
                    let lessThanMinuteAgo = moment().subtract(1,'minute').unix();
    
                    let RequestCountPerMinutes = data.filter((item) => {
                        return item.requestTime > lessThanMinuteAgo;
                    })
    
                    let thresHold = 0;
    
                    RequestCountPerMinutes.forEach((item) => {
                        thresHold = thresHold + item.counter;
                    })
    
                    if(thresHold >= 5){
    
                        return res.json({ "error" : 1,"message" : "throttle limit exceeded" })
    
                    }
                    else{
    
                        let isFound = false;
                        data.forEach(element => {
                            if(element.requestTime) {
                                isFound = true;
                                element.counter++;
                            }
                        });
                        if(!isFound){
                            data.push({
                                requestTime : currentTime,
                                counter : 1
                            })
                        }
                      
                        redisClient.set(req.headers.user,JSON.stringify(data));
    
                        next();
    
                    }
                })
            }
            else{
                let data = [];
                let requestData = {
                    'requestTime' : moment().unix(),
                    'counter' : 1
                }
                data.push(requestData);
                redisClient.set(req.headers.user,JSON.stringify(data));
    
                next();
            }
        })
    }
  • 사용자가redis 메모리에 존재하는지 확인하고 존재하면 더 처리합니다.없으면 카운터 값과 요청 시간 스탬프가 있는 사용자 상세 정보를 삽입하십시오.
  • 사용자가 이미 존재하면 마지막 1분 동안 요청 계수가 한도값을 초과했는지 확인합니다.초과하면 서버에서 요청을 무시합니다.
  • 을 초과하지 않으면 스탬프가 일치하면 계수기가 추가됩니다.그렇지 않으면 삽입됩니다.
  • 전체 소스 코드를 찾을 수 있습니다 here

    좋은 웹페이지 즐겨찾기