日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 默认站点!

默认站点

當前位置: 首頁 >

十三水算法php_基于PHP+Redis令牌桶限流

發布時間:2023/12/2 31 豆豆
默认站点 收集整理的這篇文章主要介紹了 十三水算法php_基于PHP+Redis令牌桶限流 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一 、場景描述

在開發接口服務器的過程中,為了防止客戶端對于接口的濫用,保護服務器的資源, 通常來說我們會對于服務器上的各種接口進行調用次數的限制。比如對于某個 用戶,他在一個時間段(interval)內,比如 1 分鐘,調用服務器接口的次數不能夠 大于一個上限(limit),比如說 100 次。如果用戶調用接口的次數超過上限的話,就直接拒絕用戶的請求,返回錯誤信息。
服務接口的流量控制策略:分流、降級、限流等。本文討論下限流策略,雖然降低了服務接口的訪問頻率和并發量,卻換取服務接口和業務應用系統的高可用。

二、常用的限流算法

1、漏桶算法
漏桶(Leaky Bucket)算法思路很簡單,水(請求)先進入到漏桶里,漏桶以一定的速度出水(接口有響應速率),當水流入速度過大會直接溢出(訪問頻率超過接口響應速率),然后就拒絕請求,可以看出漏桶算法能強行限制數據的傳輸速率.示意圖如下:


可見這里有兩個變量,一個是桶的大小,支持流量突發增多時可以存多少的水(burst),另一個是水桶漏洞的大小(rate)。
因為漏桶的漏出速率是固定的參數,所以,即使網絡中不存在資源沖突(沒有發生擁塞),漏桶算法也不能使流突發(burst)到端口速率.因此,漏桶算法對于存在突發特性的流量來說缺乏效率.

2、令牌桶算法
令牌桶算法(Token Bucket)和 Leaky Bucket 效果一樣但方向相反的算法,更加容易理解.隨著時間流逝,系統會按恒定1/QPS時間間隔(如果QPS=100,則間隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有個水龍頭在不斷的加水),如果桶已經滿了就不再加了.新請求來臨時,會各自拿走一個Token,如果沒有Token可拿了就阻塞或者拒絕服務.

令牌桶的另外一個好處是可以方便的改變速度. 一旦需要提高速率,則按需提高放入桶中的令牌的速率. 一般會定時(比如100毫秒)往桶中增加一定數量的令牌, 有些變種算法則實時的計算應該增加的令牌的數量.

三、基于PHP+Redis實現的令牌桶算法

