PHP verwendet den Token-Bucket-Algorithmus, um eine Flusskontrolle basierend auf Redis zu implementieren

jacklove
Freigeben: 2023-04-01 12:10:02
Original
3762 Leute haben es durchsucht

Dieser Artikel stellt PHP basierend auf Redis vor und verwendet den Token-Bucket-Algorithmus zur Steuerung des Zugriffsverkehrs. Er bietet eine vollständige Algorithmusbeschreibung und Demonstrationsbeispiele, die jeder lernen und verwenden kann.
Immer wenn es lange inländische Feiertage oder wichtige Festivals gibt, sind inländische Aussichtspunkte oder U-Bahnen überfüllt, was zu einer übermäßigen Belastung führt. Einige werden Maßnahmen zur Begrenzung des Personenstroms ergreifen Wenn der Bereich auf einen bestimmten Wert reduziert wird, wird keine weitere Berechtigung mehr gewährt.

Zum Beispiel:
Die maximal zulässige Personenzahl in der Gegend beträgt M
Die aktuelle Personenzahl in der Gegend beträgt N
Jedes Mal, wenn Sie eintreten. Eine Person, N+1, wenn N = M, darf nicht eintreten
Jede Person geht, N-1, wenn N <
Natürlich können wir Server hinzufügen, um den Druck zu teilen. Erstens erfordert das Hinzufügen von Servern auch eine gewisse Zeit für die Konfiguration, und wenn Server aufgrund einer bestimmten Aktivität hinzugefügt werden, werden diese Serverressourcen verschwendet nach Beendigung der Aktivität.

Daher können wir zunächst die

Strombegrenzungsmethode verwenden, um den Serverdruck entsprechend der Art des Unternehmens zu reduzieren. Anders als bei der Verkehrsbeschränkung an malerischen Orten

ist die Zeit vom Besuch bis zum Ende des Systems sehr kurz

, sodass wir nur die durchschnittliche Dauer jedes Besuchs kennen und das Maximum festlegen müssen Anzahl der gleichzeitigen Besucher. Token-Bucket-Algorithmus

1. Zuerst gibt es einen Token-Bucket und die Token werden im Bucket gespeichert. Zu Beginn sind die Token im Token-Bucket voll im Bucket Die Menge kann entsprechend den Serverbedingungen eingestellt werden.

2. Nehmen Sie für jeden Besuch einen Token aus dem Bucket. Wenn der Token im Bucket 0 ist, sind keine weiteren Besuche erlaubt.

3. Fügen Sie von Zeit zu Zeit Token hinzu, bis der Eimer voll ist. (Sie können in regelmäßigen Abständen mehrere Token einlegen oder den Token-Bucket entsprechend der tatsächlichen Situation direkt füllen.)

Wir können die Warteschlange von

Redis

als Token-Bucket-Container verwenden lPush (in die Warteschlange stellen), rPop (aus der Warteschlange entfernen) zum Implementieren von Token-Hinzufügungs- und Verbrauchsvorgängen. >Ausgabe:

