>웹 프론트엔드 >JS 튜토리얼 >제한 설명: API 요청 제한 관리 가이드

제한 설명: API 요청 제한 관리 가이드

DDD
DDD원래의
2024-12-05 22:29:10477검색

코드에서 조절을 언제 구현해야 합니까?

대규모 프로젝트의 경우 일반적으로 Cloudflare Rate Limiting 또는 HAProxy와 같은 도구를 사용하는 것이 가장 좋습니다. 강력하고 안정적이며 무거운 작업도 대신 처리해 드립니다.

그러나 소규모 프로젝트의 경우 또는 작업 방식을 배우고 싶다면 코드에서 직접 속도 제한기를 만들 수 있습니다. 왜요?

  • 간단하다: 이해하기 쉽고 간단한 것을 만들 수 있습니다.
  • 저예산: 서버 호스팅 외에 추가 비용이 없습니다.
  • 소규모 프로젝트에 적합: 트래픽이 적은 한 작업을 빠르고 효율적으로 유지합니다.
  • 재사용 가능: 새로운 도구나 서비스를 설정하지 않고도 다른 프로젝트에 복사할 수 있습니다.

무엇을 배울 것인가

이 가이드를 마치면 API가 과부하되지 않도록 보호하기 위해 TypeScript에서 기본 조절 장치를 구축하는 방법을 알게 될 것입니다. 우리가 다룰 내용은 다음과 같습니다.

  • 구성 가능한 시간 제한: 시도가 차단될 때마다 남용을 방지하기 위해 잠금 기간이 늘어납니다.
  • 요청 한도: 허용되는 최대 요청 수를 설정합니다. 이는 OpenAI와 같은 유료 서비스와 관련된 API에 특히 유용합니다.
  • 인메모리 스토리지: Redis와 같은 외부 도구 없이 작동하는 간단한 솔루션으로 소규모 프로젝트나 프로토타입에 이상적입니다.
  • 사용자별 제한: IPv4 주소를 사용하여 사용자별로 요청을 추적합니다. SvelteKit을 활용하여 내장된 방법으로 클라이언트 IP를 쉽게 검색할 것입니다.

이 가이드는 실용적인 출발점이 되도록 설계되었으며 불필요한 복잡성 없이 기본 사항을 배우고 싶은 개발자에게 적합합니다. 그러나 아직 생산 준비가 되어 있지 않습니다.

시작하기 전에 Lucia의 Rate Limiting 섹션에 올바른 크레딧을 주고 싶습니다.


스로틀러 구현

Throttler 클래스를 정의해 보겠습니다.

export class Throttler {
    private storage = new Map<string, ThrottlingCounter>();

    constructor(private timeoutSeconds: number[]) {}
}

Throttler 생성자는 시간 초과 기간(timeoutSeconds) 목록을 허용합니다. 사용자가 차단될 때마다 이 목록에 따라 기간이 점진적으로 늘어납니다. 결국 최종 시간 초과에 도달하면 콜백을 실행하여 사용자의 IP를 영구적으로 금지할 수도 있습니다. 하지만 이는 이 가이드의 범위를 벗어납니다.

다음은 간격을 늘려 사용자를 차단하는 조절 장치 인스턴스를 생성하는 예입니다.

const throttler = new Throttler([1, 2, 4, 8, 16]);

이 인스턴스는 처음으로 1초 동안 사용자를 차단합니다. 두 번째로 두 번째 등.

우리는 지도를 사용하여 IP 주소와 해당 데이터를 저장합니다. 지도는 빈번한 추가 및 삭제를 효율적으로 처리하므로 이상적입니다.

프로 팁: 자주 변경되는 동적 데이터에는 지도를 사용하세요. 정적이고 변하지 않는 데이터의 경우 객체가 더 좋습니다. (토끼구멍1)


엔드포인트가 요청을 받으면 사용자의 IP 주소를 추출하고 Throttler에 문의하여 요청을 허용할지 여부를 결정합니다.

작동 방식

  • 사례 A: 신규 또는 비활성 사용자

    Throttler에서 IP를 찾을 수 없는 경우 사용자의 첫 번째 요청이거나 오랫동안 비활성 상태였던 것입니다. 이 경우:

    • 작업을 허용합니다.
    • 초기 시간 초과로 IP를 저장하여 사용자를 추적합니다.
  • 사례 B: 활성 사용자

    IP가 발견되면 사용자가 이전에 요청했다는 의미입니다. 여기:

    • 마지막 블록 이후 필요한 대기 시간(timeoutSeconds 배열 기준)이 경과했는지 확인하세요.
    • 시간이 충분히 지난 경우:
    • 타임스탬프를 업데이트하세요.
    • 시간 초과 인덱스를 늘립니다(오버플로를 방지하기 위해 마지막 인덱스로 제한).
    • 그렇지 않은 경우 요청을 거부하세요.

이 후자의 경우 마지막 블록 이후 충분한 시간이 지났는지 확인해야 합니다. 우리는 인덱스 덕분에 어떤 timeoutSecond를 참조해야 하는지 알고 있습니다. 그렇지 않은 경우 간단히 되돌아오십시오. 그렇지 않으면 타임스탬프를 업데이트하세요.

export class Throttler {
    private storage = new Map<string, ThrottlingCounter>();

    constructor(private timeoutSeconds: number[]) {}
}

인덱스를 업데이트할 때 timeoutSeconds의 마지막 인덱스로 제한됩니다. 그렇지 않으면 counter.index 1이 이를 오버플로하고 다음에 this.timeoutSeconds[counter.index]에 액세스하면 런타임 오류가 발생합니다.

