跳到主要内容
版本:1.2.0

基准测试教程

概述

YuniKorn社区不断优化调度器的性能,确保YuniKorn满足大规模批处理工作负载的性能要求。 因此,社区为性能基准测试构建了一些有用的工具,可以跨版本重用。 本文档介绍了所有这些工具和运行它们的步骤。

硬件

请注意,性能结果因底层硬件而异。 文档中发布的所有结果只能作为参考。 我们鼓励每个人在自己的环境中运行类似的测试,以便根据您自己的硬件获得结果。 本文档仅用于演示目的。

本次测试中使用的服务器列表是(非常感谢国立台中教育大学, Kuan-Chou Lai 为运行测试提供这些服务器):

机型CPU内存下载/上传(Mbps)
HP1636G525.74/509.86
HP1630G564.84/461.82
HP1630G431.06/511.69
HP2432G577.31/576.21
IBM blade H221638G432.11/4.15
IBM blade H221636G714.84/4.14
IBM blade H221642G458.38/4.13
IBM blade H221642G445.42/4.13
IBM blade H221632G400.59/4.13
IBM blade H221612G499.87/4.13
IBM blade H23832G468.51/4.14
WS660T816G87.73/86.30
ASUSPRO D640MB_M640SA48G92.43/93.77
PRO E500 G6_WS720T168G90/87.18
WS E500 G6_WS720T840G92.61/89.78
E500 G588G91.34/85.84
WS E500 G5_WS690T1216G92.2/93.76
WS E500 G5_WS690T832G91/89.41
WS E900 G4_SW980T80512G89.24/87.97

每个服务器都需要执行以下步骤,否则由于用户/进程/打开文件的数量有限,大规模测试可能会失败。

1. 设置/etc/sysctl.conf

kernel.pid_max=400000
fs.inotify.max_user_instances=50000
fs.inotify.max_user_watches=52094

2. 设置/etc/security/limits.conf

* soft nproc 4000000
* hard nproc 4000000
root soft nproc 4000000
root hard nproc 4000000
* soft nofile 50000
* hard nofile 50000
root soft nofile 50000
root hard nofile 50000

部署工作流

在进入细节之前,这里是我们测试中使用的一般步骤:

  • 步骤 1: 正确配置Kubernetes API服务器和控制器管理器,然后添加工作节点。
  • 步骤 2: 部署空pod,将模拟工作节点,命名空节点。 在所有空节点都处于就绪状态后,我们需要封锁(cordon)所有本地节点,这些本地节点是集群中的物理存在,而不是模拟节点,以避免我们将测试工作负载 pod 分配给本地节点。
  • 步骤 3: 在主节点上使用Helm chart部署YuniKorn,并将 Deployment 缩减为 0 副本,并在prometheus.yml修改端口 以匹配服务的端口。
  • 步骤 4: 部署50k Nginx pod进行测试,API服务器将创建它们。 但是由于YuniKorn调度程序Deployment已经被缩减到0个副本,所有的Nginx pod都将停留在等待状态。
  • 步骤 5: 将YuniKorn部署扩展回1个副本,并封锁主节点以避免YuniKorn 在那里分配Nginx pod。 在这一步中,YuniKorn将开始收集指标。
  • 步骤 6: 观察Prometheus UI中公开的指标。

设置 Kubemark

Kubemark是一个性能测试工具,允许用户在模拟集群上运行实验。 主要用例是可扩展性测试。 基本思想是在一个物理节点上运行数十或数百个假kubelet节点,以模拟大规模集群。 在我们的测试中,我们利用 Kubemark 在少于20个物理节点上模拟多达4K节点的集群。

1. 构建镜像

克隆kubernetes仓库,并构建kubemark二进制文件
git clone https://github.com/kubernetes/kubernetes.git
cd kubernetes
KUBE_BUILD_PLATFORMS=linux/amd64 make kubemark GOFLAGS=-v GOGCFLAGS="-N -l"
将kubemark二进制文件复制到镜像文件夹并构建kubemark docker镜像
cp _output/bin/kubemark cluster/images/kubemark
IMAGE_TAG=v1.XX.X make build

