Kubernetes(K8s)是一个开源容器编排系统,可自动执行应用程序部署、扩展和管理。它是云原生世界的操作系统。 K8s 或操作系统中的任何缺陷都可能使用户进程存在风险。作为 PingCAP EE(效率工程)团队,我们在 K8s 中测试 TiDB Operator(一个创建和管理 TiDB 集群的工具)时,发现了两个 Linux 内核错误。这些错误已经困扰我们很长一段时间,并没有在整个 K8s 社区中彻底修复。

经过广泛的调查和诊断,我们已经确定了处理这些问题的方法。在这篇文章中,我们将与大家分享这些解决方法。不过,尽管这些方法很有用,但我们认为这只是权宜之策,相信未来会有更优雅的解决方案,也期望 K8s 社区、RHEL 和 CentOS 可以在不久的将来彻底修复这些问题。

Bug #1: 诊断修复不稳定的 Kmem Accounting

关键词:SLUB: Unable to allocate memory on node -1

社区相关 Issue:

  • https://github.com/kubernetes/kubernetes/issues/61937

  • https://github.com/opencontainers/runc/issues/1725

  • https://support.mesosphere.com/s/article/Critical-Issue-KMEM-MSPH-2018-0006

问题起源

薛定谔平台是我司开发的基于 K8s 建立的一套自动化测试框架,提供各种 Chaos 能力,同时也提供自动化的 Bench 测试,各类异常监控、告警以及自动输出测试报告等功能。我们发现 TiKV 在薛定谔平台上做 OLTP 测试时偶尔会发生 I/O 性能抖动,但从下面几项来看未发现异常:

  • TiKV 和 RocksDB 的日志

  • CPU 使用率

  • 内存和磁盘等负载信息

只能偶尔看到 dmesg 命令执行的结果中包含一些 “SLUB: Unable to allocate memory on node -1” 信息。

问题分析

我们使用 perf-tools 中的 funcslower trace 来执行较慢的内核函数并调整内核参数 hung_task_timeout_secs 阈值,抓取到了一些 TiKV 执行写操作时的内核路径信息:

从上图的信息中可以看到 I/O 抖动和文件系统执行 writepage 有关。同时捕获到性能抖动的前后,在 node 内存资源充足的情况下,dmesg 返回的结果也会出现大量 “SLUB: Unable to allocate memory on node -1” 的信息。

从 hung_task 输出的 call stack 信息结合内核代码发现,内核在执行 bvec_alloc 函数分配 bio_vec 对象时,会先尝试通过 kmem_cache_alloc 进行分配,kmem_cache_alloc 失败后,再进行 fallback 尝试从 mempool 中进行分配,而在 mempool 内部会先尝试执行 pool->alloc 回调进行分配,pool->alloc 分配失败后,内核会将进程设置为不可中断状态并放入等待队列中进行等待,当其他进程向 mempool 归还内存或定时器超时(5s) 后,进程调度器会唤醒该进程进行重试 ,这个等待时间和我们业务监控的抖动延迟相符。

但是我们在创建 Docker 容器时,并没有设置 kmem limit,为什么还会有 kmem 不足的问题呢?为了确定 kmem limit 是否被设置,我们进入 cgroup memory controller 对容器的 kmem 信息进行查看,发现 kmem 的统计信息被开启了,  但 limit 值设置的非常大。

我们已知 kmem accounting 在 RHEL 3.10 版本内核上是不稳定的,因此怀疑 SLUB 分配失败是由内核 bug 引起的,搜索 kernel patch 信息我们发现确实是内核 bug, 在社区高版本内核中已修复:

slub: make dead caches discard free slabs immediately

同时还有一个 namespace 泄漏问题也和 kmem accounting 有关:

mm: memcontrol: fix cgroup creation failure after many small jobs

那么是谁开启了 kmem accounting 功能呢?我们使用 bcc 中的 opensnoop 工具对 kmem 配置文件进行监控,捕获到修改者 runc 。从 K8s 代码上可以确认是 K8s 依赖的 runc 项目默认开启了 kmem accounting。

解决方案

