使用 Google Kubernetes Engine 执行分布式负载测试

本教程介绍如何使用 Google Kubernetes Engine (GKE) 部署分布式负载测试框架,该框架使用多个容器为简单的基于 REST 的 API 创建流量。在本教程中,我们会对一个部署到 App Engine 的 Web 应用执行负载测试,该 Web 应用公开了 REST 格式的端点,以捕获传入的 HTTP POST 请求。

您可以使用该模式为各种场景和应用创建负载测试框架,例如消息传递系统、数据流管理系统和数据库系统。

目标

  • 定义环境变量以控制部署配置。
  • 创建 GKE 集群。
  • 执行负载测试。
  • (可选)增加用户数量,或者将模式扩展到其他用例。

费用

本教程使用 Google Cloud 的以下收费组件:

  • Google Kubernetes Engine
  • App Engine
  • Cloud Build
  • Cloud Storage

您可使用价格计算器根据您的预计使用量来估算费用。 Google Cloud 新用户可能有资格申请免费试用

准备工作

  1. 登录您的 Google 帐号。

    如果您还没有 Google 帐号,请注册新帐号

  2. 在 Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目。

    转到项目选择器页面

  3. 确保您的 Cloud 项目已启用结算功能。 了解如何确认您的项目是否已启用结算功能

  4. 启用 Cloud Build, Compute Engine, Container Analysis, and Container Registry API。

    启用 API

完成本教程后,您可以删除所创建的资源以避免继续计费。如需了解详情,请参阅清理

示例工作负载

下图展示了将客户端请求传送到应用的示例工作负载。

从客户端发送到应用的请求。

为对该交互进行建模,您可以使用 Locust 这一基于 Python、可跨多个目标路径分发请求的分布式负载测试工具。例如,Locust 可以将请求分发到 /login/metrics 目标路径。工作负载在 Locust 中建模为一组任务

架构

该架构涉及到两个主要组件:

  • Locust Docker 容器映像。
  • 容器编排和管理机制。

Locust Docker 容器映像包含 Locust 软件。在克隆与本教程配套的 GitHub 代码库时获得的 Dockerfile 使用的是基本 Python 映像,并且包含用于启动 Locust 服务和执行任务的脚本。为尽可能贴近真实客户端的情况,每个 Locust 任务都进行了加权。例如,客户端请求总数每增加一千次,会发生一次注册。

GKE 提供容器编排和管理功能。使用 GKE,您可以指定为负载测试框架奠定基础的容器节点的数量。此外,您还可以将负载测试工作器组织到 pod 中,并指定希望 GKE 持续运行的 pod 数量。

为了部署负载测试任务,请执行以下操作:

  1. 部署负载测试主节点。
  2. 部署一组负载测试工作器。您要使用这些负载测试工作器创建大量的流量,以便执行测试。

下图显示了主节点与工作器节点的内容。

主节点包含 API 服务器、调度器和管理器。两个节点均包含代理程序 Kublet 和一个包含 4 个 pod 的 Docker 映像。

关于负载测试主节点

Locust 主节点是执行负载测试任务的入口点。Locust 主节点配置指定了数个元素,包括容器要公开的端口:

  • 8089 用于网页界面
  • 55575558 用于与工作器通信

此信息稍后将用于配置 Locust 工作器。

您要部署一项服务,确保集群内的其他 pod 可通过 hostname:port 访问所公开的端口。所公开的端口也可以通过描述性的端口名称进行引用。

您可以利用一项服务,让 Locust 工作器能够轻松发现主节点并与之进行可靠的通信,即便主节点发生故障并被部署替换为新的 pod 也是如此。该服务还包括在集群层级创建外部转发规则的指令,以便外部流量能够访问集群资源。

部署 Locust 主节点后,您可以使用外部转发规则的公共 IP 地址来打开网页界面。部署 Locust 工作器后,您可以启动模拟,并通过 Locust 网页界面查看聚合的统计信息。

关于负载测试工作器

Locust 工作器执行负载测试任务。您可以使用单个部署来创建多个 pod。这些 pod 分布在 Kubernetes 集群中。 每个 pod 都可以使用环境变量来控制配置信息,例如受测系统的主机名以及 Locust 主节点的主机名。

