谷歌云全球负载均衡 Google Cloud Load Balancing (GCLB) 作为一个全球分布式软件定义负载均衡,可以将全球各地的网络请求通过谷歌边缘节点和骨干网高效投递到用户在任一谷歌云数据中心部署的后端服务,是使用频率非常高的一个云产品。 GCLB 在没有配置边缘 WAF 的时候,会无条件接收所有外部的 HTTP/HTTPS 请求,而不做任何限流。但是,在某些场景下,比如流量增长高于后端承载能力,或者遭到 CC 攻击的时候,用户希望负载均衡能进行限流,在一段时间内减少发送到后端服务请求 QPS ,从而为后端服务扩容或者代码调整提供时间,通过放弃一部分请求来正常服务主要用户群体,并且防止后端在扩容时不必要的处理积压请求而阻塞。针对这些场景,可以利用 GCLB 的分区域负载均衡功能来实现限流方案。本文通过一个操作实例来介绍这一方案。


创建单区域后端的负载均衡服务

单区域后端的负载均衡,会将接收到的所有外部请求都转发到这个后端实例组,如下图所示。


创建 web 服务实例组

首先在谷歌云新加坡区域创建一台虚机。我们会在这台虚机上搭建模拟 HTTP 服务器处理 HTTP 请求。然后以这台虚机为基准来创建一个服务端虚机模板,以供下面步骤来创建实例。如果读者要执行这些命令,请将项目 ID 、服务账号、虚机配置等参数值改成适用于读者自己的环境的值。

gcloud compute instances create   mock-server-test --project=youzhi-lab --zone=asia-southeast1-b   --machine-type=n2-standard-2   --network-interface=network-tier=PREMIUM,subnet=default --maintenance-policy=MIGRATE   --service-account=247839977271-compute@developer.gserviceaccount.com   --scopes=https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring.write,https://www.googleapis.com/auth/servicecontrol,https://www.googleapis.com/auth/service.management.readonly,https://www.googleapis.com/auth/trace.append   --tags=http-server,https-server --image=ubuntu-1804-bionic-v20210702   --image-project=ubuntu-os-cloud --boot-disk-size=100GB   --no-boot-disk-auto-delete --boot-disk-type=pd-balanced   --boot-disk-device-name=mock-server-test-2 --no-shielded-secure-boot   --shielded-vtpm --shielded-integrity-monitoring --reservation-affinity=any

虚机创建成功后可以在控制台看到虚机状态以及分配的公网 IP 等详情。

可以通过公网 IP 登录到虚机,或者使用以下命令在 Cloud Shell 中或者安装了谷歌云 SDK 的本地环境登录这台虚机。

gcloud compute ssh mock-server-test   --zone asia-southeast1-b

下图是从控制台 Cloud Shell 上登录虚机的示例。

登录之后,在虚机上执行以下命令,安装和配置 Wiremock 。Wiremock 是一款模拟 Web 服务器的免费软件,可以用来做 Web 应用的功能和性能测试。

sudo apt update
  sudo apt install -y default-jre
  wget   https://repo1.maven.org/maven2/com/github/tomakehurst/wiremock-jre8-standalone/2.29.0/wiremock-jre8-standalone-2.29.0.jar
  mkdir mappings
  cat >./mappings/post-and-get-test.json <<EOL
  {
    "mappings": [
      {
        "request": {
          "method":   "GET",
          "url": "/"
        },
        "response": {
          "status": 200,
          "body":   "Welcome! "
        }
      },
      {
        "request": {
          "method":   "POST",
          "url":   "/api/post-test"
        },
        "response": {
          "status": 200,
          "body":   "Received POST "
        }
      },
      {
        "request": {
          "method":   "GET",
          "url":   "/api/get-test"
        },
        "response": {
          "status": 200,
          "body": "Received   GET "
        }
      }
    ]
  }
  EOL

下面的命令将 Wiremock 注册为开机自动启动的后台服务。

cat >./wiremock-start.sh   <<EOL
  
#!/bin/bash
  java -jar /usr/local/bin/wiremock-jre8-standalone-2.29.0.jar --port 80
  EOL
 
  chmod +x /home/eugeneyu/wiremock-start.sh
 
  cat >./wiremock.service <<EOL
  [Unit]
  Description=Wiremock
 
  [Service]
  WorkingDirectory=/home/eugeneyu
  ExecStart=/home/eugeneyu/wiremock-start.sh
 
  [Install]
  WantedBy=multi-user.target
  EOL
 
  cat wiremock.service |sudo tee /etc/systemd/system/wiremock.service
 
  sudo chmod +x /etc/systemd/system/wiremock.service
 
  sudo systemctl enable wiremock.service

