首页 > 编程知识 正文

深入理解linux内核第二章(linux核心编程)

时间:2023-05-05 14:06:35 阅读:91902 作者:4261

本文选自“字节跳动基础架构实践”系列文章。

《字节跳动基础设施实践》系列文章是字节跳动基础设施部门各技术团队和专家大力打造的技术干货内容,与大家分享基础设施发展过程中团队的实践经验和教训,与各位技术同学一起

“延迟浪涌”、“性能抖动”等问题通常由于多种因素而难以排除。 本文以在线问题为例,通过详细调查TLB shootdown,最终将CPU的消耗量减少2%左右,消除抖动、浪涌,使之更加稳定。

问题背景

在互联网业务运行中,不可避免地会遇到“延迟浪涌”、“性能下降”等问题。 这类问题通常受许多软件环境、甚至硬件环境的影响,原因模糊,相对难以解决。

本文以在线问题为例,深入x86架构,结合内核内存管理知识,辅以许多Linux平台上的调试工具,详细解决了TLB shootdown问题,最终解决了这个问题

名词约定

Kernel :本文中特别指Linux-4.14。

KVM :基于kernel的虚拟机器。 是目前主流的虚拟机技术之一。

Host :指虚拟化场景中的瘦主机。

Guest :指虚拟化场景中的虚拟机。

apic :高级编程序集成控制器。 Intel CPU使用的中断控制器。

lapic :局域网辅助控制器。

IPI :中央处理器中断。 CPU之间相互通知使用。

mu :内存管理单元。 Kernel用来管理虚拟和物理地址映射的硬件。

翻译锁定辅助缓冲器。 mu使用cache来加速页面表的搜索。 用于加快MMU的转换速度。

页面表条目。 管理页面表中使用的页面表项目。

jemalloc :在多线程并发的情况下,malloc/free的性能优于glibc的缺省实现的用户状态内存管理库。

TLB shootdown

TLB shootdown 是如何发生的

如上图所示,一个进程将同时运行四个thread。 由于四个thread共享同一进程的页表,因此在运行时将pgd加载到cr3中会将同一页表加载到每个CPU的TLB中。

在CPU0中,如果想要修改page table,特别是想要释放一些内存,则需要在修改page table的同时修改自己的TLB (或者重新加载TLB )。

但是,这还不够。 例如,很可能在CPU0中释放page A,并且page A被回收到kernel中,然后在其他过程中使用。 然而,与CPU1、CPU2和CPU3的TLB相对应的PTE条目被缓存,并且仍然可以访问页面a。

为了防止这种情况发生,CPU0需要通知CPU1、CPU2和CPU3,还需要在TLB中禁用对应的PTE。 通知方法是使用中间处理器中断(IPI )。

在虚拟化方案中,IPI的成本很高。 如果Guest有大量的IPI,就会看到Guest的CPU sys暴涨。 同时,可以看到,主机在虚拟机中出现了虚拟机退出的激增,其中主要发生了wrmsr的ICR请求。 (熟悉x86的学生知道,在x2apic模式下,x86上的IPI实现通过wrmsr命令请求ICR )

如何确认是 TLB shootdown 引起的问题

在Guest中运行。 # # watch-d-n1' cat/proc /中断| grep TLB '

如果看到数据的急剧上升,基本上就会看到问题。

在Guest上运行: #perf top

当你看到smp_call_function_many时,很遗憾,

就是在批量发送 IPI。

好消息是这个场景并不常见,比较特定的情况下才会发生。典型的就是用户态进程中调用了系统调用:

int madvise(void *addr, size_t length, MADV_DONTNEED); 如何检查进程使用了 jemalloc,jemalloc 会调用 madvise,见下文:# ls /proc/*/maps | xargs grep jemalloc

确实对应的进程是否在执行 madvise 的方法, MADV_DONTNEED 会释放页表项,进而引起 tlb shootdown。所以 MADV_DONTNEED 是判断 tlb 问题的重要线索:# strace -f -p 1510 2>&1 | grep madvise

madvise MADV_DONTNEED 和 munmap

确认上述的 TLB shootdown 问题之后,我们再来回顾一下,系统调用 madvise 到底起了什么作用呢?

int madvise(void *addr, size_t length, MADV_DONTNEED);

内存分配的一般过程

使用 mmap 分配一段虚拟地址空间;第一次访问到某一个 4k 内的地址的时候,MMU 发现没有对应的 PTE,触发 page fault;kernel 分配对应的 page。

