負載均衡(Load balancing)是一種計算機網絡技術,用來在多個計算機(計算機叢集)、網絡連接配接、CPU、磁盤驅動器或其他資源中配置設定負載,以達到最佳化資源使用、最大化吞吐率、最小化響應時間、同時避免過載的目的。
使用帶有負載均衡的多個伺服器元件,取代單一的元件,可以通過備援提高可靠性。負載均衡服務通常是由專用軟體和硬體來完成。
對于網際網路服務,負載均衡器通常是一個軟體程式,這個程式偵聽一個外部端口,網際網路使用者可以通過這個端口來通路服務,而作為負載均衡器的軟體會将使用者的請求轉發給背景内網伺服器,内網伺服器将請求的響應傳回給負載均衡器,負載均衡器再将響應發送到使用者,這樣就向網際網路使用者隐藏了内網結構,阻止了使用者直接通路背景(内網)伺服器,使得伺服器更加安全,可以阻止對核心網絡棧和運作在其它端口服務的攻擊。
當所有背景伺服器出現故障時,有些負載均衡器會提供一些特殊的功能來處理這種情況。例如轉發請求到一個備用的負載均衡器、顯示一條關于服務中斷的消息等。負載均衡器使得 IT 團隊可以顯著提高容錯能力。它可以自動提供大量的容量以處理任何應用程式流量的增加或減少。
對于核心 api,需要保證搞可靠性,那麼就要對于該 api 有多個 backend service,即實際後端對該 api 有多個服務的節點;那麼最好在 api-gateway 即 kong 這一層實作負載均衡。
Kong為多個後端服務提供了多種負載平衡請求方式:一種基于DNS的簡單方法,以及一種更加動态的環平衡器,該方法還允許在不需要DNS伺服器的情況下進行服務注冊。
基于DNS的負載均衡
當使用基于DNS的負載均衡時,後端服務的注冊是在Kong以外完成的,而Kong僅接收來自DNS伺服器的更新。
如果名稱解析為多個IP位址,并且主機名未解析為上遊名稱或名稱,則每個使用包含hostname(而不是IP位址)的host定義的service都将自動使用基于DNS的負載平衡你的DNS hosts檔案。
DNS記錄ttl設定(生存時間)決定資訊重新整理的頻率。當使用0的ttl時,每個請求都将使用自己的DNS查詢來解析。很明顯,這會導緻性能下降,但更新/更改的延遲将非常低。
A記錄
A記錄包含一個或多個IP位址。是以,當主機名解析為A記錄時,每個後端服務都必須具有自己的IP位址。
由于沒有weight資訊,是以所有條目在負載平衡器中将被視為具有相同的權重,并且平衡器(balancer)将進行簡單的循環。
SRV記錄
SRV記錄包含所有IP位址的權重(weight)和端口(port)資訊。後端服務可以通過IP位址和端口号的唯一組合來識别。是以,單個IP位址可以在不同的端口上托管同一服務的多個執行個體。
由于weight資訊可用,每個條目将在負載均衡器中獲得自己的權重,并執行權重循環。
同樣,任何給定的端口資訊都将被來自DNS伺服器的端口資訊覆寫。如果服務具有host = myhost.com和port = 123的屬性,并且myhost.com解析為具有127.0.0.1:456的SRV記錄,則該請求将被代理到http://127.0.0.1:456/somepath,因為123端口将被456覆寫。
DNS優先級
DNS解析器将按順序解析以下記錄類型:
- 上次解析的最後一次成功類型(LAST)
- CNAME記錄
該順序可通過dns_order配置屬性進行配置。
解析不同記錄類型的順序。 LAST類型表示上次成功查找的類型(用于指定的名稱)。格式是一個(不區分大小寫)逗号分隔的清單。
預設值:LAST,SRV,A,CNAME
DNS警告(DNS caveats)
- 無論何時重新整理DNS記錄,都會生成一個清單以正确處理權重。盡量保持權重為對方的倍數以保持算法的高效性,例如,17和31的2個權重将導緻具有527個項目的結構,而權重16和32(或其最小的相對對應項1和2)将導緻在隻有3個條目的結構中,尤其是具有非常小(甚至0)ttl值的結構。
- 在這些情況下,某些域名伺服器不會傳回所有條目(由于UDP資料包的大小)(例如Consul最多傳回3個),給定的Kong節點将隻使用由名稱伺服器提供的少數上遊服務執行個體。在這種情況下,由于名稱伺服器提供的資訊有限,Kong節點實際上不了解某些執行個體,是以上遊執行個體池可能會不一緻地加載。為了緩解這種情況,可以使用不同的名稱伺服器,使用IP位址而不是名稱,或者確定使用足夠的Kong節點來繼續使用所有上遊服務。
- 當名稱伺服器傳回3 name error時,那麼對于Kong來說這是一個有效的響應。如果這是意外,請首先驗證是否正在查詢正确的name,然後檢查您的nameserver配置。
- 從DNS記錄(A或SRV)中初始選擇IP位址不是随機的。是以,當使用ttl為0的記錄時,nameserver應該随機記錄條目。
環平衡器(ring-balancer)
當使用環平衡器時,添加和删除後端服務将由Kong處理,并且不需要DNS更新。kong将擔任服務登記。節點可以通過一個HTTP請求added/deleted,并立即start/stop接收流量。
配置環平衡器是通過上遊和目标實體完成的。
target:具有後端服務駐留端口号的IP位址或主機名,例如。 “192.168.100.12:80”。每個target都會得到一個額外的權重來訓示它獲得的相對負載。 IP位址可以是IPv4和IPv6兩種格式。
upstream:可以在路由主機字段中使用的'virtual hostname',例如,上遊命名的weather.v2.service将從具有host = weather.v2.service的服務獲得所有請求
上遊(upstream)
每個upstream都有自己的環形平衡器。每個upstream可以有許多target條目附加到它,代理到'virtual hostname'的請求将在target上進行負載平衡。環形平衡器具有預定義(pre-defined)數量的槽(number of slots),并且基于目标權重,槽(slots)被配置設定給上遊的目标。
添加和删除目标可以通過
Admin API上的簡單HTTP請求完成。這個操作相對便宜。改變上遊本身更昂貴,因為例如當槽的數量改變時平衡器将需要重建。
自動重建平衡器的唯一情況是清理目标曆史記錄時;除此之外,它隻會在改變時重建。
在平衡器内部有(從1到slots)的位置,它們随機分布( randomly distributed)在環上。在運作時需要随機性來調用環平衡器。輪子上的簡單循環(位置)将為目标提供良好的分布式權重循環,同時在插入/删除目标時也具有廉價的操作。
每個目标使用的插槽數量(至少)應該在100個左右,以確定插槽正确分布。例如。對于預期最多8個目标,即使初始設定僅包含2個目标,上遊應至少定義為slot = 800。
這裡的折衷是,插槽數量越多,随機分布越好,但更改更為昂貴(添加/删除目标)
有關添加和操作上遊的詳細資訊,請參閱
目标(target)
由于上遊保留了更改曆史記錄,目标隻能添加,不能修改或删除。要更改目标,隻需為目标添加一個新條目,然後更改重量值。最後一個條目是将要使用的條目。因為這樣的設定權重= 0将禁用目标,有效地從平衡器中删除它。有關添加和操作目标的詳細資訊,請參閱Admin API參考的目标部分。
當活動條目比活動條目多10倍時,目标将自動清除。清潔将涉及重建平衡器,是以比添加目标條目更昂貴。
目标也可以具有主機名而不是IP位址,在這種情況下,名稱将被解析,所有找到的條目将被單獨添加到環形平衡器中,例如,添加api.host.com:123且權重= 100。名稱'api.host.com'解析為具有2個IP位址的A記錄。然後這兩個IP位址将被添加為目标,每個獲得weight = 100和端口123.注意:權重用于單個條目,而不是整個!
它是否會解析為SRV記錄,然後DNS記錄中的端口和權重字段将被拾取,并且會否定給定的端口123和權重= 100。
平衡器将遵守DNS記錄的ttl設定和重新查詢,并在平衡器到期時更新。
例外情況:當DNS記錄的ttl = 0時,主機名将被添加為具有指定權重的單個目标。在對該目标的每個代理請求時,它将再次查詢名稱伺服器。
平衡算法
預設情況下,環平衡器将使用權重循環方案。另一種方法是使用基于散列的算法。散列的輸入可以是none,consumer,ip或header。如果設定為none,則将使用權重循環方案,并且散列将被禁用。
有兩種選擇,一種primary 和 一種回退(fallback),以防primary失敗(例如,如果primary設定為consumer,但沒有consumer通過驗證)
不同的散列選項:
- none:不要使用散列,而是使用weighted-round-robin(預設)。
- consumer:使用消費者ID作為散列輸入。如果沒有消費者ID可用(如果使用外部身份驗證,如ldap),此選項将回退到憑證ID。
- ip:遠端(始發)IP位址将用作輸入。在使用此設定時,檢視确定真實IP的配置設定。
- header:使用指定的标題(在hash_on_header或hash_fallback_header字段中)作為散列的輸入。
雜湊演算法基于'一緻哈希'(或'ketama原理'),它確定當平衡器通過改變目标(添加,移除,失敗或改變權重)而被修改時,隻有最小數量的哈希損失發生。這将最大化上遊緩存命中。
有關确切設定的更多資訊,請參閱Admin API參考的上遊upstream部分。
平衡警告(Balancing caveats)
環平衡器設計為既可以在單個節點上工作,也可以在群集中工作。對于權重循環算法沒有太大的差別,但是當使用基于散列的算法時,重要的是所有節點建構完全相同的環平衡器以確定它們都工作一緻。要做到這一點,平衡器必須以确定性的方式建構。
不要在平衡器中使用主機名稱,因為平衡器可能會/會慢慢發生分歧,因為DNS ttl隻有第二精度,更新取決于實際請求名稱的時間。最重要的是一些域名伺服器沒有傳回所有條目的問題,這加劇了這個問題。是以,在Kong群集中使用哈希方法時,隻能通過IP位址添加目标實體,而不能通過名稱添加target實體。
當選擇你的散列輸入時,確定輸入具有足夠的方差以得到散布良好的散列。哈希将使用CRC-32摘要進行計算。例如,如果您的系統有成千上萬的使用者,但隻有少數使用者(每個平台定義了3個使用者:Web,iOS和Android),那麼挑選consumer散列輸入是不夠的,通過設定使用遠端IP位址對于ip的哈希将提供更多的輸入差異,進而更好地配置設定哈希輸出
藍綠部署(Blue-Green Deployments)
使用環形平衡器,可以輕松地為一項服務策劃一個藍綠色部署。切換目标基礎架構隻需要服務上的PATCH請求,即可更改其主機值。
設定“blue”環境,運作version 1 of the address service:
# create an upstream
$ curl -X POST http://kong:8001/upstreams \
--data "name=address.v1.service"
# add two targets to the upstream
$ curl -X POST http://kong:8001/upstreams/address.v1.service/targets \
--data "target=192.168.34.15:80"
--data "weight=100"
$ curl -X POST http://kong:8001/upstreams/address.v1.service/targets \
--data "target=192.168.34.16:80"
--data "weight=50"
# create a Service targeting the Blue upstream
$ curl -X POST http://kong:8001/services/ \
--data "name=address-service" \
--data "host=address.v1.service" \
--data "path=/address"
# finally, add a Route as an entry-point into the Service
$ curl -X POST http://kong:8001/services/address-service/routes/ \
--data "hosts[]=address.mydomain.com"
在部署version 2 of the address service之前,請設定“green”環境:
# create a new Green upstream for address service v2
$ curl -X POST http://kong:8001/upstreams \
--data "name=address.v2.service"
# add targets to the upstream
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.17:80"
--data "weight=100"
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.18:80"
--data "weight=100"
要激活blue/green開關,現在隻需要更新服務:
# Switch the Service from Blue to Green upstream, v1 -> v2
$ curl -X PATCH http://kong:8001/services/address-service \
--data "host=address.v2.service"
主機頭設定為address.mydomain.com的傳入請求現在由Kong代理到新目标; 1/2的請求将轉到http://192.168.34.17:80/address(權重= 100),另一半将轉到http://192.168.34.18:80/address(權重= 100 )。
與往常一樣,通過Kong Admin API進行的更改是動态的,并且會立即生效。不需要重新加載或重新啟動,并且沒有進行中的請求将被丢棄。
金絲雀版本(Canary Releases)
使用環形平衡器,可以精确調整目标重量,進而實作平穩.。
使用一個非常簡單的2 target示例:
# first target at 1000
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.17:80"
--data "weight=1000"
# second target at 0
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.18:80"
--data "weight=0"
通過重複請求,但每次改變權重,流量将緩慢路由到另一個target。例如,将其設定為10%:
# first target at 900
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.17:80"
--data "weight=900"
# second target at 100
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.18:80"
--data "weight=100"
通過Kong Admin API進行的更改是動态的,并會立即生效。不需要重新加載或重新啟動,并且沒有進行中的請求将被丢棄。
KONG負載均衡實作
實際在操作過程中,采用的是 kong 的 Ring-balancer 做負載均衡。
使用 Kong Community Edition(社群版 v0.13)來搭建一個負載均衡器,由于 Kong 是基于 Openresty 的,而 Openresty 又是 Nginx 的二次封裝,所有很多配置項和 Nginx 類似。
來看一個較為典型的 Nginx 負載均衡配置:
upstream hello {
server localhost:3000 weight=100;
server localhost:3001 weight=50;
}
server {
listen 80;
location /hello {
proxy_pass http://hello;
}
}
nginx 監聽來自本地 80 端口的請求,如果路徑與 /hello 比對,便将請求原封不動的轉發到名稱為 hello 的upstream,而該 upstream 我們配置了一個負載均衡器,會路由到本地的 3000 端口和 3001 端口。
接下來便可以針對 Kong 進行負載均衡的配置了。
配置 upstream 和 target
建立一個名稱 hello 的 upstream
curl -X POST http://localhost:8001/upstreams --data "name=hello"
為 hello 添加兩個負載均衡節點
curl -X POST http://localhost:8001/upstreams/hello/targets --data "target=localhost:3000" --data "weight=100"
curl -X POST http://localhost:8001/upstreams/hello/targets --data "target=localhost:3001" --data "weight=50"
如上的配置對應了 Nginx 的配置:
upstream hello {
server localhost:3000 weight=100;
server localhost:3001 weight=50;
}
配置 service 和 route
使用 Kong v0.13之前版本的使用者可能會接觸過 api 這個概念,但是在 Kong v0.13.0 中,已經被廢除了,取而代之的是 service 和 route 的配置。
配置一個 service
curl -X POST http://localhost:8001/services --data "name=hello" --data "host=hello"
host 的值便對應了 upstream 的名稱,配置成功後會傳回生成的 service 的 id,傳回結果:8695cc65-16c1-43b1-95a1-5d30d0a50409。
為上面的 service 配置路由資訊
curl -X POST http://localhost:8001/routes --data "paths[]=/hello" --data "service.id=8695cc65-16c1-43b1-95a1-5d30d0a50409"
請求路徑包含 /hello 的請求都會被轉移到對應的 service 進行處理。
如上的配置便對應了Nginx的配置:
location /hello {
proxy_pass http://hello;
}
測試 Kong 的負載均衡
curl http://localhost:8000/hello/hi
因為複雜均衡的原因,需要多測試幾次,多次 curl 之後結果如下:
3000
3000
3000
3000
3000
3000
3001
3001
3001
3000
3001
reference:
https://getkong.org/docs/0.13.x/loadbalancing/ https://getkong.org/docs/0.13.x/configuration/作者:
zhoujie出處:
http://www.cnblogs.com/zhoujie/本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,不然我擔心部落格園找你算賬
如果您覺得本文對你有幫助,請豎起您的大拇指右下角點推薦,也可以關注我