<?php/**
 * PHP基于Redis使用令牌桶算法实现流量控制
 * Date:    2018-02-23
 * Author:  fdipzone
 * Version: 1.0
 *
 * Descripton:
 * php基于Redis使用令牌桶算法实现流量控制,使用redis的队列作为令牌桶容器,入队(lPush)出队(rPop)作为令牌的加入与消耗操作。
 *
 * Func:
 * public  add     加入令牌
 * public  get     获取令牌
 * public  reset   重设令牌桶
 * private connect 创建redis连接
 */class TrafficShaper{ // class start
    private $_config; // redis设定
    private $_redis;  // redis对象
    private $_queue;  // 令牌桶
    private $_max;    // 最大令牌数
    /**
     * 初始化
     * @param Array $config redis连接设定
     */
    public function __construct($config, $queue, $max){
        $this->_config = $config;        $this->_queue = $queue;        $this->_max = $max;        $this->_redis = $this->connect();
    }    /**
     * 加入令牌
     * @param  Int $num 加入的令牌数量
     * @return Int 加入的数量
     */
    public function add($num=0){
        // 当前剩余令牌数
        $curnum = intval($this->_redis->lSize($this->_queue));        // 最大令牌数
        $maxnum = intval($this->_max);        // 计算最大可加入的令牌数量,不能超过最大令牌数
        $num = $maxnum>=$curnum+$num? $num : $maxnum-$curnum;        // 加入令牌
        if($num>0){            $token = array_fill(0, $num, 1);            $this->_redis->lPush($this->_queue, ...$token);            return $num;
        }        return 0;
    }    /**
     * 获取令牌
     * @return Boolean
     */
    public function get(){
        return $this->_redis->rPop($this->_queue)? true : false;
    }    /**
     * 重设令牌桶,填满令牌
     */
    public function reset(){
        $this->_redis->delete($this->_queue);        $this->add($this->_max);
    }    /**
     * 创建redis连接
     * @return Link
     */
    private function connect(){
        try{            $redis = new Redis();            $redis->connect($this->_config[&#39;host&#39;],$this->_config[&#39;port&#39;],$this->_config[&#39;timeout&#39;],$this->_config[&#39;reserved&#39;],$this->_config[&#39;retry_interval&#39;]);            if(empty($this->_config[&#39;auth&#39;])){                $redis->auth($this->_config[&#39;auth&#39;]);
            }            $redis->select($this->_config[&#39;index&#39;]);
        }catch(RedisException $e){            throw new Exception($e->getMessage());            return false;
        }        return $redis;
    }
} // class end?>
Nach dem Login kopieren
Token-Algorithmus regelmäßig hinzufügen Wenn wir regelmäßig Token hinzufügen, können wir Crontab verwenden, um ihn zu implementieren, und die Add-Methode aufrufen, um mehrere Token hinzuzufügen jede Minute. Informationen zur Verwendung von Crontab finden Sie unter: „Befehlsformat für geplante Aufgabenausführung unter Linux und detaillierte Beispiele“

Das Mindestausführungsintervall von Crontab beträgt 1 Minute, wenn die Token im Token-Bucket verbraucht wurden In den ersten paar Sekunden kann das Token dann nicht mehr abgerufen werden, was dazu führt, dass der Benutzer lange warten muss.

Wir können den Algorithmus zum Hinzufügen von Token optimieren und alle paar Sekunden innerhalb einer Minute mehrere Token hinzufügen. Dadurch kann sichergestellt werden, dass jedes Mal eine Chance besteht, Token zu erhalten. Das von crontab aufgerufene Programm zum Hinzufügen von Token sieht wie folgt aus und fügt automatisch 3 Token pro Sekunde hinzu.

<?php/**
 * 演示令牌加入与消耗
 */require &#39;TrafficShaper.class.php&#39;;// redis连接设定$config = array(    &#39;host&#39; => &#39;localhost&#39;,    &#39;port&#39; => 6379,    &#39;index&#39; => 0,    &#39;auth&#39; => &#39;&#39;,    &#39;timeout&#39; => 1,    &#39;reserved&#39; => NULL,    &#39;retry_interval&#39; => 100,
);// 令牌桶容器$queue = &#39;mycontainer&#39;;// 最大令牌数$max = 5;// 创建TrafficShaper对象$oTrafficShaper = new TrafficShaper($config, $queue, $max);// 重设令牌桶,填满令牌$oTrafficShaper->reset();// 循环获取令牌,令牌桶内只有5个令牌,因此最后3次获取失败for($i=0; $i<8; $i++){
    var_dump($oTrafficShaper->get());
}// 加入10个令牌,最大令牌为5,因此只能加入5个$add_num = $oTrafficShaper->add(10);
var_dump($add_num);// 循环获取令牌,令牌桶内只有5个令牌,因此最后1次获取失败for($i=0; $i<6; $i++){
    var_dump($oTrafficShaper->get());
}?>
Nach dem Login kopieren
Das Simulationsverbrauchsverfahren ist wie folgt und verbraucht 2-8 Token pro Sekunde.

