HTTP 的負(fù)載均衡你了解么?你不是說了你們用的Nginx么?
本篇文章將會從一個朋友的面試題入手,來說一下關(guān)于 HTTP 的重定向和負(fù)載均衡。
1.HTTP 重定向
1.1 重定向是什么
重定向(Redirect)就是通過各種方法將各種網(wǎng)絡(luò)請求重新定個方向轉(zhuǎn)到其它位置(如:網(wǎng)頁重定向、域名的重定向、路由選擇的變化也是對數(shù)據(jù)報文經(jīng)由路徑的一種重定向)。
上面是百度百科的解釋,其實我在想到重定向的時候,第一反應(yīng)是 Java 中的轉(zhuǎn)發(fā)和重定向,其實道理差不多。聽我來分析一波。
其實 HTTP 的重定向也算是 URL 的重定向,而URL 重定向,也稱為 URL 轉(zhuǎn)發(fā),是一種當(dāng)實際資源,如單個頁面、表單或者整個 Web 應(yīng)用被遷移到新的 URL 下的時候,保持(原有)鏈接可用的技術(shù)。HTTP 協(xié)議提供了一種特殊形式的響應(yīng)—— HTTP 重定向(HTTP redirects)來執(zhí)行此類操作,該操作可以應(yīng)用于多種多樣的目標(biāo):網(wǎng)站維護(hù)期間的臨時跳轉(zhuǎn),網(wǎng)站架構(gòu)改變后為了保持外部鏈接繼續(xù)可用的永久重定向,上傳文件時的表示進(jìn)度的頁面。
1.2 為什么要進(jìn)行重定向
可靠地執(zhí)行 HTTP 事務(wù);
最小化時延;
節(jié)約網(wǎng)絡(luò)帶寬;
出于這些原因,Web 內(nèi)容通常分布在很多地方。這么做是出于可靠性的考慮。這樣,如 果一個位置出問題了,還有其他的可用;如果客戶端能去訪問較近的資源,就可以更快地 收到所請求的內(nèi)容,以降低響應(yīng)時間;將目標(biāo)服務(wù)器分散,還可以減少網(wǎng)絡(luò)擁塞。
1.3負(fù)載均衡的部署方式
負(fù)載均衡有三種部署方式:路由模式、橋接模式、服務(wù)直接返回模式。路由模式部署靈活,約60%的用戶采用這種方式部署;橋接模式不改變現(xiàn)有的網(wǎng)絡(luò)架構(gòu);服務(wù)直接返回(DSR)比較適合吞吐量大特別是內(nèi)容分發(fā)的網(wǎng)絡(luò)應(yīng)用。約30%的用戶采用這種模式。
1、路由模式(推薦)
路由模式的部署方式,服務(wù)器的網(wǎng)關(guān)必須設(shè)置成負(fù)載均衡機(jī)的LAN口地址,且與WAN口分署不同的邏輯網(wǎng)絡(luò)。因此所有返回的流量也都經(jīng)過負(fù)載均衡。這種方式對網(wǎng)絡(luò)的改動小,能均衡任何下行流量。
2、橋接模式
橋接模式配置簡單,不改變現(xiàn)有網(wǎng)絡(luò)。負(fù)載均衡的WAN口和LAN口分別連接上行設(shè)備和下行服務(wù)器。LAN口不需要配置IP(WAN口與LAN口是橋連接),所有的服務(wù)器與負(fù)載均衡均在同一邏輯網(wǎng)絡(luò)中。由于這種安裝方式容錯性差,網(wǎng)絡(luò)架構(gòu)缺乏彈性,對廣播風(fēng)暴及其他生成樹協(xié)議循環(huán)相關(guān)聯(lián)的錯誤敏感,因此一般不推薦這種安裝架構(gòu)。
3、服務(wù)直接返回模式
這種安裝方式負(fù)載均衡的LAN口不使用,WAN口與服務(wù)器在同一個網(wǎng)絡(luò)中,互聯(lián)網(wǎng)的客戶端訪問負(fù)載均衡的虛IP(VIP),虛IP對應(yīng)負(fù)載均衡機(jī)的WAN口,負(fù)載均衡根據(jù)策略將流量分發(fā)到服務(wù)器上,服務(wù)器直接響應(yīng)客戶端的請求。因此對于客戶端而言,響應(yīng)他的IP不是負(fù)載均衡機(jī)的虛IP(VIP),而是服務(wù)器自身的IP地址。也就是說返回的流量是不經(jīng)過負(fù)載均衡的。因此這種方式適用大流量高帶寬要求的服務(wù)。
2.常見的軟件負(fù)載均衡技術(shù)
1、基于DNS的負(fù)載均衡
由于在DNS服務(wù)器中,可以為多個不同的地址配置相同的名字,最終查詢這個名字的客戶機(jī)將在解析這個名字時得到其中一個地址,所以這種代理方式是通過DNS服務(wù)中的隨機(jī)名字解析域名和IP來實現(xiàn)負(fù)載均衡。
2、反向代理負(fù)載均衡(如Apache+JK2+Tomcat這種組合)
該種代理方式與普通的代理方式不同,標(biāo)準(zhǔn)代理方式是客戶使用代理訪問多個外部Web服務(wù)器,之所以被稱為反向代理模式是因為這種代理方式是多個客戶使用它訪問內(nèi)部Web服務(wù)器,而非訪問外部服務(wù)器。
3、基于NAT(Network Address Translation)的負(fù)載均衡技術(shù)(如Linux VirtualServer,簡稱LVS)
該技術(shù)通過一個地址轉(zhuǎn)換網(wǎng)關(guān)將每個外部連接均勻轉(zhuǎn)換為不同的內(nèi)部服務(wù)器地址,因此外部網(wǎng)絡(luò)中的計算機(jī)就各自與自己轉(zhuǎn)換得到的地址上的服務(wù)器進(jìn)行通信,從而達(dá)到負(fù)載均衡的目的。其中網(wǎng)絡(luò)地址轉(zhuǎn)換網(wǎng)關(guān)位于外部地址和內(nèi)部地址之間,不僅可以實現(xiàn)當(dāng)外部客戶機(jī)訪問轉(zhuǎn)換網(wǎng)關(guān)的某一外部地址時可以轉(zhuǎn)發(fā)到某一映射的內(nèi)部的地址上,還可使內(nèi)部地址的計算機(jī)能訪問外部網(wǎng)絡(luò)。
其實在Nginx里面實現(xiàn)負(fù)載均衡的時候,就是通過第二種,反向代理負(fù)載均衡,關(guān)于這個,之前的文章公眾號有專門的實現(xiàn)反向代理實現(xiàn)負(fù)載均衡的一篇文章,地址給大家奉上 【http://www.justdojava.com/2019/09/05/nginx-tomcat/】
3.負(fù)載均衡算法(重點)
1、輪詢法
輪詢法,就是將用戶的請求輪流分配給服務(wù)器,就像是挨個數(shù)數(shù),輪流分配。這種算法比較簡單,他具有絕對均衡的優(yōu)點,但是也正是因為絕對均衡它必須付出很大的代價,例如它無法保證分配任務(wù)的合理性,無法根據(jù)服務(wù)器承受能力來分配任務(wù)。
其實說白了就是將請求按順序輪流地分配到每個節(jié)點上,不關(guān)心每個節(jié)點實際的連接數(shù)和當(dāng)前的系統(tǒng)負(fù)載。
這種方式的優(yōu)點很明顯缺點也同樣的明顯。
優(yōu)點:簡單高效,易于水平擴(kuò)展,每個節(jié)點滿足字面意義上的均衡,它無需記錄當(dāng)前所有連接的狀態(tài),所以它是一種無狀態(tài)調(diào)度。
缺點:沒有考慮機(jī)器的性能問題,根據(jù)木桶最短木板理論,集群性能瓶頸更多的會受性能差的服務(wù)器影響。
給大家個最簡單的圖:
給大家展示一下簡單的代碼處理:
- public static void main(String[] args) {
- int[] arr = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
- int index = 4; // 索引:指定起始位置
- for (int i = 0; i < 17; i++) {
- int nextIndex = (index + 1) % arr.length;
- index = nextIndex;
- System.out.println(arr[index] + " ,index=" + index);
- }
- }
2、隨機(jī)法
隨機(jī)法,是隨機(jī)選擇一臺服務(wù)器來分配任務(wù)。它保證了請求的分散性達(dá)到了均衡的目的。同時它是沒有狀態(tài)的不需要維持上次的選擇狀態(tài)和均衡因子[5]。但是隨著任務(wù)量的增大,它的效果趨向輪詢后也會具有輪詢算法的部分缺點。
其實隨機(jī)法的優(yōu)缺點和輪訓(xùn)法的優(yōu)缺點差不多,不做太多的敘述了。
算法偽代碼:
- private static Map<String, Integer> serviceWeightMap = new HashMap<String, Integer>();
- static {
- serviceWeightMap.put("192.168.1.100", 1);
- serviceWeightMap.put("192.168.1.101", 1);
- serviceWeightMap.put("192.168.1.102", 4);
- serviceWeightMap.put("192.168.1.103", 1);
- }
- public static String testRandom() {
- // 重新創(chuàng)建一個map,避免出現(xiàn)由于服務(wù)器上線和下線導(dǎo)致的并發(fā)問題
- Map<String, Integer> serverMap = new HashMap<String, Integer>();
- serverMap.putAll(serviceWeightMap);
- //取得IP地址list
- Set<String> keySet = serverMap.keySet();
- ArrayList<String> keyList = new ArrayList<String>();
- keyList.addAll(keySet);
- Random random = new Random();
- int randomPos = random.nextInt(keyList.size());
- String server = keyList.get(randomPos);
- return server;
- }
3、最小連接法
最小連接法,將任務(wù)分配給此時具有最小連接數(shù)的節(jié)點,因此它是動態(tài)負(fù)載均衡算法。一個節(jié)點收到一個任務(wù)后連接數(shù)就會加1,當(dāng)節(jié)點故障時就將節(jié)點權(quán)值設(shè)置為0,不再給節(jié)點分配任務(wù)。
最小連接法適用于各個節(jié)點處理的性能相似時。任務(wù)分發(fā)單元會將任務(wù)平滑分配給服務(wù)器。但當(dāng)服務(wù)器性能差距較大時,就無法達(dá)到預(yù)期的效果。因為此時連接數(shù)并不能準(zhǔn)確表明處理能力,連接數(shù)小而自身性能很差的服務(wù)器可能不及連接數(shù)大而自身性能極好的服務(wù)器。所以在這個時候就會導(dǎo)致任務(wù)無法準(zhǔn)確的分配到剩余處理能力強的機(jī)器上。
其實還有好幾種算法呢,比如說,源地址哈希法 ,加權(quán)輪詢(Weight Round Robin)法等。