成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

我司“雙11”限流方案,進來抄作業!

網絡 通信技術 開發工具
日常生活中,有哪些需要限流的地方?像我旁邊有一個國家景區,平時可能根本沒什么人前往,但是一到十一或者春節就人滿為患,這時候景區管理人員就會實行一系列的政策來限制進入人流量,為什么要限流呢?

 [[430197]]

圖片來自 包圖網

假如景區能容納一萬人,現在進去了三萬人,勢必摩肩接踵,整不好還會有事故發生,這樣的結果就是所有人的體驗都不好。

如果發生了事故景區可能還要關閉,導致對外不可用,這樣的后果就是所有人都覺得體驗糟糕透了。

限流的思想就是,在保證可用的情況下盡可能多增加進入的人數,其余的人在外面排隊等待,保證里面的一萬人可以正常游玩。

回到網絡上,同樣也是這個道理,例如某某明星公布了戀情,訪問從平時的 50 萬增加到了 500 萬,系統最多可以支撐 200 萬訪問、雙十一的秒殺活動、12306 的搶票等。

那么就要執行限流規則,保證是一個可用的狀態,不至于服務器崩潰導致所有請求不可用。

限流思路

對系統服務進行限流,一般有如下幾個模式:

①熔斷

系統在設計之初就把熔斷措施考慮進去。當系統出現問題時,如果短時間內無法修復,系統要自動做出判斷,開啟熔斷開關,拒絕流量訪問,避免大流量對后端的過載請求。

系統也應該能夠動態監測后端程序的修復情況,當程序已恢復穩定時,可以關閉熔斷開關,恢復正常服務。

常見的熔斷組件有 Hystrix 以及阿里的 Sentinel,兩種互有優缺點,可以根據業務的實際情況進行選擇。

②服務降級

將系統的所有功能服務進行一個分級,當系統出現問題需要緊急限流時,可將不是那么重要的功能進行降級處理,停止服務,這樣可以釋放出更多的資源供給核心功能的去用。

例如在電商平臺中,如果突發流量激增,可臨時將商品評論、積分等非核心功能進行降級,停止這些服務,釋放出機器和 CPU 等資源來保障用戶正常下單。

而這些降級的功能服務可以等整個系統恢復正常后,再來啟動,進行補單/補償處理。

除了功能降級以外,還可以采用不直接操作數據庫,而全部讀緩存、寫緩存的方式作為臨時降級方案。

③延遲處理

這個模式需要在系統的前端設置一個流量緩沖池,將所有的請求全部緩沖進這個池子,不立即處理。

然后后端真正的業務處理程序從這個池子中取出請求依次處理,常見的可以用隊列模式來實現。

這就相當于用異步的方式去減少了后端的處理壓力,但是當流量較大時,后端的處理能力有限,緩沖池里的請求可能處理不及時,會有一定程度延遲。后面具體的漏桶算法以及令牌桶算法就是這個思路。

④特權處理

這個模式需要將用戶進行分類,通過預設的分類,讓系統優先處理需要高保障的用戶群體,其它用戶群的請求就會延遲處理或者直接不處理。

緩存、降級、限流區別如下:

  • 緩存,是用來增加系統吞吐量,提升訪問速度提供高并發。
  • 降級,是在系統某些服務組件不可用的時候、流量暴增、資源耗盡等情況下,暫時屏蔽掉出問題的服務,繼續提供降級服務,給用戶盡可能的友好提示,返回兜底數據,不會影響整體業務流程,待問題解決再重新上線服務

限流,是指在使用緩存和降級無效的場景。比如當達到閾值后限制接口調用頻率,訪問次數,庫存個數等,在出現服務不可用之前,提前把服務降級。只服務好一部分用戶。

限流的算法

限流算法很多,常見的有三類,分別是計數器算法、漏桶算法、令牌桶算法,下面逐一講解。

①計數器算法

簡單粗暴,比如指定線程池大小,指定數據庫連接池大小、Nnginx 連接數等,這都屬于計數器算法。