boolean trueboolean trueboolean trueboolean trueboolean trueboolean falseboolean falseboolean falseint 5boolean trueboolean trueboolean trueboolean trueboolean trueboolean false
Nach dem Login kopieren

Demo

Legen Sie eine geplante Aufgabe fest und führen Sie sie jede Minute aus

<?php/**
 * 定时任务加入令牌
 */require &#39;TrafficShaper.class.php&#39;;// redis连接设定$config = array(    &#39;host&#39; => &#39;localhost&#39;,    &#39;port&#39; => 6379,    &#39;index&#39; => 0,    &#39;auth&#39; => &#39;&#39;,    &#39;timeout&#39; => 1,    &#39;reserved&#39; => NULL,    &#39;retry_interval&#39; => 100,
);// 令牌桶容器$queue = &#39;mycontainer&#39;;// 最大令牌数$max = 10;// 每次时间间隔加入的令牌数$token_num = 3;// 时间间隔,最好是能被60整除的数,保证覆盖每一分钟内所有的时间$time_step = 1;// 执行次数$exec_num = (int)(60/$time_step);// 创建TrafficShaper对象$oTrafficShaper = new TrafficShaper($config, $queue, $max);for($i=0; $i<$exec_num; $i++){    $add_num = $oTrafficShaper->add($token_num);    echo &#39;[&#39;.date(&#39;Y-m-d H:i:s&#39;).&#39;] add token num:&#39;.$add_num.PHP_EOL;
    sleep($time_step);
}?>
Nach dem Login kopieren

Ausführungssimulationsverbrauch
<?php/**
 * 模拟用户访问消耗令牌,每段时间间隔消耗若干令牌
 */require &#39;TrafficShaper.class.php&#39;;// redis连接设定$config = array(    &#39;host&#39; => &#39;localhost&#39;,    &#39;port&#39; => 6379,    &#39;index&#39; => 0,    &#39;auth&#39; => &#39;&#39;,    &#39;timeout&#39; => 1,    &#39;reserved&#39; => NULL,    &#39;retry_interval&#39; => 100,
);// 令牌桶容器$queue = &#39;mycontainer&#39;;// 最大令牌数$max = 10;// 每次时间间隔随机消耗的令牌数量范围$consume_token_range = array(2, 8);// 时间间隔$time_step = 1;// 创建TrafficShaper对象$oTrafficShaper = new TrafficShaper($config, $queue, $max);// 重设令牌桶,填满令牌$oTrafficShaper->reset();// 执行令牌消耗while(true){    $consume_num = mt_rand($consume_token_range[0], $consume_token_range[1]);    for($i=0; $i<$consume_num; $i++){        $status = $oTrafficShaper->get();        echo &#39;[&#39;.date(&#39;Y-m-d H:i:s&#39;).&#39;] consume token:&#39;.($status? &#39;true&#39; : &#39;false&#39;).PHP_EOL;
    }
    sleep($time_step);
}?>
Nach dem Login kopieren
Ausführung Ergebnisse:
* * * * * php /程序的路径/cron_add.php >> /tmp/cron_add.log
Nach dem Login kopieren

Da der Token-Bucket zu Beginn voll ist (maximale Anzahl an Tokens beträgt 10), können in den ersten 10 Malen mehr Tokens abgerufen werden als beim Beitritt Bei Überschreitung der Anzahl der Karten wird der Zugriff eingeschränkt.

In diesem Artikel wird erläutert, wie PHP den Token-Bucket-Algorithmus verwendet, um eine Flusskontrolle basierend auf Redis zu implementieren. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website.

Verwandte Empfehlungen:


Redis Master-Slave-Synchronisierung , Verwandte Vorgänge der Lese-Schreib-Trennungseinstellungen

Stellt die Methode von MySQL zum Neuerstellen einer Tabelle vor Partitionieren und Daten behalten


PHP generiert relevante Inhalte für die eindeutige RequestID-Klasse

Das obige ist der detaillierte Inhalt vonPHP verwendet den Token-Bucket-Algorithmus, um eine Flusskontrolle basierend auf Redis zu implementieren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage