---
title: 一次k8s pod并发拉起慢的定位过程-官方技术文章-鲲鹏社区
description: 在k8s环境中，并发拉起100个pod，统计这100个pod全部启动完成的平均耗时，平均耗时较大，本文记录优化启动耗时的定位过程。
keywords: 一次,并发拉起慢的,定位过程,官方技术文章,鲲鹏社区,Scheduled,Scheduler,Successfully
url: https://www.hikunpeng.com/developer/techArticles/20250509-1?envFlag=1
section: (其他)
---

# 一次k8s pod并发拉起慢的定位过程-官方技术文章-鲲鹏社区

URL: https://www.hikunpeng.com/developer/techArticles/20250509-1?envFlag=1
描述: 在k8s环境中，并发拉起100个pod，统计这100个pod全部启动完成的平均耗时，平均耗时较大，本文记录优化启动耗时的定位过程。
关键词: 一次,并发拉起慢的,定位过程,官方技术文章,鲲鹏社区,Scheduled,Scheduler,Successfully

官方技术文章 [了解详情](https://www.hikunpeng.com/zh/developer/techArticles)

一次k8s pod并发拉起慢的定位过程

一次k8s pod并发拉起慢的定位过程

k8s

发表于 2025/05/09

0

作者|廖宏科

问题背景

在k8s环境中，并发拉起100个pod，统计这100个pod全部启动完成的平均耗时，平均耗时较大。

应用信息

| 软件名称 | 版本 | 说明 |
| --- | --- | ---|
| k8s | 1.20.2 | k8s框架 |
| openjdk | 1.8 | pod中运行openjdk的镜像 |
| calico | 3.15 | k8s中使用的cni组件 |
| docker | 19.03.10 | docker版本 |

测试方法

k8s的组网为一个master，两个node节点。通过脚本在master节点上并发下发创建100个pod的指令，等待这100全部为running状态之后，通过k8s日志统计每个pod从开始到完成创建的精确耗时，最终得出整体的平均耗时，一开始默认测出来为8s左右，时间偏大，需要调优。

问题定位

1）耗时拆分

结合源码，我们将整个容器部署流程进行拆分，以便分析实际延迟原因及性能瓶颈，大致步骤如下：

1） 
输入部署指令：通过kubectl输入job部署指令，向kube-apiserver请求，apiserver收到后将job对象持久化写入etcd并响应成功。

2） 
创建pod对象：job-controller通过观察apiserver发现有新的job建立后，将其从队列中拉出，根据其配置创建对应pod对象，返回apiserver并写入etcd。

3） 
调度至特定工作节点上：scheduler通过观察apiserver发现有新创建且未被调度的pod，根据特定调度规则选择其运行的工作节点，将节点信息写入pod描述后，返回apiserver并写入etcd。

4） 
创建前检查：特定工作节点上kubelet发现有pod属于该节点后，将其从队列中拉出，根据其描述创建容器。创建容器前需要进行相关检查，包括权限检查，数据目录创建，volume挂载等。

5） 
创建沙盒容器：创建业务容器前，需要先创建沙盒容器及网络接口，用于为pod内容器提供通信服务。

6） 
拉取镜像：根据pod描述拉取对应容器镜像，默认在本地有镜像缓存时直接拉取本地镜像。

7） 
创建容器：镜像拉取完毕后创建业务容器。

8） 
启动容器：容器创建完成后启动，可以开始执行实际业务。

为了方便问题定位，我们将整个过程跨分为三个阶段：调度阶段，创建阶段（包括创建前准备），启动阶段

| K8S集群（日志时间戳分析阶段） | 时间戳阶段介绍 |
| --- | ---|
| 调度阶段 | 100并发容器从收到任务指令到调度到node节点为调度阶段 |
| 创建阶段（docker容器创建、网络创建） | docker容器创建和k8s pod网络创建为创建阶段 |
| 启动阶段 | 创建完到启动过程为启动阶段 |

三个阶段的时间获取方式如下，通过调整master节点的 kube-scheduler的日志等级，可以在scheduler的日志中获取调度完成事件的精确时间；通过调整node节点的kubelet日志等级，可以在node节点的kubelet日志中获取创建完成和启动完成事件的精确时间。

在/etc/kubernetes/manifests/kube-scheduler.yaml添加--v=2，设置Scheduler 的日志等级；

在/usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf添加--v=3, 设置kubelet的日志等级。

| 阶段 | 事件 | 日志记录（v: 打印等级） |
| --- | --- | ---|
| 调度阶段 | Scheduled | Scheduler (v=2)：“Successfully bound pod to node ……” |
| 创建阶段 | Created | Kubelet (v=3)：“Created ……” |
| 启动阶段 | Started | Kubelet (v=3)：“Started ……” |

经过拆分，我们发现总耗时8s中，调度阶段的耗时占比最大：

| 阶段 | 耗时 |
| --- | ---|
| 调度阶段 | 7.7s |
| 创建阶段 | 0.5s |
| 启动阶段 | 0.1s |

2）调度阶段分析

通过分析调度阶段scheduler日志，我们提取每个pod调度完成时间，发现调度过程存在阻塞。接着，我们进一步研读日志打印的信息，发现Throttling
requests异常信息。该异常指向一条scheduler向apiserver发起的http请求，因为触发限流的缘故，等待了比正常耗时远长的时间才得到响应。

耗时日志："Throttling request  took 298.07161ms, request: PUT"， 表示触发了kube-apiserver请求限流。

调度阶段，job-controller和scheduler都要频繁向apiserverhttp请求来新建对象，获取状态，修改状态等，这样的限流机制显然极大地延缓了调度的进行，进而导致延迟加大。

因此，我们需要增大限流的阈值，从而提高网络资源的利用，加速调度阶段的进行，进而减少延迟。

问题解决

1）调度阶段优化

通过上面的分析，我们要增大scheduler和controller的并发限制，还要增大工作节点的kubelet的并发限制，k8s的并发参数主要有两个：

| K8S参数值 | 调整前 | 调整后 |
| --- | --- | ---|
| kube-api-qps | 50 | 150 |
| kube-api-burst | 100 | 200 |

k8s调整前：kube-api-qps：50（默认值），kube-api-burst: 100（默认值）

参数介绍：kube-api-qps
参数是指k8s api 的每秒请求数上限；kube-api-burst 是指 k8s api 的突发请求数。调整以上两个值，来控制每秒请求的阈值和突发请求的阈值。在100并发的测试场景中，调大该值能提升调度效率，降低调度阶段的时延。

具体调整方式如下：

1. 管理节点上Scheduler参数修改

vi /etc/kubernetes/manifests/kube-scheduler.yaml

在spec：containers：-command：中添加如下语句

- --kube-api-qps=150

- --kube-api-burst=200

2. 管理节点上Controller-manager参数修改

vi /etc/kubernetes/manifests/kube-controller-manager.yaml

在spec：containers：-command：中添加如下语句

- --kube-api-qps=150

- --kube-api-burst=200

3. 工作节点上Kubelet参数修改

vi /var/lib/kubelet/kubeadm-flags.env

在KUBELET_KUBEADM_ARGS属性中添加如下语句

--kube-api-qps=150

--kube-api-burst=200

调整完成之后重启kubelet，重新测试发现调度时间从7.7s降低到了0.5s左右，但是创建时间从0.5涨到了5.5s，整体耗时从8s下降到了6s左右。有一定优化，但创建时间大涨。这一现象说明并发调度没有瓶颈之后，并发创建存在较大瓶颈，整体是个此消彼长的态势。

2）创建阶段分析与优化

因为之前创建没有瓶颈，怀疑是之前并发程度不够没有触发创建的瓶颈，因为之前瓶颈在与调度，调度“限流”了并发之后，同一时刻进入创建阶段的pod数量不多，现在调度快速完成之后，同时进入创建阶段的pod就变多，导致创建阶段的并发调度就变得激烈。

通过对比基线环境的各项配置，我们发现存在几个操作系统内核参数的差异：

| 内核参数 | 调整前 | 调整后 |
| --- | --- | ---|
| CONFIG_HZ | CONFIG_HZ=250 | CONFIG_HZ=1000 |
| CONFIG_HZ_250=y | CONFIG_HZ_1000=y |  |

我们修改内核参数，重新编译操作系统内核之后并且重新测试，发现创建时间从5.5s降低到了1s左右，整体耗时来到了1.8s左右。

在Linux内核中，CONFIG_HZ 定义了系统定时器中断的频率，即每秒产生的时钟中断次数。CONFIG_HZ=250， 时间为1s/250 = 4ms，表示CPU 4ms产生一次时钟中断，CONFIG_HZ=1000 表示1ms产生一次时钟中断。

更快的产生时钟中断对于对，调度器能更频繁地调整进程的虚拟运行时间，确保多任务间的资源分配更公平。对于当前这类场景来看，更精确的时间调度，能够减少一些线程等待情况，更好的提高并发拉起性能。