通过上述分析,我们要么升级到高版本内核,要么在启动容器的时候禁用 kmem accounting 功能,目前 runc 已提供条件编译选项,可以通过 Build Tags 来禁用 kmem accounting,关闭后我们测试发现抖动情况消失了,namespace 泄漏问题和 SLUB 分配失败的问题也消失了。

操作步骤

我们需要在 kubelet 和 docker 上都将 kmem account 功能关闭。

1. kubelet 需要重新编译,不同的版本有不同的方式。

如果 kubelet 版本是 v1.14 及以上,则可以通过在编译 kubelet 的时候加上 Build Tags 来关闭 kmem account:

$ git clone --branch v1.14.1 --single-branch --depth 1 [https://github.com/kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
$ cd kubernetes
$ KUBE_GIT_VERSION=v1.14.1 ./build/run.sh make kubelet GOFLAGS="-tags=nokmem"

但如果 kubelet 版本是 v1.13 及以下,则无法通过在编译 kubelet 的时候加 Build Tags 来关闭,需要重新编译 kubelet,步骤如下。

首先下载 Kubernetes 代码:

$ git clone --branch v1.12.8 --single-branch --depth 1 https://github.com/kubernetes/kubernetes
$ cd kubernetes

然后手动将开启 kmem account 功能的 两个函数 替换成 下面这样:

func EnableKernelMemoryAccounting(path string) error {
return nil
}
func setKernelMemory(path string, kernelMemoryLimit int64) error {
return nil
}

之后重新编译 kubelet:

$ KUBE_GIT_VERSION=v1.12.8 ./build/run.sh make kubelet

编译好的 kubelet 在 ./_output/dockerized/bin/$GOOS/$GOARCH/kubelet 中。

2. 同时需要升级 docker-ce 到 18.09.1 以上,此版本 docker 已经将 runc 的 kmem account 功能关闭。

3. 最后需要重启机器。

验证方法是查看新创建的 pod 的所有 container 已关闭 kmem,如果为下面结果则已关闭:

$ cat /sys/fs/cgroup/memory/kubepods/burstable/pod//memory.kmem.slabinfo
cat: memory.kmem.slabinfo: Input/output error

Bug #2:诊断修复网络设备引用计数泄漏问题

关键词:kernel:unregister_netdevice: waiting for eth0 to become free. Usage count = 1

社区相关 Issue:

  • https://github.com/kubernetes/kubernetes/issues/64743

  • https://github.com/projectcalico/calico/issues/1109

  • https://github.com/moby/moby/issues/5618

问题起源

我们的薛定谔分布式测试集群运行一段时间后,经常会持续出现“kernel:unregister_netdevice: waiting for eth0 to become free. Usage count = 1” 问题,并会导致多个进程进入不可中断状态,只能通过重启服务器来解决。

问题分析

通过使用 crash 工具对 vmcore 进行分析,我们发现内核线程阻塞在 netdev_wait_allrefs 函数,无限循环等待 dev->refcnt 降为 0。由于 pod 已经释放了,因此怀疑是引用计数泄漏问题。我们查找 K8s issue 后发现问题出在内核上,但这个问题没有简单的稳定可靠复现方法,且在社区高版本内核上依然会出现这个问题。

为避免每次出现问题都需要重启服务器,我们开发一个内核模块,当发现 net_device 引用计数已泄漏时,将引用计数清 0 后移除此内核模块(避免误删除其他非引用计数泄漏的网卡)。为了避免每次手动清理,我们写了一个监控脚本,周期性自动执行这个操作。但此方案仍然存在缺陷:

  • 引用计数的泄漏和监控发现之间存在一定的延迟,在这段延迟中 K8s 系统可能会出现其他问题;

  • 在内核模块中很难判断是否是引用计数泄漏,netdev_wait_allrefs 会通过 Notification Chains 向所有的消息订阅者不断重试发布 NETDEV_UNREGISTER 和 NETDEV_UNREGISTER_FINAL 消息,而经过 trace 发现消息的订阅者多达 22 个,而去弄清这 22 个订阅者注册的每个回调函数的处理逻辑来判断是否有办法避免误判也不是一件简单的事。

解决方案

在我们准备深入到每个订阅者注册的回调函数逻辑的同时,我们也在持续关注 kernel patch 和 RHEL 的进展,发现 RHEL 的 solutions:3659011 有了一个更新,提到 upstream 提交的一个 patch:

route: set the deleted fnhe fnhe_daddr to 0 in ip_del_fnhe to fix a race

在尝试以 hotfix 的方式为内核打上此补丁后,我们持续测试了 1 周,问题没有再复现。我们向 RHEL 反馈测试信息,得知他们已经开始对此 patch 进行 backport。

操作步骤

推荐内核版本 Centos 7.6 kernel-3.10.0-957 及以上。

1. 安装 kpatch 及 kpatch-build 依赖:

UNAME=$(uname -r)
sudo yum install gcc kernel-devel-${UNAME%.*} elfutils elfutils-devel
sudo yum install pesign yum-utils zlib-devel \
binutils-devel newt-devel python-devel perl-ExtUtils-Embed \
audit-libs audit-libs-devel numactl-devel pciutils-devel bison
# enable CentOS 7 debug repo
sudo yum-config-manager --enable debug
sudo yum-builddep kernel-${UNAME%.*}
sudo debuginfo-install kernel-${UNAME%.*}
# optional, but highly recommended - enable EPEL 7
sudo yum install ccache
ccache --max-size=5G

2. 安装 kpatch 及 kpatch-build:

git clone https://github.com/dynup/kpatch && cd kpatch
make
sudo make install
systemctl enable kpatch

3. 下载并构建热补丁内核模块:

curl -SOL https://raw.githubusercontent.com/pingcap/kdt/master/kpatchs/route.patch
kpatch-build -t vmlinux route.patch (编译生成内核模块)
mkdir -p /var/lib/kpatch/${UNAME}
cp -a livepatch-route.ko /var/lib/kpatch/${UNAME}
systemctl restart kpatch (Loads the kernel module)
kpatch list (Checks the loaded module)

总结

虽然我们修复了这些内核错误,但是未来应该会有更好的解决方案。对于 Bug#1,我们希望 K8s 社区可以为 kubelet 提供一个参数,以允许用户禁用或启用 kmem account 功能。对于 Bug#2,最佳解决方案是由 RHEL 和 CentOS 修复内核错误,希望 TiDB 用户将 CentOS 升级到新版后,不必再担心这个问题。

PingCAP EE 团队致力于提高公司内部的自动化程度和团队协作效率,小伙伴们可通过 这篇文章 了解他们,如果你对这个团队正在“折腾”方向感兴趣的话,欢迎和我们聊一聊~hire@pingcap.com 

内核功能导致重启_诊断修复 TiDB Operator 在 K8s 测试中遇到的 Linux 内核问题相关推荐

  1. 内核功能导致重启_红帽RHEL Linux 7.7正式版发布 支持内核实时修复技术无需重启...

    现归属国际商业机器公司旗下的红帽目前已经推出新的功能版本,新的版本提供跨云基础的增强以及控制等. 这个版本也是红帽企业版 RHEL Linux 7.x 系列最后的功能版本,后续7.x主要将提供错误修复 ...

  2. 【Linux 内核】Linux 操作系统结构 ( Linux 内核在操作系统中的层级 | Linux 内核子系统及关系 | 进程调度 | 内存管理 | 虚拟文件系统 | 网络管理 | 进程间通信 )

    文章目录 一.Linux 内核在操作系统中的层级 二.Linux 内核子系统 三.Linux 内核子系统之间的关系 一.Linux 内核在操作系统中的层级 Linux 内核 所在层级 : 整个计算机系 ...

  3. windows10驱动精灵装完驱动后重启一直诊断修复中。。。完美解决

    给公司电脑重装完系统后安装惯例开始打驱动,用的是驱动精灵,一切顺利,安装完成后重启,结果出问题,正在诊断我的电脑,无法诊断 然后我进入疑难解答 高级选项--启动设置 然后按7禁用驱动签名,成功进入系统 ...

  4. linux内核中启动页面,Linux内核启动过程分析

    下面给出内核映像完整的启动过程: arch/x86/boot/header.S: --->header第一部分(以前的bootsector.S):  载入bootloader到0x7c00处,设 ...

  5. linux内核中的jiffies,Linux内核中的jiffies及其作用介绍及jiffies等相关函数详解

    在LINUX的时钟中断中涉及至二个全局变量一个是xtime,它是timeval数据结构变量,另一个则是jiffies,首先看timeval结构 struct timeval { time_t tv_s ...

  6. 数据增量更新定义_技术资讯 | TiDB在准实时数据仓库中的实践

    " OPPO大数据中心在2019年初承接了接入某业务线核心数据的重要任务:一期目标是建立一个能提供准实时大数据查询服务的数据仓库. 我们选用了之前从未在公司大规模正式使用过的TiDB作为核心 ...

  7. centos7系统引导自动重启_分享一个实用的脚本——全自动一键批量性安装Linux系统...

    一.背景说明: 公司最近需要上线几套业务系统,采购了11台HP服务器,服务器有厂家的工程师协助上架,可是系统人家不给安装,只能我们自己去安装吧. 想一想,机房那个环境呀~真冷!所以坚决不能一台一台去手 ...

  8. edge新版 能够正则式_在最近的一项HTML5测试中,新版Edge浏览器表现满分

    在此之前我们曾经多次关注过有关微软最新基于Chromium内核的Edge浏览器,在经过脱胎换骨的改变之后,新版的Edge浏览器,不管是在使用稳定性,还是在可扩展性上,相比于旧版都是飞跃性的提升. 而微 ...

  9. python行为驱动测试开发_行为驱动开发在 Python 开发测试中的应用

    行为驱动开发 (BDD) 简介 行为驱动开发是什么? 说到行为驱动开发(BDD),无可避免的要提到敏捷里面的测试驱动开发(TDD),TDD 的主要思想是"代码即文档",其倡导的流程 ...

最新文章

  1. boost Release 1.47.0
  2. centos 6 上安装l7 filter尝试过滤xunlei
  3. 图解Android Studio 2.0安装步骤
  4. Linux软件源apt,仓库,包的概念
  5. 全自动安装 linux光盘,CentOS 7.1全自动安装光盘制作详解
  6. gson json和类转换_带有GSON和抽象类的JSON
  7. 链表逆序(JAVA实现)
  8. python工控怎么样_搞工控不了解python,好比雄鹰断了翅膀,理由在这里!
  9. 李宏毅机器学习(七)自监督学习(二)BERT奇闻轶事
  10. 我的SQL相关TIPS
  11. 一个特殊的SQL Server阻塞案例分析
  12. J-Link RTT Viewer 的各种不爽以及解决方案
  13. uni-app cli创建项目打包并配置多环境读取配置文件信息
  14. 上交凯原|法学大陆天花板,本外校录取比1:9,双非含量高达12% | 上海交通大学凯原法学院2022届推免大数据
  15. CorelDRAWX4的VBA插件开发(三十一)使用C++制作动态连接库DLL辅助VBA构键强大功能-(5)在VBA中动态调用DLL文件
  16. 风险中性的深度学习选股策略
  17. 专业治疗选择困难症----帮你做选择
  18. join on 和where 一起使用的细节
  19. 微信3.7版小程序数据分析
  20. Python中文数字(包含小数)转阿拉伯数字参考函数

热门文章

  1. CentOS7.1 KVM虚拟化之虚拟机添加磁盘
  2. Word2vec 讨论
  3. C#基础面试题(学习总结)
  4. jsp+urlrewrite实现html分页简单粗暴实现
  5. IT忍者神龟之Struts2.xml配置全然正确流程能走通可是有红叉解决
  6. SQL Server 2012笔记分享-52:可用性指标
  7. jQuery 图片滚动效果
  8. 导入已有工程相关问题解决实录
  9. CSP认证201412-4 最优灌溉[C++题解]:最小生成树裸题、Kruskal算法求最小生成树
  10. 《图解HTTP》读书笔记--第4章返回结果的HTTP状态码