엔드포인트 예시

이 예에서는 Throttler를 사용하여 사용자가 API를 호출할 수 있는 빈도를 제한하는 방법을 보여줍니다. 사용자가 너무 많은 요청을 하면 기본 로직을 실행하는 대신 오류가 발생합니다.

const throttler = new Throttler([1, 2, 4, 8, 16]);

Throttling Explained: A Guide to Managing API Request Limits

인증 시 참고사항

로그인 시스템에서 속도 제한을 사용할 때 다음 문제가 발생할 수 있습니다.

  1. 사용자가 로그인하여 제한 시간을 해당 IP와 연결하도록 Throttler를 트리거합니다.
  2. 사용자가 로그아웃하거나 세션이 종료됩니다(예: 즉시 로그아웃, 세션과 함께 쿠키가 만료되고 브라우저가 충돌하는 등).
  3. 곧 다시 로그인을 시도하면 Throttler가 여전히 해당 사용자를 차단하고 429 요청이 너무 많음 오류를 반환할 수 있습니다.

이를 방지하려면 속도 제한에 IP 대신 사용자의 고유한 사용자 ID를 사용하세요. 또한 불필요한 블록을 방지하려면 로그인에 성공한 후 조절기 상태를 재설정해야 합니다.

Throttler 클래스에 재설정 메서드를 추가합니다.

export class Throttler {
    // ...

    public consume(key: string): boolean {
        const counter = this.storage.get(key) ?? null;
        const now = Date.now();

        // Case A
        if (counter === null) {
            // At next request, will be found.
            // The index 0 of [1, 2, 4, 8, 16] returns 1.
            // That's the amount of seconds it will have to wait.
            this.storage.set(key, {
                index: 0,
                updatedAt: now
            });
            return true; // allowed
        }

        // Case B
        const timeoutMs = this.timeoutSeconds[counter.index] * 1000;
        const allowed = now - counter.updatedAt >= timeoutMs;
        if (!allowed) {
            return false; // denied
        }

        // Allow the call, but increment timeout for following requests.
        counter.updatedAt = now;
        counter.index = Math.min(counter.index + 1, this.timeoutSeconds.length - 1);
        this.storage.set(key, counter);

        return true; // allowed
    }
}

로그인 성공 후 사용:

export class Throttler {
    private storage = new Map<string, ThrottlingCounter>();

    constructor(private timeoutSeconds: number[]) {}
}

정기적인 정리를 통해 오래된 IP 기록 관리

스로틀러가 IP 및 속도 제한을 추적하므로 더 이상 필요하지 않은 IP 레코드를 제거하는 방법과 시기를 생각하는 것이 중요합니다. 정리 메커니즘이 없으면 제한 장치가 레코드를 메모리에 계속 저장하므로 시간이 지남에 따라 데이터가 증가함에 따라 성능 문제가 발생할 수 있습니다.

이를 방지하기 위해 일정 기간 동안 활동이 없으면 오래된 기록을 주기적으로 삭제하는 정리 기능을 구현할 수 있습니다. 다음은 스로틀러에서 오래된 항목을 제거하기 위해 간단한 정리 방법을 추가하는 방법에 대한 예입니다.

const throttler = new Throttler([1, 2, 4, 8, 16]);

정리 일정을 예약하는 매우 간단한 방법(아마도 최선은 아닐 수 있음)은 setInterval을 사용하는 것입니다.

export class Throttler {
    // ...

    public consume(key: string): boolean {
        const counter = this.storage.get(key) ?? null;
        const now = Date.now();

        // Case A
        if (counter === null) {
            // At next request, will be found.
            // The index 0 of [1, 2, 4, 8, 16] returns 1.
            // That's the amount of seconds it will have to wait.
            this.storage.set(key, {
                index: 0,
                updatedAt: now
            });
            return true; // allowed
        }

        // Case B
        const timeoutMs = this.timeoutSeconds[counter.index] * 1000;
        const allowed = now - counter.updatedAt >= timeoutMs;
        if (!allowed) {
            return false; // denied
        }

        // Allow the call, but increment timeout for following requests.
        counter.updatedAt = now;
        counter.index = Math.min(counter.index + 1, this.timeoutSeconds.length - 1);
        this.storage.set(key, counter);

        return true; // allowed
    }
}

이 정리 메커니즘은 스로틀러가 오래된 레코드를 무기한 보유하지 않도록 하여 애플리케이션 효율성을 유지하는 데 도움이 됩니다. 이 접근 방식은 간단하고 구현하기 쉽지만 더 복잡한 사용 사례(예: 고급 예약 사용 또는 높은 동시성 처리)의 경우 추가 개선이 필요할 수 있습니다.

주기적인 정리를 통해 메모리 팽창을 방지하고 한동안 요청을 시도하지 않은 사용자가 더 이상 추적되지 않도록 할 수 있습니다. 이는 속도 제한 시스템을 확장 가능하고 리소스 효율적으로 만들기 위한 첫 번째 단계입니다.


  1. 모험적인 느낌이 든다면 속성이 할당되는 방식과 변경되는 방식을 읽어 보는 것이 흥미로울 수 있습니다. 또한 특히 단일형성이 선호하는 인라인 캐시와 같은 VM 최적화에 대해서도 알아보세요. 즐기다. ↩

위 내용은 제한 설명: API 요청 제한 관리 가이드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.