處理高并發無非就是四大的方法 分流、緩存、降級、限流
1、分流
實現方式最簡單的是增加多臺機器,目的是為了擴容
基本思路是 Tomcat(萬以下,tomcat頂峰700并發)=》Nginx(3-4萬并發)=》lvs(30萬并發)=》F5(百萬并發)=》DNS
集群負載均衡
集群:
tomcat、jboss、weblogic、websphere
負載均衡:
軟件:nginx、Apache、haproxy … L7(網絡第7層)
lvs L4(網絡第4層)開源免費
硬件:f5 付費價格貴
DNS 負載均衡 域名解析 同一個域名根據ip解析到不同地域的數據中心,
(dns如何做到負載均衡例:
1) 客戶端訪問www.tmall.com , 用戶向本機配置的本地DNS服務器發出查詢請求,如果本地DNS服務器有該域名的緩存記錄,則返回給用戶,否則進行第2步;
2) 本地DNS服務器進行遞歸查詢,最終會查詢到域名服務商商處的授權DNS服務器;
3) 授權DNS服務器返回一條記錄給本地DNS服務器,這里的域名可能對應多個vip(虛擬ip),會根據全局負載均衡策略設定的不同可能返回一個或多個隨機返回一個vip;
6) 本地服務器將查詢結果通過一條A記錄返回給用戶,并將緩存這條記錄。)
均衡算法:輪詢、隨機等
假設天貓www.tmall.com的數據中心位于杭州,中心集群向各運行商(電信、聯通、移動)要最大限度的帶寬以提高高并發能力,這是一種分流方式,但類似雙11的情況,帶寬達不到要求,高并發能力不足,可能只占真實并發量的1/10的話就需要考慮cdn的方式,例如在全國多個人口密集的城市建立cdn集群節點,當深圳的用戶訪問天貓時,向深圳的cdn獲取資源。
這里需要解釋一下我理解的cdn的運作原理,下圖中訪問了www.tmall.com后會向杭州的中心集群發送請求,返回html中會有很多css、img、js的鏈接資源需要加載,這時就是根據相應的負載均衡的算法去獲取離客戶端最近的cdn中去獲取。
大致是從上倒下 兩臺lvs 服務器用來負載均衡、三臺haproxy做二級負載均衡、squid集群
客戶端發送請求,會去隨機選擇一臺lvs服務器,lvs服務器隨機下發到任意一臺haproxy服務器,再由haproxy服務器隨機選擇一臺squid節點進行查詢,如果有則直接返回,沒有的話會向源站(www.tmall.com)進行資源獲取,所有的squid統一調度,如果說用戶需要高相應,比如修改了商品的圖案,因為修改的東西是存放到中心集群上的,此時cdn集群中的squid節點要做到實時更新的話,需要源站統一修改。
緩存
上面說到的dns 、 cdn 分流都是實現緩存的方式
緩存的目的主要是為了提高訪問速率,以空間換時間。
限流
如果說擴容和提速的方式都用上了還是遇到了瓶頸該如何?答案是限流
限流的目的在于保護、保持正常可用
下面用代碼實現一個簡單的秒殺搶購功能
@RestController
public class OrderController {
//1 搶購,搶購數量為5
static long limit = 5;
private AtomicLong count = new AtomicLong(0l);//原子類型保證線程安全
@GetMApping(“add”)
public String doOrder(String name){ //此處不用加鎖的方式保證線程,性能不高
long c = count.incrementAndGet();
if(c > limit){
return “秒殺結束,謝謝參與!count =” + c;
}
return “恭喜,秒殺成功! count =” + c;
}
}
上面代碼只能保證一臺服務器的情況做到count統一。多臺機器如果采用這種方式,秒殺數量就成倍增加了,商家得虧死。如果多臺集群要保證數值統一,可以采用將數值存在數據庫中的方式,此處我采用的redis。redis是單線程且線程安全的。
pom中加入redis依賴:
redis.clients
jedis
3.0.1
代碼如下:
@GetMapping(“add2”)
public String doOrder2 (String name) { //此處不用加鎖的方式保證線程,性能不高
try (Jedis jedis = new Jedis(“localhost”, 6379)) {
long c = jedis.incr(name);
if (c > limit) {
return “秒殺結束,謝謝參與!count =” + c;
}
return “恭喜,秒殺成功! count =” + c;
}
}
降級
降級預案
在進行降級之前要對系統進行梳理,看看系統是不是可以丟卒保帥;從而梳理出哪些必須誓死保護,哪些可降級;比如可以參考日志級別設置預案:
一般:比如有些服務偶爾因為網絡抖動或者服務正在上線而超時,可以自動降級;
警告:有些服務在一段時間內成功率有波動(如在95~100%之間),可以自動降級或人工降級,并發送告警;
錯誤:比如可用率低于90%,或者數據庫連接池被打爆了,或者訪問量突然猛增到系統能承受的最大閥值,此時可以根據情況自動降級或者人工降級;
嚴重錯誤:比如因為特殊原因數據錯誤了,此時需要緊急人工降級。
降級按照是否自動化可分為:自動開關降級和人工開關降級。
降級按照功能可分為:讀服務降級、寫服務降級。
降級按照處于的系統層次可分為:多級降級。