如果使用了 DONTNEED,就会释放对应的 page。如果下一次再访问到,就会重复上述的 2 和 3。

效果就是短暂的 page 归还 kernel 之后,下次访问重新分配。

madvise DONTNEED 和 munmap 的区别

例如 state 0 所示,用户态进程分配了 VMA0 和 VMA1 两个虚拟机地址空间。有的地址上已经分配了物理页面(例如 0x800000),有的还没有分配(例如 0x802000)。

如 state 1 所示,用户态进程第一次访问到了例如 0x802000 地址的时候,触发了 page fault,内核为用户态进程的 0x802000 分配了物理页面(地址是 0x202000)。

如 state 2 所示,执行了:

madvise(0x800000, 8192, MADV_DONTNEED)

之后,内核释放了对应的物理页面。那么下一次访问到 0x800000 ~ 0x801fff 的时候,就会触发 page fault。处理过程类似 state 1。

如 state 3 所示,执行了:

munmap(0x800000, 16384);

就把对应的 VMA 释放了。那么下次访问到 0x800000 ~ 0x803fff 的时候,就会触发 segment fault。因为地址已经释放,属于非法地址,内核会给进程发送 signal 11。大部分情况下,会杀掉进程。

使用 jemalloc ENV 解决 TLB shootdown

问题产生自 jemalloc,所以尝试从 jemalloc 本身入手解决问题。

尝试去社区,问 jemalloc 的 maintainer,是否有办法解决 TLB shootdown 引起的问题,maintainer 建议通过 jemalloc 环境变量(MALLOC_CONF)动态控制 jemalloc 是否启动 madvise。问题和答复见:

https://github.com/jemalloc/jemalloc/issues/1422

在本地写测试代码,实际测试 jemalloc(比较靠近 upstream 的 5.0版本)和 maintainer 给出来的建议,在进程启动前导入环境变量:

MALLOC_CONF=dirty_decay_ms:-1,muzzy_decay_ms:-1

可以验证可以成功避免问题。该环境变量可以解决 tlb 问题,详细参数作用请参看手册:

http://jemalloc.net/jemalloc.3.html#opt.dirty_decay_ms

某业务同样使用了 jemalloc,但是测试没有效果。

对业务实际使用的 so 动态链接库进行:

#strings libjemalloc.so.2 | grep -i version

可以发现实际使用的版本是:

JEMALLOC_VERSION "4.2.0-0-gf70a254d44c8d30af2cd5d30531fb18fdabaae6d"

通过阅读 jemalloc 的源代码发现,在 4.2 版本的时候,还不支持 maintainer 给出来的变量参数。但是可以通过如下变量来达到类似的效果:

MALLOC_CONF=purge:decay,decay_time:-1

设置了 jemalloc 的参数之后,业务的表现得到了明显的提升。如下图所示,最后一个零点和前一个零点进行对比,CPU 的抖动情况得到了很大的改善,从之前的 6% 左右抖动到低于 4% 的稳定运行,且 CPU 的消耗曲线更加稳定平滑。

与此同时,业务上的延迟也更加稳定,PCT99 也降低了延迟突刺情况。

写在最后

在解决问题的过程中,也并非如文章所写的一般有序进行。期间也多次使用 perf 观察热点函数的变化;使用 atop 对比前后的业务表现和系统指标;也观察虚拟化的监控数据(wrmsr 的数量)等等手段,一步一步排除干扰,锁定问题。

随着当代操作系统的复杂度的提高,问题的难度也在提高。在解决问题的过程中,我们也在进步!

最后,欢迎加入字节跳动基础架构团队,一起探讨、解决问题,一起变强!

更多分享

字节跳动自研万亿级图数据库 & 图计算实践

字节跳动 EB 级 HDFS 实践


字节跳动基础架构团队

字节跳动基础架构团队是支撑字节跳动旗下包括抖音、今日头条、西瓜视频、火山小视频在内的多款亿级规模用户产品平稳运行的重要团队,为字节跳动及旗下业务的快速稳定发展提供了保证和推动力。

公司内,基础架构团队主要负责字节跳动私有云建设,管理数以万计服务器规模的集群,负责数万台计算/存储混合部署和在线/离线混合部署,支持若干 EB 海量数据的稳定存储。

文化上,团队积极拥抱开源和创新的软硬件架构。我们长期招聘基础架构方向的同学,具体可参见 https://job.bytedance.com/「链接」,感兴趣可以联系邮箱 arch-graph@bytedance.com 。

欢迎关注字节跳动技术团队

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。