现在在虚机上执行下面的命令,验证 Wiremock 服务工作正常。

curl -v http://127.0.0.1/

 如果返回状态码不是 200 ,可以用下面命令查一下服务启动是否出错。

journalctl -u wiremock.service

也可以在本地测试从外网访问虚机的 Wiremock 服务,确保防火墙没有阻挡。

虚机上的服务工作正常后,创建磁盘镜像。

gcloud compute images create   mock-server-template-image --project=youzhi-lab   --source-disk=mock-server-test --source-disk-zone=asia-southeast1-b   --storage-location=asia-southeast1 --force

基于磁盘镜像创建虚机实例模板。

gcloud   beta compute --project=youzhi-lab instance-templates create   mock-server-template --machine-type=n2-standard-2   --network=projects/youzhi-lab/global/networks/default --network-tier=PREMIUM   --maintenance-policy=MIGRATE   --service-account=247839977271-compute@developer.gserviceaccount.com   --scopes=https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring.write,https://www.googleapis.com/auth/servicecontrol,https://www.googleapis.com/auth/service.management.readonly,https://www.googleapis.com/auth/trace.append   --tags=http-server,https-server --image=mock-server-template-image --image-project=youzhi-lab   --boot-disk-size=100GB --boot-disk-type=pd-standard   --boot-disk-device-name=mock-server-template --no-shielded-secure-boot   --shielded-vtpm --shielded-integrity-monitoring --reservation-affinity=any

使用下面命令在新加坡区域创建自动伸缩实例组。本例实例组配置为最少 2 台,最大 10 台,伸缩指标为请求数量。

PROJECT_ID=youzhi-lab
  REGION=asia-southeast1
  HEALTHCHECK_NAME=mock-server-health-check
  INSTANCE_GROUP_NAME=mock-server-mig-sin
  INSTANCE_TEMPLATE_NAME=mock-server-template
  INSTANCE_GROUP_ZONES=asia-southeast1-a,asia-southeast1-b,asia-southeast1-c
  BACKEND_NAME=backend-service-wiremock
  URLMAP_NAME=lb-wiremock
  TARGET_PROXY_NAME=target-proxy-wiremock
  FORWARD_RULE_NAME=forward-rule-wiremock
 
  gcloud compute health-checks create http $HEALTHCHECK_NAME --project=$PROJECT_ID   --port=80 --request-path=/ --proxy-header=NONE --check-interval=5 --timeout=5   --unhealthy-threshold=2 --healthy-threshold=2
 
  gcloud beta compute --project=$PROJECT_ID instance-groups managed create
  
$INSTANCE_GROUP_NAME  --base-instance-name=$INSTANCE_GROUP_NAME
  --template=$INSTANCE_TEMPLATE_NAME --size=2 --zones=$INSTANCE_GROUP_ZONES
  --instance-redistribution-type=PROACTIVE --health-check=$HEALTHCHECK_NAME
  --initial-delay=60
 
  gcloud beta compute --project "$PROJECT_ID" instance-groups managed  
  set-autoscaling "$INSTANCE_GROUP_NAME" --region "$REGION "  
  --cool-down-period "60" --max-num-replicas "10"   --min-num-replicas "2 "
  --target-load-balancing-utilization "0.8" --mode "on"


创建全球负载均衡 GCLB

我们现在创建一个 7 层全球负载均衡,并制定上面创建的新加坡区域实例组为唯一后端实例组。这样,负载均衡在全球 100 多个边缘节点接收到的用户请求,会被全量代理转发到新加的实例组进行处理。

gcloud compute backend-services   create $BACKEND_NAME
  --protocol HTTP
  --health-checks $HEALTHCHECK_NAME
  --global
  --enable-cdn
  --timeout=60
 
  gcloud compute backend-services add-backend $BACKEND_NAME
  --balancing-mode=RATE
  --max-rate-per-instance=50
  --capacity-scaler=1
  --instance-group=$INSTANCE_GROUP_NAME
  --instance-group-region=$REGION
  --global
 
  gcloud compute url-maps create $URLMAP_NAME
  --default-service $BACKEND_NAME
 
  gcloud compute target-http-proxies create $TARGET_PROXY_NAME
  --url-map $URLMAP_NAME
 
  gcloud compute forwarding-rules create $FORWARD_RULE_NAME
  --global
  --target-http-proxy=$TARGET_PROXY_NAME
  --ports=80


模拟请求并观察负载均衡转发到单一区域

负载均衡创建好后,可以到控制台查看负载均衡前端 IP 。然后用以下命令模拟外部用户并发 HTTP 请求,将这些请求发送到负载均衡。

