什么是負載均衡技術
負載均衡器是一種軟體或硬體設備,它起到了將網路流量分散到一組服務器的作用,可以防止任何一臺服務器過載,負載均衡演算法就是負載均衡器用來在服務器之間分配網路流量的邏輯(演算法是一組預定義的規則),有時候也叫做負載均衡的型別,負載均衡演算法的種類非常多,包括從簡單的輪詢負載均衡演算法到基于回應狀態資訊的自適應負載均衡演算法,
負載均衡演算法的選擇會影響負載分配機制的有效性,從而影響性能和業務連續性(也就是對外承諾的SLA),選擇正確的負載均衡演算法會對應用程式性能產生重大影響,
本文將會介紹常見的負載均衡演算法,并結合主流負載均衡軟體或硬體設備介紹各種負載均衡演算法的實作方式
常見負載均衡演算法介紹
Round Robin(輪詢負載均衡演算法)
在所有負載均衡演算法中,輪詢負載均衡演算法是最簡單的、最常用的負載均衡演算法,客戶端請求以簡單的輪換方式分發到應用程式服務器上,例如,假設有三臺應用程式服務器:第一個客戶端請求發送到第一臺應用程式服務器,第二個客戶端請求發送到第二臺應用程式服務器,第三個客戶端請求發送到第三臺應用程式服務器,第四個客戶端請求重新從第一臺應用程式服務器開始,依次往復,

輪詢負載均衡適合所有客戶端請求都需要相同的服務器負載,并且所有的服務器實體都具有相同的服務器容量和資源(比如網路帶寬和存盤)
Weighted Round Robin(加權輪詢負載均衡演算法)
加權負載均衡演算法與輪詢演算法相似,增加了根據每個服務器的相對容量來將請求分散到不同服務器的能力,它適合將傳入的客戶端請求分散到一組具有不同功能或具有不同負載容量的服務器上,服務器集群管理員根據一個標準為每個應用程式服務器分配一個權重,這個標準表示每個服務器對請求的相對處理能力,
例如,如果在其他資源都是無窮多的情況下,假如服務器#1的CPU核心數是服務器#2和服務器#3的CPU核心數的二倍,那么服務器#1的權重更高,而服務器#2和#3的權重相同(都比#1低),如果我們有4個連續的客戶端請求,那么有2次請求發送到#1,另外2次請求分別發送到#2和#3,
加權輪詢負載均衡演算法描述的是在一段時間內負載的分布情況,不同的加權輪詢負載均衡演算法可能會產生不同的選擇序列,不應該對處理下一次負載的服務器進行假設,

