如何設定 GCP HTTP(S) 負載平衡器

當你的服務開始上線、並逐漸成長茁壯的時候,除了要持續提供有趣的功能給使用者,同一時間也別忘了要提升服務的品質與穩定性,使用者會受到新的功能吸引而使用你的服務,但也會因為服務不穩定無法體驗你做出來的功能而離你而去,所以在這邊我們為您介紹 GCP HTTP(S) load balancing 。透過它,你可以以多台 HTTP server 作為後端提供服務,它會幫你檢查這些 server 是否是正常運作,並將收到的 HTTP request 送交給正常且仍有餘裕的 server 進行處理,藉此增加服務的可用性。

環境設定

各位可以參考 Google Cloud SDK 之中的說明安裝 Cloud SDK 以便跟著我們一起動手做,本文中的示範使用的 Cloud SDK 版本為 130.0.0

設定 GCP HTTP(S) load balancing

GCP HTTP(S) load balancing 由 instance group (managed and unmanaged) 、 health check 、 backend service 、 URL map 、 target HTTP(S) proxy 、以及 global forwarding rule 等元件組成,組成的方式如下圖。

gcp-https-load-balancing

出處:Setting Up HTTP(S) Load Balancing

為了讓各位瞭解各個元件在 HTTP(S) load balancing 之中扮演的是什麼角色,以及之後搭配 autoscaler 讓服務能因應流量的不同增減提供 HTTP 服務的 instance 數量,我們這裡帶著大家一步一步建立 managed instance group 、 health check 、 backend service 、 URL map 、 target HTTP proxy 、以及 global forwarding rule 並一一介紹它們。

Step 1 建立 instance template

gcloud compute --project "demo-project" \

instance-templates create "demo-instance-template" \

--machine-type "f1-micro" \

--metadata "startup-script=apt-get install nginx-light -y && echo \"Hello \$HOSTNAME\" | tee /var/www/html/index.html > /dev/null" \

--tags "http-server" \

--image-family "debian-8" \

--boot-disk-size "10" \

--boot-disk-type "pd-standard" \

--boot-disk-device-name "demo-instance-template"


這個 instance template 會在 instance 產生的時候安裝 Nginx ,並將首頁的內容替換成 Hello $HOSTNAME ,這樣我們就能知道我們透過 HTTP load balancing 連線到的是哪一個 instance 。

 

Step 2 接著使用剛建立的 instance template 建立兩個 managed instance group

gcloud compute --project "demo-project" \

instance-groups managed create "demo-instance-group-ae1a" \

--zone "asia-east1-a" \

--base-instance-name "demo-instance-group-ae1a" \

--template "demo-instance-template" \

--size "1"


gcloud compute --project "demo-project" \

instance-groups managed create "demo-instance-group-ae1b" \

--zone "asia-east1-b" \

--base-instance-name "demo-instance-group-ae1b" \

--template "demo-instance-template" \

--size "1"


managed instance group 會使用指定的 instance template 幫我們產生指定數量的 instance ,這裡我們指定兩個 managed instance group 各產生一個 instance 。

 

Step 3 建立 HTTP health check 供 backend service 使用

gcloud compute --project "demo-project" \

http-health-checks create "demo-http-health-check" \

--port "80" \

--request-path "/" \

--check-interval "5" \

--timeout "5" \

--unhealthy-threshold "2" \

--healthy-threshold "2"


這個 HTTP health check 會對 instance 的 port 80 發出 GET / HTTP/1.1 的 request ,每隔 5 秒發送一次,在 5 秒內等候 instance 回應 HTTP 200 response ,若連續 2 次在 5 秒內得到 HTTP 200 response ,則認定該 instance 為 healthy ,若連續 2 次無法滿足前述條件,則認定該 instance 為 unhealthy 。

 

Step 4 建立以 HTTP 協定跟 instance 連線的 backend service ,並使用剛建立的 HTTP health check 檢查 instance 是否可用

gcloud compute --project "demo-project" \

backend-services create "demo-http-backend-service" \

--http-health-check "demo-http-health-check" \

--protocol "HTTP" \