ab -n 15000 -c 5 -m POST -H   "Content-Length:0" -v 3

http://34.149.204.229/api/post-test

上面命令调用 Apache Bench 发送 15000 个 POST 请求到负载均衡,并使用 5 个并发进程。在负载均衡的详情页,可以看到请求开始进入负载均衡,并被转发到后端的实例组。

在控制台的 Monitoring 服务,使用 Metrics Explorer 可以用以下配置查看请求量的实时监控。从监控上可以看出,测试启动后, QPS 稳定在 35 左右。

同时,在实例组 mock-server-mig-sin 的利用率监控里,也可以看到 CPU 和网络的用量在同步上升。 


负载均衡添加后端区域实现限流

负载均衡的后端服务,如果配置了多个不同区域的后端实例组,那么负载均衡会根据负载均衡规则和具体配置,将外部请求转发到后端不同区域的实例组。如下图所示。


在离用户更近的区域创建实例组

使用下面的命令,在香港区域创建实例组。

PROJECT_ID=youzhi-lab
  REGION=asia-east2
  HEALTHCHECK_NAME=mock-server-health-check
  INSTANCE_GROUP_NAME=mock-server-mig-hkg
  INSTANCE_TEMPLATE_NAME=mock-server-template
  INSTANCE_GROUP_ZONES=asia-east2-a,asia-east2-b,asia-east2-c
  BACKEND_NAME=backend-service-wiremock
 
  gcloud beta compute --project=$PROJECT_ID instance-groups managed create
  
$INSTANCE_GROUP_NAME  --base-instance-name=$INSTANCE_GROUP_NAME
  --template=$INSTANCE_TEMPLATE_NAME --size=2 --zones=$INSTANCE_GROUP_ZONES
  --instance-redistribution-type=PROACTIVE --health-check=$HEALTHCHECK_NAME
  --initial-delay=60
 
  gcloud beta compute --project "$PROJECT_ID" instance-groups managed  
  set-autoscaling "$INSTANCE_GROUP_NAME" --region "$REGION"  
  --cool-down-period "60" --max-num-replicas "10"   --min-num-replicas "2"
  --target-load-balancing-utilization "0.8" --mode "on"

然后把新建的香港实例组添加到负载均衡后端的 Backend Service ,作为一个与新加坡区域实例组并列的 Backend 。注意下面配置限制每台虚机的最高可处理 QPS 为 10 。

gcloud compute backend-services   add-backend $BACKEND_NAME
  --balancing-mode=RATE
  --max-rate-per-instance=10
  --capacity-scaler=1
  --instance-group=$INSTANCE_GROUP_NAME
  --instance-group-region=$REGION
  --global

 

在配置生效后,再做一次并发请求测试。


ab -n 15000 -c 5 -m POST -H   "Content-Length:0" -v 3
  http://34.149.204.229/api/post-test

 

测试启动后再看一下请求量监控,可以看到,所有的请求都被负载均衡转发到了香港实例组,而没有任何请求转发到新加坡。这是因为,香港后端离用户(本例为在北京的个人笔记本)更近,那么在实例组处理能力允许时,负载均衡会全量转发到香港实例组。而香港实例组也会进行扩容来承接所有的请求。根据上面配置,香港实例组可以自动扩容到最多 10 台实例,承接 100 QPS 。

  为了避免所有的请求都被香港实例组处理,可以对香港实例组进行扩容数量限制,从而限制其能处理的最大并发请求数。下面将该实例组限制为最多 2 台实例。

gcloud beta compute --project   "$PROJECT_ID" instance-groups managed
  set-autoscaling "$INSTANCE_GROUP_NAME" --region "$REGION"  
  --cool-down-period "60" --max-num-replicas "2" --min-num-replicas   "2"
  --target-load-balancing-utilization "0.8" --mode "on"

此时再做一次请求测试,可以看到,有大约 20 QPS 被转发到了香港实例组,而剩下的请求仍然被转发给新加坡实例组。证明负载均衡可以对转发到新加坡的请求进行限流操作。


注意事项

本问介绍了谷歌云全球负载均衡对后台处理流量进行限流的原理,以及基本操作。但是要注意以下几点。

1.本例对后端流量调度是基于对负载均衡后端做了请求 RATE 配置。理论上也可以使用 CPU 利用率作为后端负载设置,但是需要估算与流量的比例关系。

2.本文要被限流的初始后端是在离用户较远的区域。如果其位于与用户最近的区域,也可以用类似的原理,在更远的区域设立第二组后端,用负载均衡的负载限制配置,将初始后端处理不了的流量调度到第二组后端。

相关推荐