作者:袋??飼養員員
cnblogs.com/GodHeng/p/8834810.html
隨著互聯網的發展,各項軟體的客戶量日益增多,當客戶量達到一定峰值時,當數以萬計的流量來臨時,程式的順利運行以及即時回應則顯得尤為重要,就像雙11那天的淘寶一樣,那么,如何設計架構才能夠抗住這千萬級的流量,
老板讓你抗住千萬級流量,如何做架構設計?
首先,要在我們架構設計的時候建立一些原則,
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協議的一種應用,用于網路資料傳輸時的流量控制,以避免擁塞的發生,該協議允許發送方在停止并等待確認前發送多個資料分組,由于發送方不必每發一個分組就停下來等待確認,因此該協議可以加速資料的傳輸,提高網路吞吐量,
發送視窗:就是發送端允許連續發送的幀的序號表,發送端可以不等待應答而連續發送資料(可以通過設定視窗的尺寸來控制)
接收視窗:接收方允許接收的幀的序串列,凡是落在接收視窗內的幀,接收方都必須處理,落在接收視窗外的幀將被丟棄,接收方每次允許接收的幀數稱為接收視窗的尺寸
演示地址:
https://media.pearsoncmg.com/aw/ecs_kurose_compnetwork_7/cw/content/interactiveanimations/selective-repeat-protocol/index.html
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. 計數器:最簡單的一種,通過控制時間段內的請求次數,
推薦去我的博客閱讀更多:
1.Java JVM、集合、多執行緒、新特性系列教程
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
4.Java、后端、架構、阿里巴巴等大廠最新面試題
覺得不錯,別忘了點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/165590.html
標籤:Java
下一篇:Spring系列.依賴注入配置
