>  기사  >  백엔드 개발  >  PHP에서 API 인터페이스의 흐름을 제한하는 방법

PHP에서 API 인터페이스의 흐름을 제한하는 방법

爱喝马黛茶的安东尼
爱喝马黛茶的安东尼원래의
2019-09-27 15:30:217334검색

PHP에서 API 인터페이스의 흐름을 제한하는 방법

인터페이스 전류 제한이란 무엇입니까?

그럼 전류 제한이란 무엇입니까? 이름에서 알 수 있듯이 현재 제한은 특정 기간 내의 동시 트래픽과 전체 트래픽을 포함하여 트래픽을 제한하는 것입니다. 광대역 패키지에 1G의 트래픽이 있는 것처럼 모두 사용되면 사라지므로 주파수를 제어하십시오. 단일 시간의 사용량 및 총 트래픽을 보여줍니다. 전류 제한을 통해 시스템의 qps를 효과적으로 제어할 수 있으므로 시스템 또는 인터페이스 서버의 안정성을 보호하려는 목적을 달성할 수 있습니다.

인터페이스 전류 제한에 일반적으로 사용되는 알고리즘

카운터 방법

카운터 방법은 전류 제한 알고리즘 중에서 가장 간단하고 구현하기 쉽습니다. 예를 들어 인터페이스 A의 경우 1분당 액세스 횟수가 100회를 초과할 수 없다고 규정합니다. 그런 다음 이렇게 할 수 있습니다. 처음에는 카운터 카운터를 설정할 수 있습니다. 요청이 올 때마다 카운터는 1씩 증가합니다. 카운터 값이 100보다 크고 요청과 첫 번째 요청 사이의 간격이 다음과 같습니다. 여전히 1분 이내에 요청이 너무 많다는 의미입니다. 요청과 첫 번째 요청 사이의 간격이 1분보다 크고 카운터 값이 여전히 현재 제한 범위 내에 있으면 카운터를 재설정합니다. 구체적인 알고리즘은 다음과 같습니다.

PHP에서 API 인터페이스의 흐름을 제한하는 방법

의사 코드는 다음과 같습니다.

class CounterDemo{
    private  $timeStamp;
    public  $reqCount=0;
    public  $limit=100;//时间窗口内最大请求数
    public $interval=1000; //时间窗口 ms
    public function __construct()
    {
        $this->timeStamp = time();
    }
    public  function grant(){
        $now=time();
        if($now<$this->timeStamp+$this->interval){
            //时间窗口内
            $this->reqCount++;
            return $this->reqCount<=$this->limit;
        }else{
            // 超时后重置
            $this->timeStamp=time();
            $this->reqCount=1;
            return true;
        }
    }
}

이 알고리즘은 간단해 보이지만 매우 심각한 문제가 있는데, 바로 임계도 문제입니다.

PHP에서 API 인터페이스의 흐름을 제한하는 방법

위 그림을 보면 0시 59분에 즉시 100개의 요청을 보낸 악의적인 사용자가 있고, 1시에 또 100개의 요청을 즉시 보냈다고 가정한 것을 알 수 있습니다. 실제로 이 사용자는 1초 만에 즉시 200개의 요청을 보냈습니다. 방금 규정한 것은 분당 최대 100개 요청이며, 이는 초당 최대 1.7개 요청입니다. 사용자는 시간 창의 재설정 노드에서 버스트 요청을 함으로써 즉시 속도 제한을 초과할 수 있습니다. 사용자는 알고리즘의 이 허점을 사용하여 애플리케이션을 즉시 압도할 수 있습니다.

관련 추천: "php tutorial"

똑똑한 친구들은 지금의 문제가 실제로는 통계의 정확성이 너무 낮기 때문이라는 것을 알아냈을 수도 있습니다. 그렇다면 이 문제를 어떻게 잘 처리할 수 있을까요? 즉, 중요한 문제의 영향을 줄이는 방법은 무엇입니까? 아래에서 슬라이딩 윈도우 알고리즘을 살펴보겠습니다.

슬라이딩 윈도우 알고리즘

PHP에서 API 인터페이스의 흐름을 제한하는 방법

위 그림에서 전체 빨간색 직사각형 상자는 시간 창을 나타냅니다. 이 예에서 시간 창은 1분입니다. 그런 다음 시간 창을 나눕니다. 예를 들어 그림에서는 슬라이딩 창을 6개의 그리드로 나누므로 각 그리드는 10초를 나타냅니다. 10초마다 시간 창이 한 프레임 오른쪽으로 이동합니다. 각 그리드에는 자체 독립 카운터가 있습니다. 예를 들어 요청이 0:35초에 도착하면 0:30부터 0:39까지 해당 카운터가 1씩 증가합니다.

그렇다면 슬라이딩 윈도우는 지금 당장의 중요한 문제를 어떻게 해결할까요? 위 그림을 보면 0:59에 도착하는 100개의 요청은 회색 그리드에 표시되고, 1:00에 도착하는 요청은 주황색 그리드에 표시됩니다. 시간이 1시에 도달하면 창이 오른쪽으로 한 칸 이동합니다. 그러면 이때 시간 창의 총 요청 수는 200개로 제한인 100을 초과하므로 현재 제한이 다음과 같은 것을 감지할 수 있습니다. 이때 발동되었습니다.