完成此步骤后,您可以获得可以模拟集群节点的kubemark镜像。 您可以将其上传到Docker-Hub或仅在本地部署。

2. 安装Kubermark

创建kubemark命名空间
kubectl create ns kubemark
创建configmap
kubectl create configmap node-configmap -n kubemark --from-literal=content.type="test-cluster"
创建secret
kubectl create secret generic kubeconfig --type=Opaque --namespace=kubemark --from-file=kubelet.kubeconfig={kubeconfig_file_path} --from-file=kubeproxy.kubeconfig={kubeconfig_file_path}

3. 标签节点

我们需要给所有的原生节点打上标签,否则调度器可能会将空pod分配给其他模拟的空节点。 我们可以利用yaml中的节点选择器将空pod分配给本地节点。

kubectl label node {node name} tag=tagName

4. 部署Kubemark

hollow-node.yaml如下所示,我们可以配置一些参数。

apiVersion: v1
kind: ReplicationController
metadata:
name: hollow-node
namespace: kubemark
spec:
replicas: 2000 # 要模拟的节点数
selector:
name: hollow-node
template:
metadata:
labels:
name: hollow-node
spec:
nodeSelector: # 利用标签分配给本地节点
tag: tagName
initContainers:
- name: init-inotify-limit
image: docker.io/busybox:latest
imagePullPolicy: IfNotPresent
command: ['sysctl', '-w', 'fs.inotify.max_user_instances=200'] # 设置为与实际节点中的max_user_instance相同
securityContext:
privileged: true
volumes:
- name: kubeconfig-volume
secret:
secretName: kubeconfig
- name: logs-volume
hostPath:
path: /var/log
containers:
- name: hollow-kubelet
image: 0yukali0/kubemark:1.20.10 # 您构建的kubemark映像
imagePullPolicy: IfNotPresent
ports:
- containerPort: 4194
- containerPort: 10250
- containerPort: 10255
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
command:
- /kubemark
args:
- --morph=kubelet
- --name=$(NODE_NAME)
- --kubeconfig=/kubeconfig/kubelet.kubeconfig
- --alsologtostderr
- --v=2
volumeMounts:
- name: kubeconfig-volume
mountPath: /kubeconfig
readOnly: true
- name: logs-volume
mountPath: /var/log
resources:
requests: # 空pod的资源,可以修改。
cpu: 20m
memory: 50M
securityContext:
privileged: true
- name: hollow-proxy
image: 0yukali0/kubemark:1.20.10 # 您构建的kubemark映像
imagePullPolicy: IfNotPresent
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
command:
- /kubemark
args:
- --morph=proxy
- --name=$(NODE_NAME)
- --use-real-proxier=false
- --kubeconfig=/kubeconfig/kubeproxy.kubeconfig
- --alsologtostderr
- --v=2
volumeMounts:
- name: kubeconfig-volume
mountPath: /kubeconfig
readOnly: true
- name: logs-volume
mountPath: /var/log
resources: # 空pod的资源,可以修改。
requests:
cpu: 20m
memory: 50M
tolerations:
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists

完成编辑后,将其应用于集群:

kubectl apply -f hollow-node.yaml

部署 YuniKorn

使用helm安装YuniKorn

我们可以用 Helm 安装 YuniKorn,请参考这个文档。 我们需要根据默认配置调整一些参数。 我们建议克隆发布仓库并修改value.yaml中的参数。

git clone https://github.com/apache/yunikorn-release.git
cd helm-charts/yunikorn

配置

value.yaml中的修改是:

  • 增加调度程序 pod 的内存/cpu 资源
  • 禁用 admission controller
  • 将应用排序策略设置为 FAIR

请参阅以下更改:

resources:
requests:
cpu: 14
memory: 16Gi
limits:
cpu: 14
memory: 16Gi
embedAdmissionController: false
configuration: |
partitions:
-
name: default
queues:
- name: root
submitacl: '*'
queues:
-
name: sandbox
properties:
application.sort.policy: fair

使用本地版本库安装YuniKorn

Helm install yunikorn . --namespace yunikorn