<?php namespace ApiLib;/*** 限流控制*/ class RateLimit {private $minNum = 60; //單個用戶每分訪問數private $dayNum = 10000; //單個用戶每天總的訪問量public function minLimit($uid){$minNumKey = $uid . '_minNum';$dayNumKey = $uid . '_dayNum';$resMin = $this->getRedis($minNumKey, $this->minNum, 60);$resDay = $this->getRedis($minNumKey, $this->minNum, 86400);if (!$resMin['status'] || !$resDay['status']) {exit($resMin['msg'] . $resDay['msg']);}}public function getRedis($key, $initNum, $expire){$nowtime = time();$result = ['status' => true, 'msg' => ''];$redisObj = $this->di->get('redis');$redis->watch($key);$limitVal = $redis->get($key);if ($limitVal) {$limitVal = json_decode($limitVal, true);$newNum = min($initNum, ($limitVal['num'] - 1) + (($initNum / $expire) * ($nowtime - $limitVal['time'])));if ($newNum > 0) {$redisVal = json_encode(['num' => $newNum, 'time' => time()]);} else {return ['status' => false, 'msg' => '當前時刻令牌消耗完!'];}} else {$redisVal = json_encode(['num' => $initNum, 'time' => time()]);}$redis->multi();$redis->set($key, $redisVal);$rob_result = $redis->exec();if (!$rob_result) {$result = ['status' => false, 'msg' => '訪問頻次過多!'];}return $result;} }

代碼要點:1:首先定義規則
單個用戶每分鐘訪問次數($minNum),單個用戶每天總的訪問次數($dayNum),接口總的訪問次數等不同的規則。2:計算速率
該代碼示例以秒為最小的時間單位,速率=訪問次數/時間($initNum / $expire)3:每次訪問后補充的令牌個數計算方式
獲取上次訪問的時間即上次存入令牌的時間,計算當前時刻與上次訪問的時間差乘以速率就是此次需要補充的令牌個數,注意補充令牌后總的令牌個數不能大于初始化的令牌個數,以補充數和初始化數的最小值為準。4:程序流程
第一次訪問時初始化令牌個數($minNum),存入Redis同時將當前的時間戳存入以便計算下次需要補充的令牌個數。第二次訪問時獲取剩余的令牌個數,并添加本次應該補充的令牌個數,補充后如何令牌數>0則當前訪問是有效的可以訪問,否則令牌使用完畢不可訪問。先補充令牌再判斷令牌是否>0的原因是由于還有速率這個概念即如果上次剩余的令牌為0但是本次應該補充的令牌>1那么本次依然可以訪問。5:針對并發的處理
使用Redis的樂觀鎖機制

四、Redis樂觀鎖介紹

redis對事務的支持比較簡單。redis只能保證一個客戶端發起的事務命令可以執行,中間不會插入其他事務。因為redis是單線程的,所以做到上面這點很容易。一般redis接受到客戶端的命令后會立即執行,但是如果客戶端發起multi命令,redis不會立即執行,而是讓當前連接進入事務上下文,把命令放到隊列中,接受到exec命令后,redis會順序執行隊列中的命令。并把執行結果打包到一起返回客戶端,之后就結束了事務上下文

一、簡單的事務控制

這個例子可以看到:兩個set命令發出后并沒有立即執行而是放到隊列中,redis接受到exec命令才開始執行。
如果有兩個線程同時修改了一個變量的值,如何控制事務回滾?下面看樂觀鎖怎么控制的?

二、樂觀鎖控制事務1.什么是樂觀鎖?
大多是基于數據版本的記錄機制。什么是數據版本?就是為數據增加一個版本標識,即為數據庫表添加一個version字段,當讀取數據時,把數據庫版本一同讀出,當做了修改后,將數據庫版本+1,同修改一起提交。如果提交數據的版本號 >數據庫當前版本號,提交成功。如圖:

2.樂觀鎖實例
假設數據庫中賬戶信息表中有一個version字段,當前值為1,賬戶余額為$500

這樣避免了操作員B用舊數據修改表中記錄的的可能。3.在redis中怎么體現的?
redis中用watch監視key,如果key在提交前被修改,則提交不成功。如下:


當session1還沒來得及對age進行修改,session2已經將age的值設為30,session1再執行的時候失敗,因為session1對age加了樂觀鎖的緣故。
watch命令會監視key,當exec時如果監視的key從調用watch后發生過變化,則整個事務會失敗。也可以調用watch多次監視多個key。三、redis事務存在的問題
redis保證事務中的命令連續執行,但是如果其中一條命令執行失敗,事務并不回滾。

為age +1的命令成功,因為anme是string類型的,所以不能做加操作,命令有一個失敗也不會回滾,age的值已經被修改了。

以上內容希望幫助到大家,很多PHPer在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那里入手去提升,對此我整理了一些資料,包括但不限于:分布式架構、高可擴展、高性能、高并發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階干貨需要的可以免費分享給大家,需要戳這里PHP進階架構師>>>視頻、面試文檔免費獲取

或者關注咱們下面的知乎專欄

PHP7進階架構師?zhuanlan.zhihu.com來源:https://www.cnblogs.com/starluke/p/11845207.html

總結

以上是默认站点為你收集整理的十三水算法php_基于PHP+Redis令牌桶限流的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得默认站点網站內容還不錯,歡迎將默认站点推薦給好友。