声明:这是我在大学毕业后进入第二家互联网公司学习的内容


背景

最近准备做虚拟化,经过分析公司现有的设备后我选择了其中配置一样的两台机器并加装内存。

加装后配置如下

  • CPU:I5-9600KF
  • 内存:64G 2666MHZ
  • 磁盘:1THDD

创建了几台虚拟机并稳定运行一段时间

随着我把项目慢慢迁移到虚拟机上发现有一天突然所有机器都“似乎”挂掉了,一起来看看怎么回事吧。

现状

研发人员有天突然发现有个服务挂了,让我查下原因,然后我发现有台机器上的pod状态处于Terminating 状态

而且删除还没用

google了一下出现Terminating的情况有以下几种

  • 磁盘空间不足
  • 存在 “i” 文件属性
  • Docker 17 版本 bug
  • 存在 Finalizers
  • 低版本 kubelet list-watch 的 bug
  • Dockerd 与 containerd 状态不同步
  • Daemonset Controller Bug

可惜发现目前的问题还不是由上面情况造成的

后来观察了下,我又发现所有Terminating的pod都是一台机器上的

然后执行kuberctl get nodes的时候发现

这台机器的状态是notready

好家伙,看来是服务器挂了,结果发现不仅这台机器挂了,还有几台机器我也ssh不进去了。

它们又都是一台服务器虚拟化出来的机器

分析问题

差不多定位到问题了,主机有问题,它虚拟化的机器当然有问题。

我先ping这台机器,发现能通

然后远程连接发现这台机器的CPU已经百分之100,然后一直恐怖地持续了1个多小时了。

我在控制台上看虚拟机的界面都开启了,但实际上没有一台机器能运行

目前这台机器跑了4台虚拟机

我杀掉一台负载最高的一台虚拟机

结果发现其他3台虚拟机又迅速把CPU吃满

直到我杀掉所有进程

把4台虚拟机释放,这才好起来了

然后我了一台机器,正常运行

