如何在Docker容器中使用巨页(大页)

简介: 在linux环境下常规页面大小是4K,常规巨页大小有两种一种是2MB,一种是1GB。巨页的好处是:减少硬件tlb miss,如此在连续内存访问场景下可以得到较大的性能提升。

在linux环境下常规页面大小是4K,常规巨页大小有两种一种是2MB,一种是1GB。巨页的好处是:减少硬件tlb miss,如此在连续内存访问场景下可以得到较大的性能提升。一般在数据库如:postgreSQL,mySql等数据库都有使用巨页时的优化措施。本文将详细介绍如何在容器环境下使用巨页,以及如何对容器使用的巨页进行限制。

当前centos 7.5为止,透明巨页不支持1GB,只支持4k—>2MB,4MB

第一章 巨页在linux上的配置

在内核中配置CONFIG_HUGETLB_PAGE和CONFIG_HUGETLBFS可以启动巨页。内核启动后通过如下命令可以挂在hugepagefs:

mount -t hugetlbfs nodev /dev/hugepages

我们在centos7.4上,内核配置和上述mount hugetlbfs的过程在系统已经默认启动了。同时系统还启动了透明巨页thp,它简化了我们使用巨页的过程。同时还在系统中配置了扫描和整理巨页的内核进程khugepaged,此进程周期性的将页面进行扫描和整理。

cat /sys/kernel/mm/transparent_hugepage/enabled

如果显示时always或madvise就表明透明巨页启动了。
其他透明巨页的配置请参考网络https://blog.csdn.net/wodatoucai/article/details/78493202

设置主机巨页

通过如下命令可以看到主机巨页数

cat /proc/meminfo |grep -i huge
AnonHugePages: 421888 KB
Hugepages_Total: 0
Hugepages_Free: 0
Hugepages_Rsvd:0
HugePagesize: 2048KB

先喂系统中开16个2MB巨页,可以通过如下方法
方法1:sysctl

sysctl vm.nr_hugepages=16

方法2:直接修改/sys/目录

echo 16 >/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

echo 16 >/sys/device/system/node/$node/hugepages/hugepages-2048kb/nr_hugepages

上述方法喂系统巨页以后,通过cat /proc/meminfo |grep -i huge 就可以看到系统中空闲巨页、巨页总数为16.

第二章 在docker容器里使用巨页

oci runc里对巨页的处理

在oci标准里定义了Spec.Linux.Resource.HugepageLimites,其格式如下:

type HugepageLimit struct{
Pagesize string
Limit uint64
}

而且runc确实也能通过传递过来的config.json文件解析出来的spec设置容器hugetlb.$(hugetlb.Pagesize).limit_in_bytes

$(hugetlb.Pagesize) 为runc中的变量这里用shell方式写出来

Docker-engine(Moby)对巨页的处理

但是在Docker(moby)中,并没有命令参数设置容器的hugepage,在docker-engine里也没有相应的流程处理hugepage。Docker-engine在容器start时的*Daemon containerStart()中首先通过Daemon createSpec()创建的符合Oci标准定义的Spec,然后调用*client create()创建/var/run/docker/libcontainerd/$containerid/config.json。就是在Daemon createSpec()里调用docker-engine\daemon\oci_linux.go:setResouces()填充Spec.Linux.Resources时刻没有对hugetlblimit成员进行任何处理。
在Moby社区里,截止2018年9月27日已经有人提交了hugetlbLimit的pr,但是社区尚未merge过:
https://github.com/moby/moby/pull/29911

操作步骤

既然Docker尚未真正实现巨页,我们也可以手动通过下面的步骤实现对docker容器里限制巨页的使用。

限制所有Docker容器的巨页使用

我们在第一章中介绍了如何向主机系统喂巨页的操作方法。容器作为主机上的进程组,如果不做任何多余配置,那么所有的容器都可以受到第一章中配置的巨页的约束。也就是说假使我在主机上配置16个巨页,我有两个容器那么,这两个容器和主机上的其他进程一共可以16个巨页。
还有一种方式可以将设置所有的Docker容器使用的总巨页数
在docker.service启动以后通过修改:

echo 4194304>/sys/fs/cgroup/docker/hugetlb.2MB.limit_in_bytes

如此修改后,所有的docker容器一共只能用2个2MB的巨页。当然这里配置巨页数要小于或等于第一章中配置的巨页内存大小

限制某个容器的巨页使用

前面的方法可以对所有docker使用的巨页进行限制,这里我们再介绍一种对某个容器使用的巨页进行限制。注意:此方法只能在容器业已启动后进行限制

echo 4194304>/sys/fs/cgroup/hugetlb/docker/$dockerid/hugetlb.2MB.limit_in_bytes

当容器里遭遇到cgroup设置的hugetlblimit导致的巨页分配失败时候,应用会受到SigBus 信号

验证

这里使用如下程序hugetlb.c验证巨页:

#include <sys/mman.h>
#include <stdio.h>
#include <memory.h>
int main(int argc, char argv[]) {
char m;
size_t s = (2UL * 1024 * 1024);
m = mmap(NULL, s, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | 0x40000 /
MAP_HUGETLB
/, -1, 0);
if (m == MAP_FAILED) {
perror("map mem");
m = NULL;
return 1;
}
memset(m, 0, s);
printf("map_hugetlb ok, press ENTER to quit!\n");
getchar();//等待
munmap(m, s);
return 0;
}

在主机上完成编译。

gcc -c hugetlb -o hugetlb.o
gcc hugetlb.o -static -o hugetlb

