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