--port-name "demo" \

--timeout "30"


因為我們的 instance 上開啟的是 HTTP 服務,故設定 backend service 以 HTTP 協定跟 instance 連線。而該 backend service 會以我們指定的 HTTP health check 定時檢查 instance 是否 healthy ,且僅會將 request 送到 healthy 的 instance 。

 

Step 5 接著為之前建立的 managed instance group 加上 name:port 的 mapping 供 backend service 存取

gcloud compute --project "demo-project" \

instance-groups set-named-ports "demo-instance-group-ae1a" \

--zone "asia-east1-a" \

--named-ports "demo:80"


gcloud compute --project "demo-project" \

instance-groups set-named-ports "demo-instance-group-ae1b" \

--zone "asia-east1-b" \

--named-ports "demo:80"


在建立 backend service 的時候,我們指定的是 port name 而非指定 port number ,我們採取在 instance group 上加上 name:port 的 mapping , backend service 會依據指定的 port name 去存取對應的 port number 。這樣即使未來我們為 backend service 加入一組新的 instance group 而他的 HTTP 服務開在不同的 port 上面,只要 port name 維持一樣,我們就還是能正常存取到新的 instance group 上開放的 HTTP 服務。

 

Step 6 之後將這些 managed instance group 加入剛剛建立的 backend service

gcloud compute --project "demo-project" \

backend-services add-backend "demo-http-backend-service" \

--instance-group "demo-instance-group-ae1a" \

--instance-group-zone "asia-east1-a" \

--balancing-mode "UTILIZATION" \

--max-utilization "0.8" \

--capacity-scaler "0.75"


gcloud compute --project "demo-project" \

backend-services add-backend "demo-http-backend-service" \

--instance-group "demo-instance-group-ae1b" \

--instance-group-zone "asia-east1-b" \

--balancing-mode "UTILIZATION" \

--max-utilization "0.8" \

--capacity-scaler "0.75"


在將 instance group 加入 backend service 的時候,我們需要為每個 instance group 指定它能負載的量,這裡我們以 CPU utilizaton 做為判斷負載量的依據,最高的 CPU utilization 設定為 80% ,並把 Capacity 設定為 75% ,這樣設定後當 instance 的 CPU utilization 到達 60% ( 80% * 75% )時, backend service 就會暫時停止對該 instance 發送 request ,直到該 instance 的 CPU utilization 低於 60% 才會再度發送 request 給它。

通常我們可以直接將 Capacity 設定為 100% ,不過有時候我們可能會希望 instance 能有些餘裕執行一些其他的工作(例如同一個 instance group 被加入到兩個不同的 backend service ),這時就可以透過調整 Capacity 來決定要讓 instance 留下多少餘裕。

其他在 HTTP(S) load balancing 可以用來做為判斷負載量依據的還有 RPS –balancing-mode “RATE” ,也就是以每秒可以處理多少 request 來分配, –max-rate-per-instance “10” 代表 instance group 中的每個 instance 能處理 10 RPS , –max-rate “10” 代表整個 instance group 能處理 10 RPS 。

另外要提的是, HTTP(S) load balancing 可以做到 global load balancing ,所以我們可以在 backend service 裡面加入位在不同 region 的 instance group ,這樣除了可以降低我們的服務在整個 region failure 的造成無法運作的風險外,還能夠將使用者的 request 導向到距離他最近的 instance 進行處理降低延遲,藉此得到更好的使用體驗。

 

Step 7 建立 URL map ,預設將所有 request 都導向到 demo-http-backend-service 這個 backend service

gcloud compute --project "demo-project" \

url-maps create "demo-http-load-balancer" \

--default-service "demo-http-backend-service"


URL map 可以依據 request 裡的 Host header 以及要存取的 resource 的 path prefix ,將該 request 導向到不同的 backend service , request 在 URL map 裡面被處理的流程如下圖。

gcp-https-load-balancing-url-maps-1

出處:URL Maps

在這裡我們僅設定一個 default service 做為展示。

gcp-https-load-balancing-url-maps-2

出處:URL Maps

 

Step 8 建立 target HTTP proxy