进入这台机器看系统日志,发现报错如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Nov 27 11:02:10 vm-20-41-k8s-node kernel: NMI watchdog: BUG: soft lockup - CPU#1 stuck for 23s! [kubelet:73052]
Nov 27 11:02:10 vm-20-41-k8s-node kernel: Modules linked in: veth vxlan ip6_udp_tunnel udp_tunnel xt_statistic xt_physdev xt_nat ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6_tables xt_comment xt_mark xt_conntrack ipt_MASQUERADE nf_nat_masquerade_ipv4 nf_conntrack_netlink nfnetlink xt_addrtype iptable_filter iptable_nat nf_nat_ipv4 nf_nat overlay(T) vmw_vsock_vmci_transport vsock iosf_mbi crc32_pclmul ghash_clmulni_intel ppdev aesni_intel vmw_balloon lrw gf128mul glue_helper ablk_helper cryptd joydev pcspkr sg vmw_vmci i2c_piix4 parport_pc parport nf_conntrack_ipv4 nf_defrag_ipv4 br_netfilter bridge stp llc ip_vs_sh ip_vs_wrr ip_vs_rr ip_vs nf_conntrack sunrpc ip_tables xfs libcrc32c sr_mod cdrom sd_mod crc_t10dif crct10dif_generic ata_generic pata_acpi vmwgfx drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops
Nov 27 11:02:10 vm-20-41-k8s-node kernel: ttm ata_piix drm nfit libata libnvdimm mptspi crct10dif_pclmul crct10dif_common scsi_transport_spi crc32c_intel mptscsih e1000 mptbase serio_raw drm_panel_orientation_quirks dm_mirror dm_region_hash dm_log dm_mod
Nov 27 11:02:10 vm-20-41-k8s-node kernel: CPU: 1 PID: 73052 Comm: kubelet Kdump: loaded Tainted: G ------------ T 3.10.0-1127.el7.x86_64 #1
Nov 27 11:02:10 vm-20-41-k8s-node kernel: Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 02/27/2020
Nov 27 11:02:10 vm-20-41-k8s-node kernel: task: ffff88a5fe3862a0 ti: ffff88a60aaec000 task.ti: ffff88a60aaec000
Nov 27 11:02:10 vm-20-41-k8s-node kernel: RIP: 0010:[<ffffffff9d716f62>] [<ffffffff9d716f62>] generic_exec_single+0x102/0x1c0
Nov 27 11:02:10 vm-20-41-k8s-node kernel: RSP: 0000:ffff88a60aaefb60 EFLAGS: 00000202
Nov 27 11:02:10 vm-20-41-k8s-node kernel: RAX: 0000000000000080 RBX: ffff88a60aaefb30 RCX: 0000000000000003
Nov 27 11:02:10 vm-20-41-k8s-node kernel: RDX: ffffffff9de13b10 RSI: 0000000000000080 RDI: 0000000000000286
Nov 27 11:02:10 vm-20-41-k8s-node kernel: RBP: ffff88a60aaefba8 R08: ffffffff9de13b08 R09: ffffd4859e961580
Nov 27 11:02:10 vm-20-41-k8s-node kernel: R10: 0000000000004b35 R11: fffffffffffffffa R12: 0000000000000002
Nov 27 11:02:10 vm-20-41-k8s-node kernel: R13: ffff88a63ffd9008 R14: 0000000000000000 R15: 000000031d65acc0
Nov 27 11:02:10 vm-20-41-k8s-node kernel: FS: 00007f8c97fff700(0000) GS:ffff88a61d640000(0000) knlGS:0000000000000000
Nov 27 11:02:10 vm-20-41-k8s-node kernel: CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
Nov 27 11:02:10 vm-20-41-k8s-node kernel: CR2: 00007f8cac560ee0 CR3: 0000000818c9a000 CR4: 00000000003607e0
Nov 27 11:02:10 vm-20-41-k8s-node kernel: Call Trace:
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d67e730>] ? leave_mm+0x120/0x120
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d67e730>] ? leave_mm+0x120/0x120
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d67e730>] ? leave_mm+0x120/0x120
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d71707f>] smp_call_function_single+0x5f/0xa0
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d984ee5>] ? cpumask_next_and+0x35/0x50
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d71762b>] smp_call_function_many+0x22b/0x270
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d67e8f8>] native_flush_tlb_others+0xb8/0xc0
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d67ea94>] flush_tlb_page+0x54/0xa0
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d8077f8>] ptep_clear_flush+0x68/0xa0
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d7ef345>] wp_page_copy.isra.73+0x335/0x5b0
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d7f176b>] do_wp_page+0xfb/0x720
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d871054>] ? mntput+0x24/0x40
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d85e266>] ? path_openat+0x176/0x5a0
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9d7f5e02>] handle_mm_fault+0xb22/0xfb0
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9dd8d653>] __do_page_fault+0x213/0x500
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9dd8d975>] do_page_fault+0x35/0x90
Nov 27 11:02:10 vm-20-41-k8s-node kernel: [<ffffffff9dd89778>] page_fault+0x28/0x30
Nov 27 11:02:10 vm-20-41-k8s-node kernel: Code: 89 de 48 03 14 c5 e0 0f 35 9e 48 89 df e8 17 51 28 00 84 c0 75 53 45 85 ed 74 16 f6 43 20 01 74 10 0f 1f 84 00 00 00 00 00 f3 90 <f6> 43 20 01 75 f8 31 c0 48 8b 7c 24 28 65 48 33 3c 25 28 00 00

网上查了下资料发现这个报错叫作内核软死锁

内核软死锁

这个bug没有让系统彻底死机,但是若干个进程(或者kernel thread)被锁死在了某个状态(一般在内核区域),很多情况下这个是由于内核锁的使用的问题。