设置Prometheus

YuniKorn通过Prometheus公开其调度指标。 因此,我们需要设置一个Prometheus服务器来收集这些指标。

1. 下载Prometheus版本

wget https://github.com/prometheus/prometheus/releases/download/v2.30.3/prometheus-2.30.3.linux-amd64.tar.gz
tar xvfz prometheus-*.tar.gz
cd prometheus-*

2. 配置prometheus.yml

global:
scrape_interval: 3s
evaluation_interval: 15s

scrape_configs:
- job_name: 'yunikorn'
scrape_interval: 1s
metrics_path: '/ws/v1/metrics'
static_configs:
- targets: ['docker.for.mac.host.internal:9080']
# 9080为内部端口,需要端口转发或修改9080为服务端口

3. 启动Prometheus

./prometheus --config.file=prometheus.yml

运行测试

设置环境后,您就可以运行工作负载并收集结果了。 YuniKorn社区有一些有用的工具来运行工作负载和收集指标,更多详细信息将在此处发布。


收集和观察YuniKorn指标

Prometheus 启动后,可以轻松收集 YuniKorn 指标。 这是 YuniKorn 指标的文档。 YuniKorn 跟踪一些关键调度指标,这些指标衡量一些关键调度路径的延迟。 这些指标包括:

  • scheduling_latency_seconds: 主调度例程的延迟,以秒为单位。
  • app_sorting_latency_seconds: 所有应用程序排序的延迟,以秒为单位。
  • node_sorting_latency_seconds: 所有节点排序的延迟,以秒为单位。
  • queue_sorting_latency_seconds: 所有队列排序的延迟,以秒为单位。
  • container_allocation_attempt_total: 尝试分配容器的总次数。 尝试状态包括 allocatedrejectederrorreleased。 该指标仅增加。

您可以在Prometheus UI上轻松选择和生成图形,例如:

Prometheus Metrics List


性能调优

Kubernetes

默认的 K8s 设置限制了并发请求,这限制了集群的整体吞吐量。 在本节中,我们介绍了一些需要调整的参数,以提高集群的整体吞吐量。

kubeadm

设置pod网络掩码

kubeadm init --pod-network-cidr=10.244.0.0/8

CNI

修改CNI掩码和资源。

  net-conf.json: |
{
"Network": "10.244.0.0/8",
"Backend": {
"Type": "vxlan"
}
}
  resources:
requests:
cpu: "100m"
memory: "200Mi"
limits:
cpu: "100m"
memory: "200Mi"

Api-Server

在 Kubernetes API 服务器中,我们需要修改两个参数:max-mutating-requests-inflightmax-requests-inflight。 这两个参数代表API请求带宽。 因为我们会产生大量的Pod请求,所以我们需要增加这两个参数。修改/etc/kubernetes/manifest/kube-apiserver.yaml

--max-mutating-requests-inflight=3000
--max-requests-inflight=3000

Controller-Manager

在Kubernetes控制器管理器中,我们需要增加三个参数的值:node-cidr-mask-sizekube-api-burst kube-api-qps. kube-api-burstkube-api-qps控制服务器端请求带宽。node-cidr-mask-size表示节点 CIDR。 为了扩展到数千个节点,它也需要增加。

Modify /etc/kubernetes/manifest/kube-controller-manager.yaml:

--node-cidr-mask-size=21 //log2(集群中的最大pod数)
--kube-api-burst=3000
--kube-api-qps=3000

kubelet

在单个工作节点中,我们可以默认运行110个pod。 但是为了获得更高的节点资源利用率,我们需要在Kubelet启动命令中添加一些参数,然后重启它。

修改/etc/systemd/system/kubelet.service.d/10-kubeadm.conf中的起始参数,在起始参数后面添加--max-Pods=300并重启。

systemctl daemon-reload
systemctl restart kubelet

概括

借助Kubemark和Prometheus,我们可以轻松运行基准测试、收集YuniKorn指标并分析性能。 这有助于我们识别调度程序中的性能瓶颈并进一步消除它们。 YuniKorn社区未来将继续改进这些工具,并继续获得更多的性能改进。