gcloud compute --project "demo-project" \

target-http-proxies create "demo-target-http-proxy" \

--url-map "demo-http-load-balancer"


target HTTP proxy 是 HTTP load balancing 用來面向 client 端的元件,使 client 能以 HTTP 協定存取 URL map 之後的服務。其他還有 target HTTPS proxy 可以為 client 提供 HTTPS 服務,但這要先取得 SSL certificate 後才能使用,不過建立 target HTTPS proxy 的方式與 target HTTP proxy 的差異不大,這裡就不多做介紹。

 

Step 9 保留 global IP address 供 HTTP load balancing 的 global forwarding rule 使用

gcloud compute --project "demo-project" \

addresses create "demo-http-load-balancing-address" --global


 

Step 10 然後查詢剛剛保留下來的 global IP address

gcloud compute --project "demo-project" \

addresses describe "demo-http-load-balancing-address" --global


記下 address 欄位的值,這裡假設保留下來的 IP 是 111.111.111.111 ,之後在建立 global forwarding rule 以及測試時會用到。

 

Step 11 建立 HTTP load balancing 的 global forwarding rule

這裡你可以在 address 直接輸入剛剛查詢到的 global IP address

gcloud compute --project "demo-project" \

forwarding-rules create "demo-http-forwarding-rule" \

--address "111.111.111.111" --global \

--ip-protocol "TCP" --ports "80" \

--target-http-proxy "demo-target-http-proxy"


也可以選擇輸入該 global IP address 的 resource reference selfLink

gcloud compute --project "demo-project" \

forwarding-rules create "demo-http-forwarding-rule" \

--address "global/addresses/demo-http-load-balancing-address" --global \

--ip-protocol "TCP" --ports "80" \

--target-http-proxy "demo-target-http-proxy"


這裡我們指定與 IP address 111.111.111.111TCP port 80 建立的連線都交由 demo-target-http-proxy 處理。

這樣 HTTP load balancing 的設定就完成了!

測試 HTTP load balancing

我們先執行兩個指令,查看兩個 managed instance group 裡面有哪些 instance 。

gcloud compute --project "demo-project" \

instance-groups managed list-instances "demo-instance-group-ae1a" \

--zone "asia-east1-a"


gcloud compute --project "demo-project" \

instance-groups managed list-instances "demo-instance-group-ae1b" \

--zone "asia-east1-b"


假設我們看到有 demo-instance-group-ae1a-abcddemo-instance-group-ae1b-efgh 這兩個 instance 。

接著用以下指令,每五秒對我們剛剛建立的 HTTP load balancing 發出 request 。

watch -n 5 'curl http://111.111.111.111/ 2>/dev/null'


觀察一段時間就會發現回應的 HTTP response 會是在 Hello demo-instance-group-ae1a-abcdHello demo-instance-group-ae1b-efgh 間切換,這證明 request 是被送到不同的 instance 上處理。

接下來我們把其中一個 instance 上的 Nginx 給關閉,使該 instance 變成 unhealthy 的狀態。

gcloud compute --project "demo-project" \

ssh "demo-instance-group-ae1a-abcd" \

--zone "asia-east1-a" \

--command 'sudo systemctl stop nginx.service'


因為該 instance 變成 unhealthy 的狀態, backend service 就不會將 request 送到該 instance ,所以之後我們就只會看到 response 出現 Hello demo-instance-group-ae1b-efgh

總結

這裡我們帶各位建立了 HTTP load balancing 的 managed instance group 、 backend service 、 URL map 、 target HTTP proxy 、以及 global forwarding rule 並一一說明了它們的用途,並展示了 HTTP load balancing 將 request 送往 healthy instance 的功能。

下一篇文章,我們將為您帶來 autoscaler 的介紹,讓您的服務能因應不同程度的流量,自動增減提供服務的 instance 數量,讓您在財務支出與服務規模間能取得更有彈性的平衡點。

Reference

Setting Up HTTP(S) Load Balancing

Creating Instance Templates

Creating Groups of Managed Instances

Adding Health Checks

Backend Services

URL Maps

Target Proxies

Global forwarding rules