Least Connections(最少連接負載均衡演算法)
最少連接負載均衡演算法又叫做最少等待請求演算法(Least Outstanding Request, LOR),最少連接負載均衡是一種動態負載均衡演算法,客戶端請求被分發到在接收到請求時活動連接數最少的應用服務器,在應用服務器具有類似規格的情況下,一臺服務器可能會因為連接數過多而過載(無法接收請求也屬于過載),這個演算法考慮了活動連接負載,這種技術適合具有不同連接時間的傳入請求(多機房)以及一組在處理能力和可用資源方面相對相似的服務器,
Weighted Least Connections(加權最少連接負載均衡演算法)
加權最少連接建立在最少連接負載均衡演算法上,考慮不同的應用程式服務器特性,與加權輪詢負載均衡演算法相同,服務器集群管理員根據一個標準為每個應用程式服務器分配一個權重,這個標準表示每個服務器對請求的相對處理能力,負載均衡器根據活動鏈接和分配的服務器權重做出負載平衡決策(例如,使用連接數乘以權重的倒數,選擇值最高的服務器),
Resource Based(基于資源的負載均衡演算法)
基于資源的負載均衡演算法又叫做自適應負載均衡演算法,基于資源的負載均衡演算法根據后端服務器提供的狀態指標來做出決策,這個狀態指標可以由一個運行在服務器上的自定義應用程式(比如agent),或從基礎設施提供方的開放介面獲取,負載均衡器定期查詢每臺服務器的狀態指標,然后適當地調整服務器的動態權重,
在這種方式下,負載均衡演算法實際上是在每臺真實服務器上執行健康檢查,這個演算法適用于任何需要來自每臺服務器的詳細健康檢查資訊來做出負載均衡決策的情況,
例如:此演算法適用于作業負載多變且需要詳細的應用程式性能和狀態來評估服務器運行狀態的任何應用程式(例如CPU密集型的最短路徑計算,或其他高性能計算場景),
Fixed Weighting(固定權重負載均衡演算法)
固定權重負載均衡演算法允許服務器集群管理員根據他們的標準為每個應用程式服務器分配一個權重,以表示每個服務器的相對流量處理能力,權重最高的應用服務器將接收所有流量,如果權重最高的應用服務器出現故障,所有流量將會被引導到下一個權重最高的應用服務器,此方法適用于單個服務器能夠處理所有預期傳入請求的作業負載,如果當前活動的服務器發生故障,一個或多個“熱備用”服務器可以直接用于承擔負載,
Weighted Response Time(加權回應時間負載均衡演算法)
加權回應時間負載均衡演算法使用應用程式的回應時間來計算服務器權重,回應速度最快的應用程式服務器接收下一個請求,此方法適用于應用程式回應時間是最重要的問題的場景,
當應用程式提供的是對外開放服務時尤為重要,因為對外開放服務都會為合作伙伴提供服務級別協議(Service Level Argument,SLA),而SLA中承諾的主要就是服務的可用性與服務的回應時間(TP99、TP999等),
Source IP Hash(源地址哈希負載均衡演算法)
源地址哈希負載均衡演算法使用客戶端請求的源IP與目標IP地址生成唯一的哈希密鑰,用于將客戶端請求分配給特定的服務器,如果傳輸層會話中斷,可以重新密鑰,因此客戶端請求將會被定向到它之前使用的統一服務器,當客戶端對于每個連續連接始侄訓傳到同一服務器至關重要時,此方法最適用,
服務端研發經常接觸的資料庫事務就適用于此場景
Consistent Hash(一致性哈希負載均衡演算法)
一致性哈希負載均衡演算法類似于源地址哈希,不同在于一致性哈希負載均衡演算法可以使用任意應用引陣列成唯一的哈希密鑰,并且當服務器集群發生變化時可以盡可能少地進行資料遷移,
常見負載均衡演算法實作
本節將會介紹各種常見負載均衡演算法的實作方式,某些負載均衡演算法具有多種不同的實作方式,并且每種實作方式都有各自適用的場景,這些不同的實作方式也會在本節進行介紹,同時本節中會假設所有的請求都是線性的,不會處理并發安全相關的細節,
Round Robin(輪詢負載均衡演算法)
在所有負載均衡演算法中,輪詢負載均衡演算法實作起來最簡單,只需要一個變數表示當前位置并不斷增加即可,
public class RoundRobinLoadBalancer { private final List instances; private int position; public RoundRobinLoadBalancer(List instances) { this.instances = instances; this.position = ThreadLocalRandom.current().nextInt(instances.size()); } public ServiceInstance peek(HttpServletRequest request) { int peeked = (position++) & Integer.MAX_VALUE; return instances.get(peeked % instances.size()); } }
這里有兩個需要注意的點
-
當我們初始化位置時,需要將其設定為一個隨機值,避免多個負載均衡器同時請求同一個服務器,造成服務器的瞬時壓力
-
在位置自增時,需要忽略符號位,因為Java沒有無符號整數,所以當位置的值超出整型最大值時會變成負值導致拋出例外,至于為什么不能使用絕對值,是因為整型的最小值沒有對應的絕對值,得到的依舊是負值(Spring Cloud #1074)
Weighted Round Robin(加權輪詢負載均衡演算法)
加權輪詢負載均衡演算法有很多主流的實作,并且各自都有各自的優點,雖然加權負載均衡產生任意符合全總分配比例分布的選擇序列都是合適的,但在短時間視窗內是否能夠選擇盡可能多的節點提供服務仍是評價加權負載均衡實作的質量的關鍵指標,
陣列展開方式
陣列展開實作方式是一種適用空間換時間的策略,適用于較小的服務器集群或專用型負載均衡設備,它的優點是速度非常快,與Round Robin實作完全一致,它的缺點也很明顯,當權重的總和很大時會帶來很大的記憶體開銷
public class WeightedLoadBalancer { private final List instances; private int position; public WeightedLoadBalancer(List instances) { this.instances = expandByWeight(instances); } public ServiceInstance peek(HttpServletRequest request) { int peeked = (position++) & Integer.MAX_VALUE; return instances.get(peeked % instances.size()); } private List expandByWeight(List instances) { List newInstances = new ArrayList<>(); for (ServiceInstance instance : instances) { int bound = instance.getWeight(); for (int w = 0; weight < bound; weight++) { newInstances.add(instance); } } Collections.shuffle(newInstances); return newInstances; } }
這里有三個需要注意的點:
-
當實體按權重展開成陣列的時候,可能會出現實體權重都很大,但是它們的最大公約數不為1,這個時候可以使用最大公約數來減少展開后的陣列大小,因為最大公約數的諸多限制,例如任意自然數N與N+1互質,任意自然數N與1互質,所以很容易出現優化失敗的情況,因此本示例并未給出,感興趣的可以去看Spring Cloud相關PR(Spring Cloud #1140)
-
在實體按權重展開成陣列后,需要對得到的陣列進行洗牌,以保證流量盡可能均勻,避免連續請求相同實體(Java中實作的洗牌演算法是Fisher-Yates演算法,其他語言可以自行實作)
-
因為是在構建負載均衡器的時候按權重展開成陣列的,所以在負載均衡器構建完成后無法再改變實體的權值,對于頻繁動態變更權重的場景不適用
上界收斂選擇方式
上界收斂選擇方式提前計算出所有權重的最大值,并將初始上界設定為所有權重的最大值,接下來我們一輪一輪地去遍歷所有實體,并找到權重大于等于上界的實體,當前輪遍歷結束后,所有大于等于上界的元素都被選取到了,接下來開始嘗試權重更低的節點,直到最后上界為0時,將其重新置為最大值,目前openresty (有人在issue #44上分析了這種演算法)



public class WeightedLoadBalancer { private final List instances; private final int max; private final int gcd; private int bound; private int position; public WeightedLoadBalancer(List instances) { this.instances = instances; this.max = calculateMaxByWeight(instances); this.gcd = calculateGcdByWeight(instances); this.position = ThreadLocalRandom.current().nextInt(instances.size()); } public ServiceInstance peek(HttpServletRequest request) { if (bound == 0) { bound = max; } while (instances.size() > 0) { for (int peeked = position; peeked < instances.size(); peeked++) { ServiceInstance instance = instances.get(peeked); if (instance.getWeight() >= bound) { position = peeked + 1; return instance; } } position = 0; bound = bound - gcd; } return null; } private static int calculateMaxByWeight(List instances) { int max = 0; for (ServiceInstance instance : instances) { if (instance.getWeight() > max) { max = instance.getWeight(); } } return max; } private static int calculateGcdByWeight(List instances) { int gcd = 0; for (ServiceInstance instance : instances) { gcd = gcd(gcd, instance.getWeight()); } return gcd; } private static int gcd(int a, int b) { if (b == 0) { return a; } return gcd(b, a % b); } }
這里面有四個需要注意的點:
-
如果是短頻率請求,將會一直訪問高權重實體,導致在短時間視窗內負載看起來并不均勻,這個可以通過改變方向,從下界向上界逼近來解決,
-
每一輪后降低上界的值可以取所有權重的最大公約數,因為如果每次下降1的話,中間這些輪會反復請求權重最高的那些實體,導致負載不均衡,
-
雖然最大公約數可以減少下降次數,但是如果權重相差非常多,并且所有元素都是互質的(n與n+1互質,任意自然數n與1互質,在實踐中非常容易出現),那么在上界下降的程序中將會帶來很多空轉,這個可以參考廣度優先遍歷的思想,使用先入先出的佇列來減少空轉,
-
與陣列展開方式遇到的問題相同,因為是在構建負載均衡器的時候計算最大公約數的值,所以對于頻繁動態變更權重的場景依舊會有很大的性能開銷,但是相較于陣列展開方式可以避免頻繁動態分配陣列導致的性能與記憶體碎片問題
權重輪轉實作
權重輪轉演算法中將會存盤兩個權重的值,一個是不會變化的原始權重,一個是會隨著每次選擇變化的當前權重,權重輪轉實作中維護了一個回圈不變數——所有節點的當前權重的和為0,每輪遍歷程序中所有實體的有效權重都會增加它的原始權重,并選擇出當前權重最高的節點,選擇出權重最高的節點后將它的當前權重減去所有實體權重的總和,以避免它再次被選擇,NGINX中加權輪詢負載均衡演算法使用此實作(NGINX),這種演算法的優勢是它很平滑,低權重節點的等待時間較短,并且每輪權重輪轉的最小正周期很小,是所有服務器實體權重的和,,
在NGINX中又叫做平滑加權負載均衡(Smooth Weighted Load Balancing,SWRR),

public class WeightedLoadBalancer { private final List instances; public WeightedLoadBalancer(List instances) { this.instances = instances; } public ServiceInstance peek(HttpServletRequest request) { ServiceInstance best = null; int total = 0; for (ServiceInstance instance : instances) { total += instance.getWeight(); instance.setCurrentWeight(instance.getCurrentWeight() + instance.getWeight()); if (best == null || instance.getCurrentWeight() > best.getCurrentWeight()) { best = instance; } } if (best != null) { best.setCurrentWeight(best.getCurrentWeight() - total); } return best; } }
這里面有三個需要注意的點:
-
權重輪轉非常適合實體變化頻率非常高的集合,因為它不需要提前構建資料結構
-
權重輪轉實作的效率與實體數量相關,時間復雜度是O(n),當集群服務器數量非常大時需要限制每次參與選擇的服務器數量(Spring Cloud #1111)
-
權重輪轉實作需要修改服務器實體的資料結構,當服務實體是由其他機構提供時無法使用此實作
EDF(Earliest Deadline First)實作
EDF演算法最早被用在CPU調度上,EDF是搶占式單處理器調度的最佳調度演算法,EDF實作與權重輪轉實作相似,引入了名為deadline的額外變數,可以認為權重越高的服務器實體完成任務的時間越快,那么在假設所有請求的成本相同時,所需要花費的時間是權重的倒數,所以可以很自然地選擇可以最早空閑出來提供服務的服務器實體,并將任務分配給它,
實作EDF演算法只需要將每個下游服務器實體與deadline系結,然后以deadline為優先級維護到優先佇列中,并不斷取出隊首元素,調整它的deadline,并將它重新提交到優先佇列中,知名Service Mesh代理envoy使用了此方法實作加權負載均衡(envoy),以及螞蟻開源網路代理mosn中也實作了此方法(mosn #1920)
public class WeightedLoadBalancer { private final PriorityQueue entries; public WeightedLoadBalancer(List instances) { this.entries = instances.stream().map(EdfEntry::new).collect(Collectors.toCollection(PriorityQueue::new)); } public ServiceInstance peek(HttpServletRequest request) { EdfEntry entry = entries.poll(); if (entry == null) { return null; } ServiceInstance instance = entry.instance; entry.deadline = entry.deadline + 1.0 / instance.getWeight(); entries.add(entry); return instance; } private static class EdfEntry implements Comparable { final ServiceInstance instance; double deadline; EdfEntry(ServiceInstance instance) { this.instance = instance; this.deadline = 1.0 / instance.getWeight(); } @Override public int compareTo(EdfEntry o) { return Double.compare(deadline, o.deadline); } } }
EDF每次選擇的演算法復雜度為O(log(n)),相較于陣列展開要慢,但相較于上界收斂選擇在最壞情況下以及權重輪轉都需要O(n)的時間復雜度來說,其性能表現的非常好,并且對于超大集群,其性能下降不明顯,其空間復雜度為O(n),不會造成很大的記憶體開銷,
Least Connections(最少連接負載均衡演算法)
遍歷比較方式
最簡單的實作方式,遍歷所有實體,并找出當前連接數最少的實體
public class LeastConnectionLoadBalancer { private final List instances; public LeastConnectionLoadBalancer(List instances) { this.instances = instances; } public ServiceInstance peek(HttpServletRequest request) { ServiceInstance best = null; for (ServiceInstance instance : instances) { if (best == null || instance.getConnections() < best.getConnections()) { best = instance; } } if (best != null) { best.setConnections(best.getConnections() + 1); } return best; } }
堆維護方式
所有動態有序集合都可以通過優先佇列來實作,與EDF演算法相同,取出隊首的元素,修改它的優先級,并放回佇列中
public class LeastConnectionLoadBalancer { private final PriorityQueue instances; public LeastConnectionLoadBalancer(List instances) { this.instances = instances.stream().collect(toCollection( () -> new PriorityQueue<>(comparingInt(ServiceInstance::getConnections)))); } public ServiceInstance peek(HttpServletRequest request) { ServiceInstance best = instances.poll(); if (best == null) { return null; } best.setConnections(best.getConnections() + 1); return best; } }
Weighted Least Connections(加權最少連接負載均衡演算法)
加權最少連接負載均衡演算法的實作方式與最少連接負載均衡演算法相同,只是在計算時增加了權重相關的引數
遍歷比較方式
public class LeastConnectionLoadBalancer { private final List instances; public LeastConnectionLoadBalancer(List instances) { this.instances = instances; } public ServiceInstance peek(HttpServletRequest request) { ServiceInstance best = null; for (ServiceInstance instance : instances) { if (best == null || instance.getConnections() * best.getWeight() < best.getConnections() * instance.getWeight()) { best = instance; } } if (best != null) { best.setConnections(best.getConnections() + 1); } return best; } }
Tips,在不等式中 a/b < c/d 與 ad < bc等價,并且可以避免除法帶來的性能與精度問題
堆維護方式
public class LeastConnectionLoadBalancer { private final PriorityQueue instances; public LeastConnectionLoadBalancer(List instances) { this.instances = instances.stream().collect(toCollection( () -> new PriorityQueue<>(comparingDouble(ServiceInstance::getWeightedConnections)))); } public ServiceInstance peek(HttpServletRequest request) { ServiceInstance best = instances.poll(); if (best == null) { return null; } best.setConnections(best.getConnections() + 1); best.setWeightedConnections(1.0 * best.getConnections() / best.getWeight()); return best; } }
Weighted Response Time(加權回應時間負載均衡演算法)
加權回應時間負載均衡演算法使用統計學的方法,通過歷史的回應時間來得到預測值,使用這個預測值來選擇相對更優的服務器實體,得到預測值的方法有很多,包括時間視窗內的平均值、時間視窗內的TP99、歷史所有回應時間的指數移動加權平均數(EWMA)等等,其中Linkerd與APISIX使用了EWMA演算法(Linkerd和APISIX),
通過歷史的回應時間來得到預測值這個操作通常是CPU開銷很大的,實際使用時可以不用遍歷所有元素,而是使用K-臨近元素或直接隨機選擇兩個元素進行比較即可,這種啟發式方法辦法無法保證全域最優但是可以保證不至于全域最差,
Source IP Hash(源地址哈希負載均衡演算法)
源地址哈希負載均衡以任意演算法將請求地址映射成整型數,并將這個整型數映射到實體串列的下標
public class IpHashLoadBalancer { private final List instances; public IpHashLoadBalancer(List instances) { this.instances = instances; } public ServiceInstance peek(HttpServletRequest request) { int h = hashCode(request); return instances.get(h % instances.size()); } private int hashCode(HttpServletRequest request) { String xForwardedFor = request.getHeader("X-Forwarded-For"); if (xForwardedFor != null) { return xForwardedFor.hashCode(); } else { return request.getRemoteAddr().hashCode(); } } }
這里有一個需要注意的點:
-
面向公網提供服務的負載均衡器前面可能會經過任意多層反向代理服務器,為了獲取到真實的源地址,需要先獲取X-Forwarded-For頭部,如果該頭部不存在再去獲取TCP連接的源地址
負載均衡技術擴展
服務注冊表與發現(Service Registry and Service Discovery)
在維護大型服務器集群時,服務器實體隨時都有可能被創建或移除,當服務器被創建或移除時,集群管理員需要到各個負載均衡設備上去更新服務器實體串列,
服務注冊表會在內部維護服務對應的服務器實體串列,在服務器實體被創建并成功運行服務后,服務器實體會去服務注冊表中注冊自身,包括網路地址(IPv4/IPv6)、服務埠號、服務協議(TCP/TLS/HTTP/HTTPS)以及自身提供的服務名稱等等,有的服務注冊表本身也會提供主動健康檢查的能力(如Eureka與Consul),在服務器實體正常退出時會在服務注冊表執行反注冊邏輯,這個時候服務注冊表就會將這個服務器實體從服務器實體串列中移除,即使服務器實體例外退出導致無法執行反注冊邏輯,服務注冊表也會通過主動健康檢查機制將這個例外的服務器實體從服務器實體串列中移除,
在擁有服務注冊表后,負載均衡設備不需要再手動維護服務器實體串列,而是當請求到來時從服務注冊表中拉取對應的服務器實體串列,并在這個服務器實體串列中進行負載均衡,為了提高服務的可用性,負載均衡設備會在本地(記憶體或本地檔案注冊表)快取這些服務器實體串列,以避免由于負載均衡設備與服務注冊表無法連接而導致服務不可用,
快取及重新獲取服務器串列的策略根據不同業務場景有不同的實作,在Spring Cloud Loadbalancer中是通過快取過期而觸發重新獲取的邏輯(Spring Cloud),當服務注冊表不可用時,因為負載均衡設備中無可用的服務器備份而導致服務完全不可用;在大部分的負載均衡設備中將快取獲取與更新邏輯改為定時器主動重繪的機制,這樣當服務注冊表不可用時可以主動決定是否將舊資料標記為過期,盡管本地快取可以提高服務的可用性,但是要注意負載均衡設備在使用的仍舊是舊的服務提供方串列,當長時間無法獲取到新的服務提供方串列時,負載均衡設備應當舍棄舊的服務提供方串列,并將服務不可用的問題暴露出來,通過基礎設施提供的監控與告警能力通知集群管理員來進行處理,
健康檢查(Health Check)
健康檢查本質是一個預定規則,它向負載均衡器背后的服務器集群中的所有成員發送相同的請求,以確定每個成員服務器是否可以接受客戶端請求,
對于某些型別的健康檢查,通過評估來自服務器的回應以及收到服務器回應所需的時間以確定每個成員服務器的運行狀態,通常情況下,當成員服務器的狀態變為不健康時,負載均衡器應該快速地將其從服務器實體串列中移除,并在成員服務器狀態恢復正常時將其重新添加回服務器實體串列中,
-
對于網路層負載均衡器(也叫做NLB或L4LB),通過建立TCP連接,根據是否能夠成功建立連接以及建立連接所需要的時間來確定成員服務器的狀態,
-
對于應用層負載均衡器(也叫做ALB或L7LB),通過發送應用層協議(不只是HTTP協議)定義的用于健康檢查的請求報文,并根據回應報文內容以及整個請求從建立連接到完整收到所有回應所花費的時間來確定成員服務器的狀態,
應用負載均衡器沒有固定的模式,例如,對于提供HTTP協議服務的應用,可以提供用于健康檢查的URL,設定通過健康檢查的HTTP狀態碼(或狀態碼集),并驗證回應報文中用于表示服務器狀態的欄位(通過JSONPath或XMLPath等提取)是否是預期值等方式來確認成員服務器狀態;對于RPC協議,可以提供專門的ping-pong服務,負載均衡器根據RPC協議組裝請求報文,并發送ping請求到成員服務器上,并根據成員服務器回傳的內容是否為pong回應來確認成員服務器的狀態,具體設計可以參考websocket的ping-pong機制(RFC 6455),
慢啟動(Slow Start)
負載均衡器中的慢啟動思想來自于TCP的擁塞控制理論,其核心也是為了避免大量請求涌入剛剛啟動完成的應用程式,導致大量請求阻塞、超時或例外的情況, 眾所周知,Java是半編譯半解釋型語言,包括Java語言在內,現代解釋型語言的解釋器都帶有即時編譯器(Just In Time,JIT),JIT編譯器會跟蹤每個方法的執行點,對那些熱點路徑(Hotspot)進行更高效的優化,這也是Hotspot JVM名字的由來,而JIT對熱點路徑的優化全都來自于自應用程式啟動以來的所有方法呼叫,也就是說應用程式的系統承載能力是隨著程式的運行而不斷得到強化的,經過JIT優化的Java代碼甚至可以得到近似GCC中O3(最高級別)優化的性能,跟多關于JIT編譯器的細節可以看Oracle的Java開發者指南(Java Developer Guide),
同時,現代應用程式都不可避免的會使用本地快取,當應用程式剛剛啟動時記憶體中的快取是空的,隨著應用程式的運行,不斷地訪問外部系統獲取資料并將資料寫入到記憶體快取中,應用程式與外部系統的互動會不斷減少,應用程式的系統承載能力也會逐漸達到峰值,
上面是應用程式在啟動后性能不斷提升的因素中最常見的,初次之外還有很多的因素,所以為了避免大量請求涌入剛剛啟動完成的應用程式的現象發生,負載均衡器會通過慢啟動的方式,隨著服務器運行不斷增加這些服務器實體的權重,最終達到服務器的實際權重,從而達到動態調整分配給這些服務器實體的流量的效果,
服務器權重變化演算法有很多,包括隨時間線性增長、隨時間對數增長、隨時間指數增長、隨時間變冪增長、與隨時間按Logistic增長等,目前京東服務框架(JSF)實作的是隨時間線性增長;envoy實作了隨時間變冪增長,并引入了漸進因子來調整變化速率(envoy slow start),
總結
負載均衡技術是網路代理與網關組件最核心的組成部分,本文簡單介紹了什么是負載均衡技術、常見的負載均衡演算法以及常見負載均衡演算法的實作,并給出了負載均衡技術的擴展,為將來更深入學習網路代理相關技術打下基礎,
因本人才學疏淺經驗能力有限,文中難免會有疏忽和遺漏,以及不連貫的地方,歡迎大家與我溝通交流給出建議,
作者:紀卓志
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/531461.html
標籤:其他
下一篇:UE代碼重構方法