計數器算法是限流算法里最簡單也是最容易實現的一種算法。舉個例子,比如我們規定對于 A 接口,我們 1 分鐘的訪問次數不能超過 100 個。

那么我們可以這么做:在一開始的時候,我們可以設置一個計數器 counter,每當一個請求過來的時候,counter 就加 1。

如果 counter 的值大于 100 并且該請求與第一個請求的間隔時間還在 1 分鐘之內,那么說明請求數過多,拒絕訪問。

如果該請求與第一個請求的間隔時間大于 1 分鐘,且 counter 的值還在限流范圍內,那么就重置 counter,就是這么簡單粗暴。

②漏桶算法

漏桶算法思路很簡單,水(請求)先進入到漏桶里,漏桶以一定的速度出水,當水流入速度過大會超過桶可接納的容量時直接溢出,可以看出漏桶算法能強行限制數據的傳輸速率。

  • 削峰:有大量流量進入時,會發生溢出,從而限流保護服務可用。
  • 緩沖:不至于直接請求到服務器,緩沖壓力,消費速度固定,因為計算性能固定。

③令牌桶算法

令牌桶與漏桶相似,不同的是令牌桶桶中放了一些令牌,服務請求到達后,要獲取令牌之后才會得到服務。

舉個例子,我們平時去食堂吃飯,都是在食堂內窗口前排隊的,這就好比是漏桶算法,大量的人員聚集在食堂內窗口外,以一定的速度享受服務。

如果涌進來的人太多,食堂裝不下了,可能就有一部分人站到食堂外了,這就沒有享受到食堂的服務,稱之為溢出,溢出可以繼續請求,也就是繼續排隊,那么這樣有什么問題呢?

如果這時候有特殊情況,比如有些趕時間的志愿者啦或者高三要高考啦,這種情況就是突發情況。

如果也用漏桶算法那也得慢慢排隊,這也就沒有解決我們的需求,對于很多應用場景來說,除了要求能夠限制數據的平均傳輸速率外,還要求允許某種程度的突發傳輸。

這時候漏桶算法可能就不合適了,令牌桶算法更為適合。

如圖所示,令牌桶算法的原理是系統會以一個恒定的速度往桶里放入令牌,而如果請求需要被處理,則需要先從桶里獲取一個令牌,當桶里沒有令牌可取時,則拒絕服務。

并發限流

簡單來說就是設置系統閾值總的 QPS 個數,這些也挺常見的,就拿 Tomcat 來說,很多參數就是出于這個考慮。

例如配置的 acceptCount 設置響應連接數,maxConnections 設置瞬時最大連接數,maxThreads 設置最大線程數。

在各個框架或者組件中,并發限流體現在下面幾個方面:

  • 限制總并發數(如數據庫連接池、線程池)
  • 限制瞬時并發數(nginx 的 limit_conn 模塊,用來限制瞬時并發連接數)
  • 限制時間窗口內的平均速率(如 Guava 的 RateLimiter、nginx 的 limit_req 模塊,限制每秒的平均速率)
  • 其他的還有限制遠程接口調用速率、限制 MQ 的消費速率。
  • 另外還可以根據網絡連接數、網絡流量、CPU 或內存負載等來限流。

有了并發限流,就意味著在處理高并發的時候多了一種保護機制,不用擔心瞬間流量導致系統掛掉或雪崩,最終做到有損服務而不是不服務。

但是限流需要評估好,不能亂用,否則一些正常流量出現一些奇怪的問題而導致用戶體驗很差造成用戶流失。

接口限流

接口限流分為兩個部分,一是限制一段時間內接口調用次數,參照前面限流算法的計數器算法,二是設置滑動時間窗口算法。

①接口總數

控制一段時間內接口被調用的總數量,可以參考前面的計數器算法,不再贅述。

②接口時間窗口

固定時間窗口算法(也就是前面提到的計數器算法)的問題是統計區間太大,限流不夠精確,而且在第二個統計區間時沒有考慮與前一個統計區間的關系與影響(第一個區間后半段+第二個區間前半段也是一分鐘)。

