背景:公司的SSO服務原本是依辦公區域建立四組。再一次後來的調整與升級,將所有節點視作一個巨大群集,並且將原本的反向代理工具Nginx,替換成Apache APISIX。並且希望在各自辦公區域的客戶端,優先使用該區域的服務節點。這該怎麼做到呢?
讓我們把焦點只放在本系列主角APISIX負責任務上,它是怎麼設定負載平衡的?
在前一天,「新竹百貨公司」的例子(已停用高乘載管制),每次透過APISIX拜訪新竹百貨公司,都會被帶到新竹巨城、新竹SOGO、新竹大遠百、竹北大遠百任何一個。這種透過輪詢進行負載平衡的機制,叫做「Round Robin(RR)」。常見的機制還有「Least conn」和「CHash」
Least conn並不那麼容易DEMO,所以只在特別DEMO 「CHash」:
設定欄位 | 內容 |
---|---|
Algorithm | CHash |
Hash on | vars |
Key | remote_addr |
透過設定Key爲remote_addr
,也就是來源客戶端IP,來決定應該將請求分配給上游哪一個節點。因爲通常同一台電腦到APISIX使用的網路介面並不會改變,IP也不會經常變動,因此這麼設定以後,就總是會到特定的新竹百貨公司。以我自己的環境來說,最後總是會到「新竹SOGO」。
可以在進一步調整各個節點的權重。像是新竹巨城、新竹SOGO允許有比較大的人流,設定權重爲30;新竹大遠百有威秀影城,人也蠻多的,設定權重爲25;最後竹北大遠百比較遠,設定權重爲15。這樣總共加起來剛好100。(30+30+25+15=100
)
進行一百次呼叫試試看:
for c in $(seq 100);
do;
curl --silent http://新竹百貨公司.com:9080/ |grep title;
done|sort|uniq -c
得到這麼個結果:
31 <title>新竹SOGO</title>
24 <title>新竹大遠百</title>
31 <title>新竹巨城</title>
14 <title>竹北大遠百</title>
百貨公司 | 拜訪次數 | 比例 |
---|---|---|
新竹巨城 | 31 次 | 31% |
新竹SOGO | 31 次 | 31% |
新竹大遠百 | 24 次 | 24% |
竹北大遠百 | 15 次 | 15% |
有時候遇到節點維護、調整,暫時無法提供服務,APISIX同Nginx一樣,如果該節點無法建立連線,會嘗試使用其他節點。現在把「竹北大遠百」服務先暫停下來,再跑50次請求看看:
18 <title>新竹SOGO</title>
14 <title>新竹大遠百</title>
18 <title>新竹巨城</title>
百貨公司 | 拜訪次數 | 比例 |
---|---|---|
新竹巨城 | 18 次 | 36% |
新竹SOGO | 18 次 | 36% |
新竹大遠百 | 14 次 | 28% |
竹北大遠百 | 0 次 | 0% |
但是僅是這樣,實際上仍會嘗試使用異常的節點,這可能增加回應時間:
更好的方式是直接在上游群集移除該節點,或是也可以將其權重直接設定爲「0」。
30 <title>新竹SOGO</title>
24 <title>新竹大遠百</title>
31 <title>新竹巨城</title>
百貨公司 | 拜訪次數 | 比例 |
---|---|---|
新竹巨城 | 30 次 | 35% |
新竹SOGO | 31 次 | 36% |
新竹大遠百 | 24 次 | 28% |
竹北大遠百 | 0 次 | 0% |
這麼一來不但少一次確定會出錯的請求,負載也會重新在分配,接近於 30 / (30+30+25) = 35%
和25 / (30+30+25) = 30%
能不能這樣:「優先前去新竹巨城和新竹SOGO;新竹大遠百次之;最後才去竹北大遠百」。
(竹北大遠百已經重新開業)
透過Dashboard上的管理表達已經無法完成此需求。這次需要直接調整JSON物件,原本點擊「Configure」的按鈕,改點擊「View」顯式JSON內容,並在不同Nodes.Target添加priority
的屬性:
我們將各個百貨公司的權重設定如下
百貨公司 | 權重 |
---|---|
新竹巨城 | 1 |
新竹SOGO | 1 |
新竹大遠百 | -1 |
竹北大遠百 | -2 |
現在再來拜訪新竹百貨公司看看:
百貨公司 | 拜訪次數 | 比例 |
---|---|---|
新竹巨城 | 30 次 | 50% |
新竹SOGO | 30 次 | 50% |
新竹大遠百 | 0 次 | 0% |
竹北大遠百 | 0 次 | 0% |
如果巨城因爲颱風沒有開:
百貨公司 | 拜訪次數 | 比例 |
---|---|---|
新竹巨城 | 0 次 | 0% |
新竹SOGO | 30 次 | 100% |
新竹大遠百 | 0 次 | 0% |
竹北大遠百 | 0 次 | 0% |
喔,忘記了!新竹SOGO就在巨城旁邊,當然也放颱風假!
百貨公司 | 拜訪次數 | 比例 |
---|---|---|
新竹巨城 | 0 次 | 0% |
新竹SOGO | 0 次 | 0% |
新竹大遠百 | 25 次 | 100% |
竹北大遠百 | 0 次 | 0% |
恩...巨城放颱風假,應該就是新竹市放颱風假...新竹大遠百也沒開。颱風天想去逛百貨公司只好去竹北了。(欸!不是,颱風天還是好好待在家好嗎?)
百貨公司 | 拜訪次數 | 比例 |
---|---|---|
新竹巨城 | 0 次 | 0% |
新竹SOGO | 0 次 | 0% |
新竹大遠百 | 0 次 | 0% |
竹北大遠百 | 15 次 | 100% |
不過這樣的問題是...經常白跑......下次可能需要先查查看有沒有開再去了Orz
公司SSO服務的負載平衡設定也類似這樣設定:
{
"host": "site1-1.local",
"port": 8443,
"weight": 10,
"priority": 1
},
{
"host": "site1-2.local",
"port": 8443,
"weight": 10,
"priority": 1
},
{
"host": "site2-1.local",
"port": 8443,
"weight": 10,
"priority": -1
},
{
"host": "site2-2.local",
"port": 8443,
"weight": 10,
"priority": -1
},
{
"host": "site3-1.local",
"port": 8443,
"weight": 10,
"priority": -2
},
{
"host": "site3-2.local",
"port": 8443,
"weight": 10,
"priority": -2
},
{
"host": "site4-1.local",
"port": 8443,
"weight": 10,
"priority": -3
},
{
"host": "site4-2.local",
"port": 8443,
"weight": 10,
"priority": -3
}