下图显示了 Locust 主节点与 Locust 工作器之间的关系。

Locust 主节点位于层次结构顶部,下方有多个工作器。

初始化通用变量

您必须定义多个变量来控制基础架构元素的部署位置。

  1. 打开 Cloud Shell:

    打开 Cloud Shell

    请通过 Cloud Shell 运行本教程中的所有终端命令。

  2. 设置环境变量:

    REGION=us-central1
    ZONE=${REGION}-b
    PROJECT=$(gcloud config get-value project)
    CLUSTER=gke-load-test
    TARGET=${PROJECT}.appspot.com
    SCOPE="https://www.googleapis.com/auth/cloud-platform"
    
  3. 设置默认地区和项目 ID,这样您就不必在每条后续命令中都指定这些值:

    gcloud config set compute/zone ${ZONE}
    gcloud config set project ${PROJECT}
    

设置环境

  1. 从 GitHub 克隆示例代码库:

    git clone https://github.com/GoogleCloudPlatform/distributed-load-testing-using-kubernetes
    
  2. 将您的工作目录更改为克隆的代码库:

    cd distributed-load-testing-using-kubernetes
    

创建 GKE 集群

  1. 创建 GKE 集群:

    gcloud container clusters create $CLUSTER \
       --zone $ZONE \
       --scopes $SCOPE \
       --enable-autoscaling --min-nodes "3" --max-nodes "10" \
       --scopes=logging-write,storage-ro \
       --addons HorizontalPodAutoscaling,HttpLoadBalancing
    
  2. 连接到 GKE 集群:

    gcloud container clusters get-credentials $CLUSTER \
       --zone $ZONE \
       --project $PROJECT
    

构建 Docker 映像

  1. 构建 Docker 映像,并将其存储在项目的 Container Registry 中:

    gcloud builds submit \
        --tag gcr.io/$PROJECT/locust-tasks:latest docker-image
    
  2. 验证该 Docker 映像在项目的 Container Repository 中:

    gcloud container images list | grep locust-tasks
    

    输出如下所示:

    gcr.io/[PROJECT]/locust-tasks
    Only listing images in gcr.io/[PROJECT]. Use --repository to list images in other repositories.
    

部署示例应用

  • 在 App Engine 上部署示例应用:

    gcloud app deploy sample-webapp/app.yaml \
      --project=$PROJECT
    

    输出结果类似于以下内容:

    File upload done.
    Updating service [default]...done.
    Setting traffic split for service [default]...done.
    Deployed service [default] to [https://[PROJECT].appspot.com]
    

部署 Locust 主节点和工作器节点

  1. 将目标主机和项目 ID 替换为 locust-master-controller.yamllocust-worker-controller.yaml 文件中已部署的端点和项目 ID:

    sed -i -e "s/\[TARGET_HOST\]/$TARGET/g" kubernetes-config/locust-master-controller.yaml
    sed -i -e "s/\[TARGET_HOST\]/$TARGET/g" kubernetes-config/locust-worker-controller.yaml
    sed -i -e "s/\[PROJECT_ID\]/$PROJECT/g" kubernetes-config/locust-master-controller.yaml
    sed -i -e "s/\[PROJECT_ID\]/$PROJECT/g" kubernetes-config/locust-worker-controller.yaml
    
  2. 部署 Locust 主节点和工作器节点:

    kubectl apply -f kubernetes-config/locust-master-controller.yaml
    kubectl apply -f kubernetes-config/locust-master-service.yaml
    kubectl apply -f kubernetes-config/locust-worker-controller.yaml
    
  3. 验证 Locust 部署:

    kubectl get pods -o wide
    

    输出结果类似于以下内容:

    NAME                             READY   STATUS    RESTARTS   AGE   IP           NODE
    locust-master-87f8ffd56-pxmsk    1/1     Running   0          1m    10.32.2.6    gke-gke-load-test-default-pool-96a3f394
    locust-worker-58879b475c-279q9   1/1     Running   0          1m    10.32.1.5    gke-gke-load-test-default-pool-96a3f394
    locust-worker-58879b475c-9frbw   1/1     Running   0          1m    10.32.2.8    gke-gke-load-test-default-pool-96a3f394
    locust-worker-58879b475c-dppmz   1/1     Running   0          1m    10.32.2.7    gke-gke-load-test-default-pool-96a3f394
    locust-worker-58879b475c-g8tzf   1/1     Running   0          1m    10.32.0.11   gke-gke-load-test-default-pool-96a3f394
    locust-worker-58879b475c-qcscq   1/1     Running   0          1m    10.32.1.4    gke-gke-load-test-default-pool-96a3f394
    
  4. 验证服务:

    kubectl get services
    

    输出结果类似于以下内容:

    NAME            TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)                                        AGE
    kubernetes      ClusterIP      10.35.240.1     <none>          443/TCP                                        12m
    locust-master   LoadBalancer   10.35.250.221   35.222.247.12   8089:30680/TCP,5557:30699/TCP,5558:31386/TCP   1m
    
  5. 将外部 IP 地址分配给 Locust 主节点服务,同时运行监视循环:

    kubectl get svc locust-master --watch
    
  6. Ctrl+C 退出监视循环,然后运行以下命令以记录外部 IP 地址:

    EXTERNAL_IP=$(kubectl get svc locust-master -o jsonpath="{.status.loadBalancer.ingress[0].ip}")
    