為了解決上面我們提到的臨界問題,我們試圖把每個統計區間分為更小的統計區間,更精確的統計計數。

在上面的例子中,假設 QPS 可以接受 100 次查詢/秒,前一分鐘前 40 秒訪問很低,后 20 秒突增,并且這個持續了一段時間,直到第二分鐘的第 40 秒才開始降下來。

根據前面的計數方法,前一秒的 QPS 為 94,,后一秒的 QPS 為 92,那么沒有超過設定參數。

但是在中間區域,QPS 達到了 142,,這明顯超過了我們的允許的服務請求數目,所以固定窗口計數器不太可靠,需要滑動窗口計數器。

計數器算法其實就是固定窗口算法,只是它沒有對時間窗口做進一步地劃分,所以只有 1 格。

由此可見,當滑動窗口的格子劃分的越多,也就是將秒精確到毫秒或者納秒,那么滑動窗口的滾動就越平滑,限流的統計就會越精確。需要注意的是,消耗的空間就越多。

限流實現

這一部分是限流的具體實現,簡單說說,畢竟長篇代碼沒人愿意看。

①guava 實現

引入包:

  1. <!-- https://mvnrepository.com/artifact/com.google.guava/guava --> 
  2. <dependency> 
  3.     <groupId>com.google.guava</groupId> 
  4.     <artifactId>guava</artifactId> 
  5.     <version>28.1-jre</version> 
  6. </dependency> 

核心代碼:

  1. LoadingCache<Long, AtomicLong> counter = CacheBuilder.newBuilder(). 
  2.   expireAfterWrite(2, TimeUnit.SECONDS) 
  3.   .build(new CacheLoader<Long, AtomicLong>() { 
  4.  
  5.    @Override 
  6.    public AtomicLong load(Long secend) throws Exception { 
  7.     // TODO Auto-generated method stub 
  8.     return new AtomicLong(0); 
  9.    } 
  10.   }); 
  11. counter.get(1l).incrementAndGet(); 

②令牌桶實現

