大家好,关于仿火山视频网站源码分享很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于火山视频制作软件的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!
本文选自“字节跳动基础架构实践”系列文章。
“字节跳动基础架构实践”系列文章是由字节跳动基础架构部门各技术团队及专家倾力打造的技术干货内容,和大家分享团队在基础架构发展和演进过程中的实践经验与教训,与各位技术同学一起交流成长。
“延迟突刺”、“性能抖动”等问题通常会受到多方因素影响不便排查,本文以线上问题为例,详解TLBshootdown,最终使得CPU的消耗降低2%左右,并消除了抖动突刺,变得更加稳定。
问题背景
在互联网业务运行的过程中,难免遇到“延迟突刺”、“性能抖动”等问题,而通常这类问题会受到多种软件环境甚至硬件环境的影响,原因较为隐晦,解决起来相对棘手。
本文以一个线上问题为例子,深入x86体系结构,结合内核内存管理的知识,辅以多种Linux平台上的Debug工具,详解TLBshootdown问题,最终解决掉该问题,提升了业务性能。
名词约定
Kernel:本文中特指Linux-4.14。
KVM:Kernel-basedVirtualMachine。现在主流的虚拟机技术之一。
Host:指虚拟化场景下的宿主机。
Guest:指虚拟化场景下的虚拟机。
APIC:AdvancedProgrammableInterruptController。IntelCPU使用的中断控制器。
LAPIC:LocalAdvancedProgrammableInterruptController。
IPI:Inter-ProcessorInterrupt。CPU之间相互通知使用。
MMU:MemoryManagementUnit。Kernel用来管理虚拟地址和物理地址映射的硬件。
TLB:TranslationLookasideBuffer。MMU为了加速查找页表,使用的cache。用来加速MMU的转化速度。
PTE:PageTableEntry。管理页表使用的页表项。
jemalloc:一个用户态内存管理的库,在多线程并发的场景下,malloc/free的性能好于glibc默认的实现。
TLBshootdown
TLBshootdown是如何发生的
如上图所示,一个进程有4个thread并行执行。由于4个thread共享同一个进程的页表,在执行的过程中,通过把pgd加载到cr3的方式,每个CPU的TLB中加载了相同的pagetable。
如果CPU0上,想要修改pagetable,尤其是想要释放一些内存,那么需要修改pagetable,同时修改自己的TLB(或者重新加载TLB)。
然而,这还不够。例如,CPU0上释放了pageA,并且pageA被kernel回收,很有可能被其他的进程使用。但是,CPU1、CPU2以及CPU3的TLB中还是缓存了对应的PTE表项,依然可以访问到pageA。
为了防止这个事情发生,CPU0需要通知CPU1、CPU2和CPU3,也需要在TLB中禁用掉对应的PTE。通知的方式就是使用IPI(Inter-ProcessorInterrupt)。
在虚拟化的场景下,IPI的成本比较高。如果Guest中有大量的IPI,就会看到Guest的CPUsys暴涨。同时,在Host上可以发现虚拟机发生vmexit突增,其中主要是wrmsr的ICRRequest产生。(熟悉x86的同学知道,x2apic模式下,x86上IPI的实现即通过wrmsr指令请求ICR)
如何确认是TLBshootdown引起的问题
在Guest中执行:
34;cat/proc/interrupts|grepTLB&perftop\n
如果看到smp_call_function_many,那么很不幸,就是在批量发送IPI。
好消息是这个场景并不常见,比较特定的情况下才会发生。典型的就是用户态进程中调用了系统调用:
intmadvise(void*addr,size_tlength,MADV_DONTNEED);\n
如何检查进程使用了jemalloc,jemalloc会调用madvise,见下文:
strace-f-p15102>&1|grepmadvise\n
madviseMADV_DONTNEED和munmap
确认上述的TLBshootdown问题之后,我们再来回顾一下,系统调用madvise到底起了什么作用呢?
intmadvise(void*addr,size_tlength,MADV_DONTNEED);\n
内存分配的一般过程
使用mmap分配一段虚拟地址空间;第一次访问到某一个4k内的地址的时候,MMU发现没有对应的PTE,触发pagefault;kernel分配对应的page。
如果使用了DONTNEED,就会释放对应的page。如果下一次再访问到,就会重复上述的2和3。
效果就是短暂的page归还kernel之后,下次访问重新分配。
madviseDONTNEED和munmap的区别
例如state0所示,用户态进程分配了VMA0和VMA1两个虚拟机地址空间。有的地址上已经分配了物理页面(例如0x800000),有的还没有分配(例如0x802000)。
如state1所示,用户态进程第一次访问到了例如0x802000地址的时候,触发了pagefault,内核为用户态进程的0x802000分配了物理页面(地址是0x202000)。
如state2所示,执行了:
madvise(0x800000,8192,MADV_DONTNEED)\n
之后,内核释放了对应的物理页面。那么下一次访问到0x800000~0x801fff的时候,就会触发pagefault。处理过程类似state1。
如state3所示,执行了:
munmap(0x800000,16384);\n
就把对应的VMA释放了。那么下次访问到0x800000~0x803fff的时候,就会触发segmentfault。因为地址已经释放,属于非法地址,内核会给进程发送signal11。大部分情况下,会杀掉进程。
使用jemallocENV解决TLBshootdown
问题产生自jemalloc,所以尝试从jemalloc本身入手解决问题。
尝试去社区,问jemalloc的maintainer,是否有办法解决TLBshootdown引起的问题,maintainer建议通过jemalloc环境变量(MALLOC_CONF)动态控制jemalloc是否启动madvise。问题和答复见:
https://github.com/jemalloc/jemalloc/issues/1422\n
在本地写测试代码,实际测试jemalloc(比较靠近upstream的5.0版本)和maintainer给出来的建议,在进程启动前导入环境变量:
MALLOC_CONF=dirty_decay_ms:-1,muzzy_decay_ms:-1\n
可以验证可以成功避免问题。该环境变量可以解决tlb问题,详细参数作用请参看手册:
http://jemalloc.net/jemalloc.3.htmlstringslibjemalloc.so.2|grep-iversion\n
可以发现实际使用的版本是:
JEMALLOC_VERSION&34;\n
通过阅读jemalloc的源代码发现,在4.2版本的时候,还不支持maintainer给出来的变量参数。但是可以通过如下变量来达到类似的效果:
MALLOC_CONF=purge:decay,decay_time:-1\n
设置了jemalloc的参数之后,业务的表现得到了明显的提升。如下图所示,最后一个零点和前一个零点进行对比,CPU的抖动情况得到了很大的改善,从之前的6%左右抖动到低于4%的稳定运行,且CPU的消耗曲线更加稳定平滑。
与此同时,业务上的延迟也更加稳定,PCT99也降低了延迟突刺情况。
写在最后
在解决问题的过程中,也并非如文章所写的一般有序进行。期间也多次使用perf观察热点函数的变化;使用atop对比前后的业务表现和系统指标;也观察虚拟化的监控数据(wrmsr的数量)等等手段,一步一步排除干扰,锁定问题。
随着当代操作系统的复杂度的提高,问题的难度也在提高。在解决问题的过程中,我们也在进步!
最后,欢迎加入字节跳动基础架构团队,一起探讨、解决问题,一起变强!
更多分享
字节跳动自研万亿级图数据库&图计算实践
字节跳动EB级HDFS实践
字节跳动基础架构团队
字节跳动基础架构团队是支撑字节跳动旗下包括抖音、今日头条、西瓜视频、火山小视频在内的多款亿级规模用户产品平稳运行的重要团队,为字节跳动及旗下业务的快速稳定发展提供了保证和推动力。
公司内,基础架构团队主要负责字节跳动私有云建设,管理数以万计服务器规模的集群,负责数万台计算/存储混合部署和在线/离线混合部署,支持若干EB海量数据的稳定存储。
文化上,团队积极拥抱开源和创新的软硬件架构。我们长期招聘基础架构方向的同学,具体可参见https://job.bytedance.com/「链接」,感兴趣可以联系邮箱arch-graph@bytedance.com。
欢迎关注字节跳动技术团队
关于仿火山视频网站源码分享到此分享完毕,希望能帮助到您。