Linux内核对于每一个cpu都有一个监控进程,在技术界这个叫做watchdog(看门狗)。通过ps –ef | grep watchdog能够看见,进程名称大概是watchdog/X(数字:cpu逻辑编号1/2/3/4之类的)。

这个进程或者线程每一秒钟运行一次,否则会睡眠和待机。这个进程运行会收集每一个cpu运行时使用数据的时间并且存放到属于每个cpu自己的内核数据结构。在内核中有很多特定的中断函数。

这些中断函数会调用soft lockup计数,他会使用当前的时间戳与特定(对应的)cpu的内核数据结构中保存的时间对比,如果发现当前的时间戳比对应cpu保存的时间大于设定的阀值,他就假设监测进程或看门狗线程在一个相当可观的时间还没有执。

Cpu软锁为什么会产生,是怎么产生的?如果linux内核是经过精心设计安排的CPU调度访问,那么怎么会产生cpu软死锁?那么只能说由于用户开发的或者第三方软件引入,看我们服务器内核panic的原因就是qmgr进程引起。

因为每一个无限的循环都会一直有一个cpu的执行流程(qmgr进程示一个后台邮件的消息队列服务进程),并且拥有一定的优先级。

Cpu调度器调度一个驱动程序来运行,如果这个驱动程序有问题并且没有被检测到,那么这个驱动程序将会暂用cpu的很长时间。

根据前面的描述,看门狗进程会抓住(catch)这一点并且抛出一个软死锁(soft lockup)错误。软死锁会挂起cpu使你的系统不可用。

软死锁的原因

  • 服务器电源供电不足,导致CPU电压不稳导致CPU死锁
  • 虚机所在的宿主机的CPU太忙或磁盘IO太高
  • BIOS KVM开启以后的相关bug,关闭KVM可解决,但关闭以后物理机不支持虚拟化
  • VM网卡驱动存在bug,处理高水位流量时存在bug导致CPU死锁
  • BIOS开启了超频,导致超频时电压不稳,容易出现CPU死锁
  • Linux kernel存在bug
  • KVM存在bug

监控

万事离不开监控,通过我之前安装的K8S的监控可以清晰的发现,在之前Terminating的容器的生命周期里,最后CPU达到百分之100(2C),出现了2个这样Terminating的容器

那么显而易见,这台虚拟机的进程把CPU跑满,导致这台虚拟机所在宿主机的CPU太慢,从而影响整个虚拟机集群

解决问题

目前这台宿主机上虚拟化的4台配置如下

三台2c 4g

一台6c 48g

而这台宿主机刚刚开始介绍说了是CPU I5-9600KF 只能虚拟化出来6c

怪我当初太贪了,我想的是那3台机器应该占用不了2c,但是提高cpu上限能增加突发情况的CPU处理速度

结果没考虑到当所有的机器都需要大量计算时,整体虚拟机的CPU核心数上限(12c)已经远远超过宿主机的CPU核心数(6c)

最后我将这些机器老老实实改成3台1c的和一台3c的机器了,然后再更改pod的模板,将上限调低到1.2c 最多有2个容器在这个虚拟机上跑

经过几天的测试后发现之前的问题已经不存在。

总结

总结其实没少好说的,贪了一手,毕竟我比较机智,目前只将部分测试环境的服务迁移到这些虚拟机上

这个事件再次印证了一个道理,上生产之前一定要经过大量的测试,每一次暴露的问题都能让你少在生产重犯一些失误,敬畏你的工作——SRE。

PS:至于为什么用酷睿的CPU,其实不是我想用,而是公司还剩很多主机,并且没有额外的服务器,只能拿主机当服务器使用了,就这么简单,我也想用至强的啊。。。

参考资料

Pod 一直处于 Terminating 状态

报错kernel:NMI watchdog: BUG: soft lockup - CPU#0 stuck for 22s


版权声明:

原创不易,洗文可耻。除非注明,本博文章均为原创,转载请以链接形式标明本文地址。