做者:袋🐴飼養員員
cnblogs.com/GodHeng/p/8834810.html
html
隨着互聯網的發展,各項軟件的客戶量日益增多,當客戶量達到必定峯值時,當數以萬計的流量來臨時,程序的順利運行以及即時響應則顯得尤其重要,就像雙11那天的淘寶同樣。那麼,如何設計架構纔可以抗住這千萬級的流量。java
老闆讓你抗住千萬級流量,如何作架構設計?nginx
首先,要在咱們架構設計的時候創建一些原則。面試
1. 實現高併發算法
服務拆分:將整個項目拆分紅多個子項目或者模塊,分而治之,將項目進行水平擴展。數據庫
服務化:解決服務調用複雜以後的服務的註冊發現問題。後端
消息隊列:解耦,異步處理緩存
緩存:各類緩存帶來的併發服務器
2. 實現高可用網絡
集羣、限流、降級
3. 業務設計
冪等:就是用戶對於同一操做發起的一次請求或者屢次請求的結果是一致的,不會由於屢次點擊而產生了反作用,就像數學裏的數字1,多少次冪的結果都是1。舉個最簡單的例子,那就是支付,用戶購買商品後支付,支付扣款成功,可是返回結果的時候網絡異常,此時錢已經扣了,用戶再次點擊按鈕,此時會進行第二次扣款,返回結果成功,用戶查詢餘額發現多扣錢了,流水記錄也變成了兩條。
防重:防止一樣的數據同時提交
除了在業務方向判斷和按鈕點擊以後不能繼續點擊的限制之外,在服務器端也能夠作到防重:
在服務器端生成一個惟一的隨機標識號(Token<令牌>)同事在當前用戶的Session域中保存這個令牌,而後將令牌發送到客戶端的form表單中,在form表單中使用隱藏域來存儲這個Token,表單提交的時候聯通這個Token一塊兒提交到服務器,而後在服務器端判斷客戶提交上來的Token與服務器端生成的Token是否一致,若是不一致,那就重複提交了,此時服務器端就能夠不處理重複提交的表單,若是相同則處理表單,處理完後清楚當前用戶的Session域中存儲的標識號。高可用高併發架構參考:高可用高併發的 9 種技術架構。
在下列狀況中,服務器程序將拒絕處理用戶提交的表單請求:
1)存儲Session域中的Token與表單提交的Token不一致
2)當前用戶的Session中不存在Token
3)用戶提交的表單數據中沒有Token。
狀態機
軟件設計中的狀態機概念,通常是指有限狀態機(英語:finite-state machine,縮寫:FSM)又稱有限狀態自動機,簡稱狀態機,是表示有限個狀態以及在這些狀態之間的轉移和動做等行爲的數學模型。
這裏着重講一下限流的概念和例子
限流的目的
限流的目的是經過對併發訪問/請求進行限速或者一個時間窗口內的請求進行限速來保護系統的可用性,一旦達到限制速率就能夠拒絕服務。就像手機預售同樣,假如要賣出3萬臺,只須要接收3萬用戶的請求就能夠,其餘的用戶請求能夠選擇過濾,能夠提示"當前服務器過忙,請稍後再試"的提示。推薦你們看這篇文章:接口限流算法:漏桶算法&令牌桶算法。
限流方式:
1. 限制瞬時併發數 : 好比在入口層(nginx添加nginx_http_limit_conn_module)來限制同一個ip來源的鏈接數,防止惡意攻擊訪問的狀況。
2. 限制總併發數:經過配置數據庫鏈接池、線程池大小來約束總併發數
3. 限制時間窗口內的平均速率:在接口層面,經過限制訪問速率來控制接口的併發請求。
4. 其餘方式:限制遠程接口的調用速率、限制MQ的消費速率。
經常使用限流算法
1. 滑動窗口協議:一種常見的流量控制技術,用來改善吞吐量的技術。
滑動窗口協議的由來:
滑動窗口(sliding window)是一種流量控制技術。早期的網絡通信中,通訊雙方不會考慮網絡的擁擠狀況直接發送數據。因爲你們不知道網絡擁塞情況,同時發送數據,致使中間節點阻塞掉包,誰也發送不了數據,因此就有了滑動窗口機制來解決此問題。 發送和接收方都會維護一個數據幀的序列,這個序列被稱爲窗口。
定義:滑動窗口協議(Sliding Window Protocol),屬於TCP協議的一種應用,用於網絡數據傳輸時的流量控制,以免擁塞的發生。該協議容許發送方在中止並等待確認前發送多個數據分組。因爲發送方沒必要每發一個分組就停下來等待確認,所以該協議能夠加速數據的傳輸,提升網絡吞吐量。
發送窗口:就是發送端容許連續發送的幀的序號表。發送端能夠不等待應答而連續發送數據(能夠經過設置窗口的尺寸來控制)
接收窗口:接收方容許接收的幀的序列表,凡是落在接收窗口內的幀,接收方都必須處理,落在接收窗口外的幀將被丟棄。接收方每次容許接收的幀數稱爲接收窗口的尺寸
演示地址:
2. 漏桶:漏桶算法能強行限制數據的傳輸速率。
漏桶算法思路很簡單,請求先進入到漏桶裏,漏桶以必定的速度出水。當水請求過大會直接溢出,能夠看出漏桶算法能強行限制數據的傳輸速率。進入端無需考慮出水端的速率,就像mq消息隊列同樣,provider只須要將消息傳入隊列中,而不須要關心Consumer是否接收到了消息。
對於溢出的水,就是被過濾的數據,能夠直接被丟棄,也能夠經過某種方式暫時保存,如加入隊列之中,像線程池裏對溢出數據的4種處理機制同樣
3. 令牌桶:屬於控制速率類型的限流算法。
對於不少應用場景來講,除了要求可以限制數據的平均傳輸速率外,還要求容許某種程度的突發傳輸。這時候漏桶算法可能就不合適了,令牌桶算法更爲適合。令牌桶算法的原理是系統會以一個恆定的速度往桶裏放入令牌,而若是請求須要被處理,則須要先從桶裏獲取一個令牌,當桶裏沒有令牌可取時,則拒絕服務。
設置 Rate = 2 :每秒放入令牌的個數
桶的大小:100
這裏用一個小demo來實現一下令牌桶
public class TokenDemo { //qps:每秒鐘處理完請求的次數;tps:每秒鐘處理完的事務次數 //表明qps是10; RateLimiter rateLimiter = RateLimiter.create(10); public void doSomething(){ if (rateLimiter.tryAcquire()){ //嘗試得到令牌.爲true則獲取令牌成功 System.out.println("正常處理"); }else{ System.out.println("處理失敗"); } } public static void main(String args[]) throws IOException{ /* * CountDownLatch是經過一個計數器來實現的,計數器的初始值爲線程的數量,此值是線程將要等待的操做數(線程的數量)。 * 當某個線程爲了想要執行這些操做而等待時, 它要使用 await()方法。 * 此方法讓線程進入休眠直到操做完成。 * 當某個操做結束,它使用countDown() 方法來減小CountDownLatch類的內部計數器,計數器的值就會減1。 * 當計數器到達0時,它表示全部的線程已經完成了任務,這個類會喚醒所有使用await() 方法休眠的線程們恢復執行任務。 * * */ CountDownLatch latch = new CountDownLatch(1); Random random = new Random(10); TokenDemo tokenDemo = new TokenDemo(); for (int i=0;i<20;i++){ new Thread(()->{ try { latch.await(); Thread.sleep(random.nextInt(1000)); tokenDemo.doSomething(); }catch (InterruptedException e){ e.printStackTrace(); } }).start(); } latch.countDown(); System.in.read(); } }
執行結果:
正常處理 正常處理 正常處理 正常處理 正常處理 處理失敗 正常處理 處理失敗 處理失敗 處理失敗 正常處理 處理失敗 正常處理 處理失敗 正常處理 正常處理 正常處理 正常處理 處理失敗 處理失敗
因而可知,當令牌不足時,會獲取令牌失敗,達到限流的效果。
4. 計數器:最簡單的一種。經過控制時間段內的請求次數。
推薦去個人博客閱讀更多:
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
以爲不錯,別忘了點贊+轉發哦!