共计 8297 个字符,预计需要花费 21 分钟才能阅读完成。
作者 | 第二天太阳、凯文神父
导读:本文摸索和钻研 Linux 内存通明大页相干技术,优化内存调配,晋升服务性能,节俭机器老本。通过设计残缺的通明大页机制,实现在云上大规模机器集群疾速推广应用,获得 CPU 性能和时延优化 10%+ 显著双收益。本文总结通明大页技术架构机制实践经验,介绍如何在保障服务稳定性前提下,获得多场景性能收益,心愿感兴趣的读者能有所启发。
全文 8456 字,预计浏览工夫 22 分钟。
01 背景
随着业务和计算机硬件技术一直倒退,呈现越来越大的内存机器(>=700G),满足简单计算解决需要,同时 Linux 内核的同步继续迭代降级,操作系统能够反对古代硬件架构的大页面容量性能,以适应越来越大的零碎内存。
在云上大规模机器集群中,传统内存页面管理机制存在肯定的性能问题,以典型举荐零碎服务为例,一方面单次申请产生的两头数据规模较大,另一方面程序广泛应用了本地词典 & 缓存等技术,这使响应单次申请所须要波及的内存访存范畴显著增大。通过 perf 统计线上局部典型程序的 dtlb\_load\_misses.walk\_active 和 dtlb\_store\_misses.walk\_active 的占比,也观测到页表缓存命中率有余的体现,均匀观测大多程序有 5%-10% 的时钟周期存在未命中导致陷入 Page Walk 的景象。
目前在机器硬件大内存和零碎内核技术都具备状况下,通明大页(Transparent Huge Page)内存治理利用成为可能。通过增大页面大小,预期能够显著解决页表缓存命中有余的景象,进而广泛晋升程序性能,然而因为存在若干缺点,次要集中在内存用量显著上涨,频繁回收重整带来额定开销减少以及不可控的随机卡顿。基于这些因素,目前业界对通明大页机制的个别认知均偏负向,排查问题追到通明大页,尚无确切论断阐明对服务影响状况,这也是利用通明大页技术一道难题。
02 大页内存技术演进
内存作为计算机上十分重要的一种资源,程序加载运行、CPU 指令和数据获取等都依赖内存应用,因而内存拜访性能是影响计算机性能的一个很重要的因素。古代 Linux 零碎上内存的调配次要过程如下,见图 1:
1、应用程序通过调用内存调配函数(malloc, free, realloc, calloc),零碎调用 brk 或者 mmap 进行内存调配,申请虚拟内存地址空间。
2、虚拟内存至物理内存映射处理过程,通过申请 MMU 调配单元,依据虚拟地址计算出该地址所属的页面,再依据页面映射表的起始地址计算出该页面映射表 (PageTable) 项所在的物理地址,依据物理地址在高速缓存的 TLB 中寻找该表项的内容,如果该表项不在 TLB 中,就从内存将其内容装载到 TLB 中。
其中:
虚拟内存(_Virtual Memory_):古代操作系统广泛应用的一种技术,每个过程有用独立的逻辑地址空间,内存被分为大小相等的多个块, 称为页(Page). 每个页都是一段间断的地址,对应物理内存上的一块称为页框,通常页和页框大小相等。
MMU(_Memory-Management Unit_):内存治理单元,负责管理虚拟地址到物理地址的内存映射,实现各个用户过程都领有本人的独立的地址空间,提供硬件机制的内存拜访权限查看,爱护每个过程所用的内存不会被其余的过程所毁坏。
PageTable:虚拟内存至物理内存页面映射关系存储单元。
TLB(_Translation Lookaside Buffer_):高速虚构地址映射缓存, 次要为了晋升 MMU 地址映射解决效率,加了缓存机制,如果存在即可间接取出映射地址供应用。
____△____图 1 Linux 内存分配机制(虚构 + 物理映射)
2.1 规范大页(HugePage)
规范大页 Huge pages 通过晋升单位页面的大小,代替传统的 4KB 内存页面,以适应越来越大的零碎内存,让操作系统能够反对古代硬件架构的大页面容量性能,升高 MMU 治理开销,晋升内存解决性能。次要有两种格局大小:2MB 和 1GB,2MB 块大小适宜 GB 大小的内存,1GB 页块大小适宜用于 TB 级别的内存;2MB 是默认的页大小。
长处:
- 无需替换:不存在页面因为内存空间有余而换入换出的问题。
- 加重 TLB Cache 的压力:雷同的内存大小,治理的虚拟地址数量变少,升高了 CPU Cache 可缓存的地址映射压力。
- 升高 Page Table 负载:内存页的数量会缩小,从而须要更少的 Page table,节约了页表所占用的内存数量。
- 打消 Page table 查找负载::因为页面不须要替换,所以不须要页表查找。
- 进步内存的整体性能:页面变大后,解决的页面较少,因而能够显著防止拜访页表时可能呈现的瓶颈。
毛病:
- 须要正当设置,防止内存节约:在操作系统启动期间被动态分配并被保留,共享内存不会被置换,在应用 HugePage 的内存不能被其余的过程应用,所以要正当设置该值,防止造成内存节约。
- 动态设置无奈自适应:如果减少 HugePage 或增加物理内存或者是以后服务器减少了新的实例发生变化,须要从新设置所需的 HugePage 大小。
应用形式:
1)规范大页查看机器开启状况
能够通过以下命令查看大页开启状况
grep Huge /proc/meminfo
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
2)大页设置
通过设置 vm.nr\_hugepages 参数的值批改大页数量,大页调配须要间断的内存,机器长期运行存在内存碎片,可能不满足调配须要,个别开机启动时就须要调配设置,如以下命令设置大页配置:
sysctl -w vm.nr_hugepages=20
3)大页应用
利用须要通过 mmap 零碎调用或者 shmat 和 shmget 零碎调用适配才能够应用大页,个别的利用过程都是不能够拜访此大页空间。
2.2 通明大页(Transparent Huge Pages)
规范大页可带来性能晋升,但存在配置和治理上的艰难,很难手动治理,而且通常须要对代码进行重大的更改能力无效应用,不能通用适配利用的接入应用,从 RHEL 6 开始引入通明大页技术(kernel >=kernel-2.6.32),在规范大页的根底上,通过一个形象层,可能主动创立、治理和应用传统大页,用来进步内存治理的性能,解决大页手动治理的问题,通明大页为系统管理员和开发人员缩小了很多应用传统大页的复杂性。
长处:
- 绝对规范大页,操作系统动静治理大页调配,反对大页调配,大页 -> 一般页换出拆分,依据具体利用应用状况,自适应调整调配。
- 应用上对利用通明,且开源社区继续测试、优化和适配大部分利用,同时反对多种大页申请形式配置,满足多场景的调配需要
毛病:
- THP 在运行时动静分配内存,可能会带来运行时内存调配的 CPU 开销和上涨问题。
- THP 同步申请模式下,调配失败时触发申请时,导致利用的一些随机卡顿景象。
应用形式:
通明大页失效形式:对匿名内存的通明 Hugepage 反对能够齐全禁用,也能够仅在 MADV\_HUGEPAGE 区域内启用(防止耗费更多内存资源的危险),也能够在零碎范畴内启用,能够通过以下办法之一实现:
echo always >/sys/kernel/mm/transparent_hugepage/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabled
大页内存页面碎片整顿管制:
/sys/kernel/mm/transparent_hugepage/defrag
大页内存整理模式:
具体应用如下:
echo always >/sys/kernel/mm/transparent_hugepage/defrag
echo defer >/sys/kernel/mm/transparent_hugepage/defrag
echo defer+madvise >/sys/kernel/mm/transparent_hugepage/defrag
echo madvise >/sys/kernel/mm/transparent_hugepage/defrag
echo never >/sys/kernel/mm/transparent_hugepage/defrag
整体内存页面技术汇总:一般页,规范大页和通明大页次要技术特色和优缺点状况如下表:
03 整体解决方案
大规模在线服务集群开启通明大页,实际中面临一些问题和挑战:
1、大规模机器集群,多利用混布下,环境简单,少数程序未很好适配大页调配,如何管制大页失效形式,对混布利用影响可控。
2、如何晋升利用接入大页机制效率,升高业务接入老本,实现通用推广。
依据云上大规模集群的机器硬件状况,内核版本和服务混布的特点,整体大页机制技术方案设计,从机器内核 (Machine & Kernel),混布容器(container) 和应用服务 (Applicatoin) 三个层级思考,保障机器大页环境,实现容器内随利用定制开启和敞开大页性能,同时兼容默认的规范页面,在接入上基于内存调配库思考通用接入,对业务方通明。上面次要从三个层级介绍大页机制设计思路:
____△____图 2 大页机制技术架构
3.1 机器内核层(Kernel)
在机器内核层面,大页应用次要有通明大页 (Transparent Huge Page) 和一般大页 (Hupgetlb) 两种形式,通明大页具体工作模式分为显式开启 (Explicit Enable) 和隐式开启(Implicit Enable);申请形式上有异步申请(Async Defrag)和同步申请(Sync Defrag)。实际中,依据云上集群混布 & 大部分服务常驻过程特点,抉择通明大页 + 显式开启 + 异步申请模式形式,具体技术选型阐明如下:
- 通明大页(THP)
一般大页 hugetlb 尽管没有动静重整开销,然而目前必须开机预留,在逐步推广期通明大页自适应性更强。
- 显式开启(Explicit Enable)
大多数利用依赖的 malloc 并未良好适应通明大页,会因为碎片带来更大的边疆冗余和更大的重整开销,显式开启能够随程序 malloc 机制降级逐渐开启,也实现混布环境对其它利用影响可控。
- 异步申请(Async Defrag)
同步重整会在重启期带来显著卡顿,运行期也可能会有零星随机卡顿,异步模式能够尽可能防止卡顿产生,因为集群简直都是常驻过程,异步模式个别也足以提供短缺的大页填充率。
机器内核参数设置
开启:
echo 'never' >/sys/kernel/mm/transparent_hugepage/defrag
echo 'madvise' >/sys/kernel/mm/transparent_hugepage/enabled
敞开:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
应用状况:
# 整机查看
grep AnonHugePages /proc/meminfo
AnonHugePages: 612832 kB
#过程查看
cat /proc/pid/smaps | awk '/AnonHugePages/{h+=$2}/Anonymous/{a+=$2}END{print a, h, h/a}'
# 大页应用和申请状况
egrep 'trans|thp' /proc/vmstat
nr_anon_transparent_hugepages 2018
thp_fault_alloc 6021
thp_fault_fallback 0
thp_collapse_alloc 201
thp_collapse_alloc_failed 0
thp_split 22
3.2 Pass 容器层(Container)
云上集群的利用部署,在物理机器之上,次要通过 Pass 化容器虚拟化技术,实现相互间资源和应用隔离,保障利用独立洁净的运行环境,目前通明大页对机器操作系统内核版本有要求(Kernels >= kernel-2.6.32),这样须要对开启大页的服务,反对按内核版本调度部署,保障大页的运行环境,其次对于 PageCache 场景增加安全监控和相应的解决机制,具体阐明如下:
- 亲和部署(Kernel Version Affinity)
通明大页异步重整,依赖高版本内核,在集群多版本内核并存状况下,容器可通过亲和内核部署保障大页环境;这样既能够升高集群全降级内核资源依赖,实现局部服务疾速利用大页,还能够通过同步逐步升内核反对更多大页环境,实现逐渐全笼罩。
- 代码锁定(mlock)
代码段锁定 mlock 机制,局部机器 PageCache 短缺,可能异步重整进一步回收会引起代码段淘汰带来卡顿,目前落地察看不显著。
3.3 应用服务层(Application)**
应用服务层,接入大页须要对利用的内存调配做兼容解决,目前内存应用上,为了性能上的思考,次要间接通过内存库应用内存,咱们对内存库做了针对性优化,对业务应用通明,实现利用通用的疾速接入,其次对应数据和词典类服务可通过间接大页应用形式接入,缩小内存库治理的开销,进一步晋升解决性能。具体阐明如下:
- 通用业务逻辑(Common Business)
优化内存库适应大页调配,接口上对立通过环境变量的形式,管制利用的大页是否开启,晋升惯例内存使用性能,升高接入老本,实现利用通明疾速接入。
- 大块内存生产 (DB&Dict 类) 精细化治理
对于大内存生产场景,比方数据库类或者词典类服务,生产的内存块大小比拟固定,这样能够通过自主 mmap&madvise 应用大页形式,缩小通过内存库带来的额定开销,谋求极致性能优化。
3.4 辅助设施(Assistant)
为了更好的把控和理解机器和利用通明大页应用状况,设计了欠缺的通明大页监控机制,实现无效的性能指标监控,也不便反对对大页内核参数的相干调优。
- 大页使用率
通用大页监控库 Lib 反对任意服务的通用接入,填补非云上环境的监控需要;
云上容器内嵌通明大页监控,通明实现对利用内存大页覆盖率指标查看。
- THP 内核调优
建设机器粒度的内核大页 Khugepaged 过程耗费指标监控;
通过优化调整大页内核参数,综合 Khugepaged 重整大页工夫和资源耗费,保障利用较佳的大页使用率。
04 关键技术
工程实际中,通过大页内核参数调优 + 优化内存库,让利用充沛应用大页内存,最大化施展大页内存解决性能;同时优化内存应用,管制内存涨幅在正当范畴。次要有如下两个方面优化指标:
- 晋升大页覆盖率
因为机器混布环境和异步调配大页的机制,不肯定保障机器内存大页足够调配应用,如何调优大页内核参数和优化内存库,晋升利用大页使用率。如测试中发现零碎 THP 默认参数非最佳,JeMalloc 内存库存在大页应用上的有余中央,可优化实现应用大页性能最大化。
- 升高内存上涨幅度
对于页面从规范的 4KB 晋升至 2MB 大小, 未做很好适配的利用,可能存在肯定的内存涨幅,通过调整内存库参数,升高开启大页内存带来的内存上涨开销,管制在正当的 10% 左右范畴。
5.1 大页相干参数调优
4.1 大页相干参数调优
联合内核大页参数和 Malloc 库参数,晋升服务大页调配覆盖率和缩小内存开销。
1. 通明大页内核参数调优
通过优化相干内核参数,综合 CPU 开销和重整速度,晋升大页调配效率,内核大页治理过程 khugepaged 进行大页的调配、聚合和拆分等操作,主要参数如下:
alloc\_sleep\_millisecs:整顿一次碎片距离,如果本次调配大页失败,下一次尝试调配时期待时长,单位毫秒。
max\_ptes\_none:指定将一组小页面合并为一个大页面时,能够调配多少额定的小页面数量。
pages\_to\_scan:每次扫描的页面数量。
scan\_sleep\_millisecs:扫描距离,单位毫秒。
对应常驻的服务,能够通过如下参数组合配置,实现大页重整在较小开销下,保障较好的大页覆盖率。
echo '100' >/sys/kernel/mm/transparent_hugepage/khugepaged/alloc_sleep_millisecs
echo '511' > /sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_none
echo '2048' >/sys/kernel/mm/transparent_hugepage/khugepaged/pages_to_scan
echo '100' >/sys/kernel/mm/transparent_hugepage/khugepaged/scan_sleep_millisecs
2.Malloc 库调配参数调优
以 JeMalloc 为例,默认初始化内存块 (arena) 大小, 是机器的 CPU 核数 *4,在过程启动后无奈动静批改,在实践中,通常状况利用无需这么多内存块,个别依据逻辑核数量配置即可,这样能够优化大页内存下的内存开销。
4.2 应用层内存池化技术
通过内存池化,进一步晋升大页的应用效率,缩小碎片内存长期占用导致的内存上涨,优化升高内存应用,目前次要从以下两个方面发展优化。
- 内存池 - 长生命周期碎片内存
通过内存池技术,整块内存间断调配治理,防止重复申请和开释,解决长期 cache 场景下,小内存碎片长期滞留,导致内存上涨较多状况。
- 自定义大页 - 大块内存申请应用场景
程序内有大块内存操作应用,大小较固定,如 DB 类,词典服务等,大块内存应用 THP madvise 自行开发治理,小内存应用 Malloc 库,进一步晋升性能。
自定义大页,次要应用步骤:
1. HugePage 大小对齐申请
size_t mem_size = num*(2UL <<20); //2MB 倍数
auto* ptr = (char*)mmap(nullptr, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
2. MADVISE 区域标记应用
通过接口 int madvise(void *addr, size\_t length, int advice) 应用标记 MADV\_HUGEPAGE 大页内存,如:
int ret = madvise(ptr, mem_size, MADV_HUGEPAGE);
if (ret != 0) {
//fail
std::cout << "fail ret:" << ret;
return -1;
}
//success todo
3. HugePage 大小对齐应用 & 开释
应用:能够自行治理这段 num*HugePage 大小内存应用,尽量凑齐到 HugePage 大小倍数应用
开释:保障 HugePage 大小倍数开释,这样缩小大页被拆分,导致下次申请失败,触发异步重整操作,带来肯定机器性能开销。
05 模块开启大页性能测试状况
以举荐零碎中一个服务模块为例,通过理论业务场景流量压测,比照大页版本 vs 一般版本性能指标,从次要的底层 cache 性能和过程性能两方面进行剖析评比:
- 内存 Cache miss 指标
通过 perf 工具统计过程读写换页 (dtlb\_load\_misses.walk\_active 和 dtlb\_store\_misses.walk\_active) 降落 66%+,具体指令状况如下表:
- 过程性能指标
统计服务过程的 CPU 和解决时延指标,大页版本实现 CPU 均匀优化 11.3%,均匀时延优化 11.2%,具体见下表:
06 总结
通过钻研通明大页技术优化内存调配,晋升服务性能,并在云上大规模集群落地,实践证明是一个卓有成效的性能优化伎俩。目前通明大页机制在百度外围举荐零碎全面落地,笼罩举荐零碎所有次要模块,性能收益显著,获得 CPU 优化 10%+,时延升高 10%+。
作为后续,本我的项目也在一直摸索大规模 C ++ 服务优化的最佳实际,也欢送志同道合者独特探讨。
参考资料:
https://www.kernel.org/doc/ht…
https://jemalloc.net/jemalloc…
https://linux.die.net/man/2/m…
——-END——–
举荐浏览:
百度直播 iOS SDK 平台化输入革新
百度 APP 基于 Pipeline as Code 的继续集成实际
Go 语言应用 MySQL 的常见故障剖析和应答办法
百度交易中台之钱包零碎架构浅析
基于宽表的数据建模利用