穩定模式(SmoothBursty:令牌生成速度恒定):

  1. public static void main(String[] args) { 
  2.  // RateLimiter.create(2)每秒產生的令牌數 
  3.  RateLimiter limiter = RateLimiter.create(2); 
  4.     // limiter.acquire() 阻塞的方式獲取令牌 
  5.  System.out.println(limiter.acquire());; 
  6.  try { 
  7.   Thread.sleep(2000); 
  8.  } catch (InterruptedException e) { 
  9.   // TODO Auto-generated catch block 
  10.   e.printStackTrace(); 
  11.  } 
  12.  System.out.println(limiter.acquire());; 
  13.  System.out.println(limiter.acquire());; 
  14.  System.out.println(limiter.acquire());; 
  15.  System.out.println(limiter.acquire());; 
  16.  
  17.  System.out.println(limiter.acquire());; 
  18.  System.out.println(limiter.acquire());; 

RateLimiter.create(2) 容量和突發量,令牌桶算法允許將一段時間內沒有消費的令牌暫存到令牌桶中,用來突發消費。

漸進模式(SmoothWarmingUp:令牌生成速度緩慢提升直到維持在一個穩定值):

  1. // 平滑限流,從冷啟動速率(滿的)到平均消費速率的時間間隔 
  2. RateLimiter limiter = RateLimiter.create(2,1000l,TimeUnit.MILLISECONDS); 
  3. System.out.println(limiter.acquire());; 
  4. try { 
  5.  Thread.sleep(2000); 
  6. } catch (InterruptedException e) { 
  7.  // TODO Auto-generated catch block 
  8.  e.printStackTrace(); 
  9. System.out.println(limiter.acquire()); 
  10. System.out.println(limiter.acquire()); 
  11. System.out.println(limiter.acquire()); 
  12. System.out.println(limiter.acquire()); 
  13.  
  14. System.out.println(limiter.acquire()); 
  15. System.out.println(limiter.acquire()); 

超時:

  1. boolean tryAcquire = limiter.tryAcquire(Duration.ofMillis(11)); 

在 timeout 時間內是否能夠獲得令牌,異步執行。

③分布式系統限流(Nginx+Lua 實現)

可以使用 resty.lock 保持原子特性,請求之間不會產生鎖的重入:

https://github.com/openresty/lua-resty-lock

使用 lua_shared_dict 存儲數據:

  1. local locks = require "resty.lock" 
  2.  
  3. local function acquire() 
  4.     local lock =locks:new("locks"
  5.     local elapsed, err =lock:lock("limit_key"-- 互斥鎖 保證原子特性 
  6.     local limit_counter =ngx.shared.limit_counter -- 計數器 
  7.  
  8.     local key = "ip:" ..os.time() 
  9.     local limit = 5 -- 限流大小 
  10.     local current =limit_counter:get(key
  11.  
  12.     if current ~= nil and current + 1> limit then -- 如果超出限流大小 
  13.        lock:unlock() 
  14.        return 0 
  15.     end 
  16.     if current == nil then 
  17.        limit_counter:set(key, 1, 1) -- 第一次需要設置過期時間,設置key的值為1, 
  18.        -- 過期時間為1秒 
  19.     else 
  20.         limit_counter:incr(key, 1) -- 第二次開始加1即可 
  21.     end 
  22.     lock:unlock() 
  23.     return 1 
  24. end 
  25. ngx.print(acquire()) 

作者:等不到的口琴

編輯:陶家龍

出處:https://urlify.cn/fuAB7j

 

責任編輯:武曉燕 來源: urlify
相關推薦

2020-12-29 09:23:40

分庫分表訂單

2021-10-28 19:10:51

RustPythonjs

2020-09-24 12:32:41

微軟開發 AI

2024-11-21 15:29:34

2025-02-26 07:40:25

運營分析體系運營策略

2021-03-31 10:12:12

MongoDBQPS存儲

2020-04-29 11:06:26

Redis分布式限流器

2021-07-23 14:58:28

Nginx限流方案

2021-04-21 07:53:12

Java限流器管理

2021-06-09 11:28:04

用戶畫像標簽

2022-12-28 11:44:19

用戶畫像互聯網用戶信息

2023-11-01 11:34:40

用戶畫像企業

2022-02-17 08:54:44

Service開發Mybatis

2021-03-30 10:46:42

SpringBoot計數器漏桶算法

2023-07-26 15:15:53

AI

2013-11-08 10:21:13

2016-11-10 13:09:33

2021-04-25 09:00:14

項目互聯網上線

2014-02-26 11:22:38

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 粉嫩一区二区三区性色av | 亚洲欧美日韩精品久久亚洲区 | 欧美福利 | jizz视频 | 五月综合久久 | 自拍偷拍第一页 | 韩国毛片一区二区三区 | 日本大香伊一区二区三区 | 久国产视频 | 九九亚洲精品 | 黑人性hd | 中文字幕成人av | 亚洲日本欧美日韩高观看 | 久久久久国 | 国产91视频免费 | 亚洲精品免费视频 | 天天艹逼网 | 亚洲精品黄色 | 91亚洲精品在线观看 | 国产一区二区在线视频 | 国产视频不卡一区 | av在线一区二区三区 | 国产精品午夜电影 | 久久69精品久久久久久久电影好 | 国产在线一区二 | 成人在线精品视频 | 日韩免费高清视频 | 国产成人免费 | 天天干天天草 | 国产精品1区 | 97人人澡人人爽91综合色 | 国产亚洲精品久久久优势 | 久久一区二区av | 午夜一区二区三区在线观看 | 蜜桃在线一区二区三区 | 欧美在线视频一区二区 | 黄色网毛片| 国产精品www | 精品自拍视频 | 国产免费一区二区三区网站免费 | 亚洲一区二区 |