지금 카운터 알고리즘을 검토하겠습니다. 카운터 알고리즘이 실제로 슬라이딩 윈도우 알고리즘이라는 것을 알 수 있습니다. 단지 시간 창을 더 이상 나누지 않기 때문에 그리드가 1개만 있을 뿐입니다.

미닫이 창의 그리드가 더 많이 분할되면 슬라이딩 창의 롤링이 더 부드러워지고 전류 제한 통계가 더 정확해지는 것을 볼 수 있습니다.

누수 버킷 알고리즘

누수 버킷 알고리즘이라고도 하는 누출 버킷 알고리즘입니다. 누출 버킷 알고리즘을 이해하기 위해 Wikipedia에서 알고리즘의 개략도를 살펴보겠습니다.

PHP에서 API 인터페이스의 흐름을 제한하는 방법

그림에서 전체 알고리즘이 실제로 매우 간단하다는 것을 알 수 있습니다. 먼저, 물이 들어오고 나가는 고정된 용량의 양동이가 있습니다. 물이 유입되는 경우에는 얼마나 많은 물이 유입될지, 얼마나 빠르게 흐를지 예측할 수 없습니다. 하지만 물이 흘러나오는 경우에는 이 물통을 사용하여 물이 흘러나오는 속도를 고정할 수 있습니다. 또한 물통이 가득 차면 남은 물이 넘치게 됩니다.

알고리즘의 물을 실제 애플리케이션의 요청으로 대체해 보면 Leaky Bucket 알고리즘이 본질적으로 요청 속도를 제한한다는 것을 알 수 있습니다. Leaky Bucket 알고리즘을 사용하면 인터페이스가 일정한 속도로 요청을 처리하도록 보장할 수 있습니다. 따라서 Leaky Bucket 알고리즘은 본질적으로 중요도 문제가 없습니다. 구체적인 의사코드 구현은 다음과 같습니다:

class LeakyDemo{
    private  $timeStamp;
    public  $capacity;// 桶的容量
    public  $rate; // 水漏出的速度
    public  $water;// 当前水量(当前累积请求数)
    public function __construct()
    {
        $this->timeStamp = time();
    }
    public  function grant(){
        $now=time();
        $this->water=max(0,$this->water-($now-$this->timeStamp)*$this->rate);// 先执行漏水,计算剩余水量
        $this->timeStamp=$now;
        if(($this->water+1)<$this->capacity){
            // 尝试加水,并且水还未满
            $this->water+=1;
            return true;
        }else{
            // 水满,拒绝加水
            return false;
        }
    }
}

토큰 버킷 알고리즘

令牌桶算法,又称token bucket。为了理解该算法,我们再来看一下维基百科上对该算法的示意图:

PHP에서 API 인터페이스의 흐름을 제한하는 방법

从图中我们可以看到,令牌桶算法比漏桶算法稍显复杂。首先,我们有一个固定容量的桶,桶里存放着令牌(token)。桶一开始是空的,token以一个固定的速率r往桶里填充,直到达到桶的容量,多余的令牌将会被丢弃。每当一个请求过来时,就会尝试从桶里移除一个令牌,如果没有令牌的话,请求无法通过。

具体的伪代码实现如下:

class TokenBucketDemo{
    private  $timeStamp;
    public  $capacity;// 桶的容量
    public  $rate; // 令牌放入的速度
    public  $tokens;// 当前令牌的数量
    public function __construct()
    {
        $this->timeStamp = time();
    }
    public  function grant(){
        $now=time();
        $this->tokens=min(0,$this->tokens+($now-$this->timeStamp)*$this->rate);// 先执行漏水,计算剩余水量
        $this->timeStamp=$now;
        if($this->tokens<1){
            // 若不到1个令牌,则拒绝
            return false;
        }else{
            // 还有令牌,领取令牌
            $this->tokens -= 1;
            return true;
        }
    }
}

临界问题

我们再来考虑一下临界问题的场景。在0:59秒的时候,由于桶内积满了100个token,所以这100个请求可以瞬间通过。但是由于token是以较低的 速率填充的,所以在1:00的时候,桶内的token数量不可能达到100个,那么此时不可能再有100个请求通过。所以令牌桶算法可以很好地解决临界问题。下图比较了计数器(左)和令牌桶算法(右)在临界点的速率变化。我们可以看到虽然令牌桶算法允许突发速率,但是下一个突发速率必须要等桶内有足够的token后才能发生。

PHP에서 API 인터페이스의 흐름을 제한하는 방법

总结

计数器算法是最简单的算法,可以看成是滑动窗口的低精度实现。滑动窗口由于需要存储多份的计数器(每一个格子存一份),所以滑动窗口在实现上需要更多的存储空间。也就是说,如果滑动窗口的精度越高,需要的存储空间就越大。

漏桶算法 VS 令牌桶算法

漏桶算法和令牌桶算法最明显的区别是令牌桶算法允许流量一定程度的突发。因为默认的令牌桶算法,取走token是不需要耗费时间的,也就是说,假设桶内有100个token时,那么可以瞬间允许100个请求通过。

令牌桶算法由于实现简单,且允许某些流量的突发,对用户友好,所以被业界采用地较多。当然我们需要具体情况具体分析,只有最合适的算法,没有最优的算法。

위 내용은 PHP에서 API 인터페이스의 흐름을 제한하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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