测试负载

您可以使用 Locust 主节点网页界面,针对受测系统执行负载测试任务。

  1. 获取系统的外部 IP 地址:

    echo $EXTERNAL_IP
    

  2. 打开浏览器,然后打开 Locust 主节点网页界面。将以下网址中的 [EXTERNAL_IP] 替换为上一步中获得的 IP 地址:http://[EXTERNAL_IP]:8089

    Locust 主节点网页界面提供了一个对话框,用于启动新的 swarm,并指定用户数量和填充率。

  3. 将总计 Number of users to simulate 指定为 10,将生成用户的 Hatch rate 指定为每秒 5 名用户。

  4. 接下来,点击 Start swarming 以开始模拟。

    在系统开始大量生成请求后,系统会开始聚合统计数据以获得模拟指标,例如请求数量和每秒请求数,如下图所示:

    Locust 网页界面显示统计信息开始聚合。
  5. 点击 Stop 以终止测试。

您可以通过 Google Cloud Console 查看已部署的服务和其他指标。

App Engine 信息中心按类型显示一小时的请求图表。

增加用户数量(可选)

如果要增加用于测试应用的负载,可以添加模拟用户。在添加模拟用户之前,请务必确保有充足的资源可支持负载的增加。借助 Google Cloud,您可以在无需重新部署现有 pod 的前提下为部署添加 Locust 工作器 pod,只要您拥有支持更多 pod 的基础虚拟机资源即可。初始 GKE 集群最初有 3 个节点,最多可通过自动扩缩增加到 10 个节点。

  • 将 Locust 工作器 pod 池扩大到包含 20 个 pod。

    kubectl scale deployment/locust-worker --replicas=20
    

    部署和启动新 pod 需要几分钟时间。

如果看到 Pod Unschedulable 错误,则必须向集群添加更多节点。如需了解详情,请参阅调整 GKE 集群的大小

在 pod 启动完毕之后,返回 Locust 主节点网页界面,重新开始负载测试。

扩展模式

若要扩展此模式,您可以创建新的 Locust 任务,甚至可以改为使用其他负载测试框架。

您可以自定义所收集的指标。例如,您可能想要测量每秒的请求数,可能希望在负载增加时监控响应延迟时间,也可能想要检查响应失败率和错误类型。

如需了解详情,请参阅 Cloud Monitoring 文档。

清理

学完本教程后,请清理您在 GCP 上创建的资源,避免日后再为这些资源付费。

删除项目

为了避免产生费用,最简单的方法是删除您为本教程创建的项目。

如需删除项目,请执行以下操作:

  1. 在 Cloud Console 中,转到管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

删除 GKE 集群

如果您不想删除整个项目,请运行以下命令删除 GKE 集群:

   gcloud container clusters delete $CLUSTER --zone $ZONE
   

后续步骤