创建一个目录将测试程序拷贝进去,并通过容器-v参数讲此目录bind mount到容器里首先你需要一个ubuntu镜像

mkdir -p /home/zxy/work
mv hugetlb /home/zxy/work
docker run -it ubuntu:latest -v /home/zxy/work:/home/work bash

进入容器后,运行hugetlb。同时在另外一个主机控制台上,通过docker exec命令再在刚创建的容器上,再创一个bash

docker exec -it dockerid bash

此处运行cat /etc/meminfo|grep -i huge可以看到有一个巨页被使用了。

在hugetlb程序运行完成后,如果按照上一小节的方法将测试容器的/sys/fs/cgroup/hugetlb/docker/$dockerid/hugetlb.2MB.limit_in_bytes修改为0,然后再在上述容器里运行hugetlb程序会提示收到sigbus信号中止了。

如何知道程序使用了巨页

通过如下命令可以看到程序是否使用巨页

echo /proc/$pidof programfilename/maps|grep -i hugepage
Xxxxxxx---xxxxxxx xxxxx. /anon_hugepage(deleted)

上述maps中anon_hugepage里的delete表明这个页面被hugetlbfs使用了,并不是表明删除了。

cgroup实现的hugetlb 控制

cgoup中hugetlb控制hugepage的使用是从内核3.10才开始支持的。有如下控制项:

hugetlb.<hugepagesize>.limit_in_bytes //可读写,控制hugepage的使用量
Hugetlb.<hugepagesize>.max_usage_in_bytes//只读,显示历史上最大hugepage使用量
Hugetlb.<hugepagesize>.usage_in_bytes//只读,显示当前的hugepage使用量
Hugetlb.<hugepagesize>.failcnt//只读,显示因为当前的cgroup hugetlb限制而导致的hugepage分配失败次数。*

总结

在docker上要使用hugepage,需要首先在主机上喂hugepage。如果需要对容器使用的hugepage进行控制,那么需要手动在主机上设置cgroup hugetlb limit。

目录
相关文章
|
13天前
|
监控 NoSQL 时序数据库
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
142 77
|
21天前
|
监控 Docker 容器
在Docker容器中运行打包好的应用程序
在Docker容器中运行打包好的应用程序
|
5天前
|
关系型数据库 应用服务中间件 PHP
实战~如何组织一个多容器项目docker-compose
本文介绍了如何使用Docker搭建Nginx、PHP和MySQL的环境。首先启动Nginx容器并查看IP地址,接着启动Alpine容器并安装curl测试连通性。通过`--link`方式或`docker-compose`配置文件实现服务间的通信。最后展示了Nginx配置文件和PHP代码示例,验证了各服务的正常运行。
20 3
实战~如何组织一个多容器项目docker-compose
|
14天前
|
数据建模 应用服务中间件 nginx
docker替换宿主与容器的映射端口和文件路径
通过正确配置 Docker 的端口和文件路径映射,可以有效地管理容器化应用程序,确保其高效运行和数据持久性。在生产环境中,动态替换映射配置有助于灵活应对各种需求变化。以上方法和步骤提供了一种可靠且易于操作的方案,帮助您轻松管理 Docker 容器的端口和路径映射。
55 3
|
21天前
|
存储 缓存 监控
Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
本文介绍了Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
54 7
|
21天前
|
存储 Prometheus 监控
Docker容器内进行应用调试与故障排除的方法与技巧,包括使用日志、进入容器检查、利用监控工具及检查配置等,旨在帮助用户有效应对应用部署中的挑战,确保应用稳定运行
本文深入探讨了在Docker容器内进行应用调试与故障排除的方法与技巧,包括使用日志、进入容器检查、利用监控工具及检查配置等,旨在帮助用户有效应对应用部署中的挑战,确保应用稳定运行。
30 5
|
21天前
|
开发框架 安全 开发者
Docker 是一种容器化技术,支持开发者将应用及其依赖打包成容器,在不同平台运行而无需修改。
Docker 是一种容器化技术,支持开发者将应用及其依赖打包成容器,在不同平台运行而无需修改。本文探讨了 Docker 在多平台应用构建与部署中的作用,包括环境一致性、依赖管理、快速构建等优势,以及部署流程和注意事项,展示了 Docker 如何简化开发与部署过程,提高效率和可移植性。
49 4
|
21天前
|
负载均衡 网络协议 算法
Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式
本文探讨了Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式,以及软件负载均衡器、云服务负载均衡、容器编排工具等实现手段,强调两者结合的重要性及面临挑战的应对措施。
49 3
|
21天前
|
存储 安全 数据安全/隐私保护
Docker 容器化应用管理更加高效,但数据安全和业务连续性成为关键。
在数字化时代,Docker 容器化应用管理更加高效,但数据安全和业务连续性成为关键。本文探讨了 Docker 应用的备份与恢复策略,涵盖备份的重要性、内容、方法及常见工具,制定备份策略,恢复流程及注意事项,并通过案例分析和未来趋势展望,强调备份与恢复在保障应用安全中的重要性。
26 2
|
21天前
|
存储 安全 数据中心
Docker 容器凭借轻量级和高效的特性,成为应用部署的重要工具
Docker 容器凭借轻量级和高效的特性,成为应用部署的重要工具。本文探讨了 Docker 如何通过 Namespace 和 Cgroups 实现 CPU、内存、网络和存储资源的隔离,提高系统安全性和资源利用率,以及面临的挑战和应对策略。
37 1
下一篇
DataWorks