YARN的Memory和CPU配置调优

/ hadoop / 60浏览

背景

前面介绍了很多Flink On Yarn的实现方案。也经历了近2个月的测试。接下来就是要上线去使用。

由于线上只有基础的HBase、HDFS、ZOOKEEPER,因此,我们需要搭建YARN集群。

资源

下面是我们目前存在的计算机资源信息。

计算机 内存 CPU 硬盘 已部署服务
bigdata-master001 64G 8核 100G HBase Master
HDFS NameNode
bigdata-master002 64G 8核 100G HBase Master
HDFS NameNode
bigdata-slave001 64G 8核 2*1T HBase RegionServer
HDFS DataNode
ZooKeeper Server
bigdata-slave002 64G 8核 2*1T HBase RegionServer
HDFS DataNode
ZooKeeper Server
bigdata-slave003 64G 8核 2*1T HBase RegionServer
HDFS DataNode
ZooKeeper Server
bigdata-slave004 64G 8核 2*1T HBase RegionServer
HDFS DataNode
ZooKeeper Server
bigdata-slave005 64G 8核 2*1T HBase RegionServer
HDFS DataNode
ZooKeeper Server
bigdata-slave006 64G 8核 2*1T HBase RegionServer
HDFS DataNode
ZooKeeper Server
bigdata-slave007 64G 8核 2*1T HBase RegionServer
HDFS DataNode
ZooKeeper Server
bigdata-slave008 64G 8核 2*1T HBase RegionServer
HDFS DataNode
ZooKeeper Server

YARN部署

分离式部署

YARN,资源调度器,用来管理集群中的资源,并将提交的任务(MP、Flink、Spark)调度到对应的容器去执行。

提交到YARN的任务,大部分都是一些离线任务,大数据处理任务,比较消耗CPU、内存。

优点:

分离式部署的方式,使得YARN集群与HBase系统相独立,避免了计算和存储时争抢CPU/内存/网络等物理资源。从而避免了资源枯竭时,影响到正常的业务系统。

缺点:

分离式部署的优点显而易见,缺点其实也有。就是在业务比较空闲的情况下,HBase集群大部分处于空闲状态,资源不能够充分利用。如果资源长期闲置不用,比较可惜,资源利用率太低。

超融合部署

将所有服务,全部堆在一起。可以完全利用资源。缺点除了影响正常业务以外,在规模越来越大、服务越来越多的情况下,管理变得更加困难,硬件故障的概率也会越来越大。

因此,该方式,只适合小集群、业务单一的场景。

部署方式选择

个人意愿:稳定可靠大于资源浪费。

如果在不具备采购新机器的条件下,也可以融合部署。不过需要注意一些点。

由于YARN不会主动探知计算机当前可用多少资源,你告诉它多少,它就管理多少。且YARN上调度的任务,大多都是需要大内存、高CPU的,如果将计算机的全部资源告诉YARN,那么恭喜,YARN会把任务怼到你的计算机像块砖,且失败率会大大提高。

YARN的Memory和CPU配置调优

内存配置

YARN作为一个资源调度器,会考虑集群里面每一台机器的计算资源,然后根据提交的任务申请的资源进行分配container。container是YARN里面资源分配的基本单位,具有一定的内存以及CPU资源。一个节点可以拥有多个container,一个container只能属于一个节点,不能跨节点。

一般情况下,每两个container使用一块磁盘以及一个CPU核的时候可以使集群的资源得到一个比较好的利用。

分配给YARN的内存 = 总内存 - 系统预留内存 - HBase内存 - 其他服务内存

对于我们目前64G的内存,HBase使用的堆内存32G,无堆外内存。系统内存预留8G,其他服务内存预留4G。故每个机器可以有20G的内存交给YARN来管理。对于20G的内存,每个container的最小容量可以设置为1024M。

一般情况下,每两个container使用一块磁盘以及一个CPU核的时候可以使集群的资源得到一个比较好的利用。(经验值,参考文章:https://docs.cloudera.com/HDPDocuments/HDP2/HDP-2.1.1/bk_installing_manually_book/content/rpm-chap1-11.html)

每台计算机最多可以拥有多少个container,可以通过如下方式来计算:

containers = min(2*cores, 1.8*disks, total_memory/min_container_memory)

由于我们的磁盘有三块,一块100G的系统盘 + 2块1T的硬盘。故每个节点可以拥有的containers为:5。

每个container的平均内存使用大小的计算方式如下:

4 = RAM-per-container = max(min_container_memory, total_memory / containers)

通过计算,可得到如下配置:

配置文件 配置参数 参数说明 默认值 计算值
yarn-site.xml yarn.nodemanager.resource.memory-mb 该节点上 YARN 可使用的物理内存总量 8192 MB = containers * RAM-per-container
yarn-site.xml yarn.scheduler.minimum-allocation-mb 单个容器可申请的最小内存 1024MB = RAM-per-container
yarn-site.xml yarn.scheduler.maximum-allocation-mb 单个容器可申请的最大内存 8192 MB = containers * RAM-per-container
yarn-site.xml (check) yarn.app.mapreduce.am.resource.mb MR运行在YARN上时,为AM分配的内存(我们目前不跑MR任务,可以默认值) 1536 MB = 2 * RAM-per-container
yarn-site.xml (check) yarn.app.mapreduce.am.command-opts AppMaster JVM堆大小。(我们目前不跑MR任务,可以默认值) -Xmx1024m = 0.8 2 RAM-per-container
mapred-site.xml mapreduce.map.memory.mb MR任务,MAP阶段内存大小 1024 MB = RAM-per-container
mapred-site.xml mapreduce.reduce.memory.mb MR任务,Reduce阶段内存大小 1024 MB = 2 * RAM-per-container
mapred-site.xml mapreduce.map.java.opts java堆大小 = 0.8 * RAM-per-container
mapred-site.xml mapreduce.reduce.java.opts java堆大小 = 0.8 2 RAM-per-container

CPU配置

YARN中目前的CPU被划分成虚拟CPU(CPU virtual Core),这里的虚拟CPU是YARN自己引入的概念,初衷是,考虑到不同节点的CPU性能可能不同,每个CPU具有的计算能力也是不一样的,比如某个物理CPU的计算能力可能是另外一个物理CPU的2倍,这时候,你可以通过为第一个物理CPU多配置几个虚拟CPU弥补这种差异。用户提交作业时,可以指定每个任务需要的虚拟CPU个数。

虚拟CPU并非物理CPU,例如一个任务只申请了1个vcore,如果任务内部启用了多线程,这些线程都会造成cpu资源不可控,实际cpu利用率会大大提升。

YARN目前只管理内存资源,不管理CPU资源。因此,在超融合部署的场景下,必须要进行CPU资源隔离,才能保证其他服务不受影响。

cgroup

cgroup是系统提供的资源隔离功能,可以隔离系统的多种类型的资源。YARN可以通过cgroup来对资源进行隔离。YARN目前支持对cpu/mem/io三种资源进行隔离。

默认情况下,YARN使用 DefaultContainerExecutor, 以 NodeManager 启动者的身份来执行启动Container等操作,安全性低且没有任何CPU资源隔离机制。

要达到资管隔离的目的,必须要使用 LinuxContainerExecutor,从而以应用提交者的身份创建文件,运行/销毁 Container。允许用户在启动Container后直接将CPU份额和进程ID写入cgroup路径的方式实现CPU资源隔离。

YARN支持cgroup

YARN中启用cgroup的配置参考官方文档:http://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/NodeManagerCgroups.html

在yarn-site.xml中配置

yarn.nodemanager.container-executor.class = org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor
yarn.nodemanager.linux-container-executor.resources-handler.class = org.apache.hadoop.yarn.server.nodemanager.util.CgroupsLCEResourcesHandler
yarn.nodemanager.linux-container-executor.cgroups.hierarchy = cgrup/hbase  #注意写权限
yarn.nodemanager.linux-container-executor.cgroups.mount = false

一旦YARN启用了cgroup,就可以来限制cpu使用情况。yarn配置的具体方式如下:

yarn如何做到cpu隔离

YARN对cpu的资源限制通过soft limit 和 head limit两种方式来进行限制。这两种方式的底层,实际是通过修改 cgroup 的 cpu.cfs_period_us,cpu.cfs_quota_us,cpu.shares 三个文件来实现。

head limit

它是通过改变cpu.cfs_quota_uscpu.cfs_period_us文件控制cpu资源使用的上限。严格按照任务初始分配的cpu进行限制,即使还有空闲的CPU资源也不会占用。cpu的使用情况:

containerCPU = (containerVCores * yarnProcessors) / nodeVCores

例如一台8核的虚拟机,给namenode设置的vcore也为8,启动一个vcore为1的container,在cpu-limit为50%的情况下,使用率不会超过:50%。如果启动了10个1核的容器,总的cpu使用率也不会超过400%。

soft limit

在soft limit下,底层通过 cpu.shares 文件控制资源使用,该参数只能控制资源使用的下限。

对于上面的例子,启动一个vcore为1的container,在cpu-limit为50%的情况下,总的cpu使用率被限制为400%,head limit方式,只能使用50%的cpu,而soft limit模式下,可以使用100%的cpu。

软限制下,container 可以在 NameNode 有空闲 CPU 资源时,超额使用 CPU,这种模式下,可以保证 NM 总体 CPU 使用率比较高,提升集群的计算性能和吞吐量。

所以建议使用软限制方式。不论这个值怎么设置,所有 containers 总的 CPU 使用率都不会超过 cpu-limit 设置的值。

总结

默认值配置,基本不符合我们集群的配置,需要对一些参数进行调整。

内存配置

单个节点交给Yarn管理的内存 = 系统总内存 - 系统使用内存 - 服务内存

对应到我们集群中:

单个节点交给Yarn管理的内存 = 64 - 32 - 8 - 4 = 20G

最大容器数

每个节点,可以创建的container数 = min(2cores, 1.8 disks, total_memory/min_container_memory)

对应到我们集群中:

containers = min(2 8, 1.8 3, 20 / 1) = 5

容器平均使用内存

RAM-per-container = max(min_container_memory, total_memory/containers)

对应到我们集群:

RAM-per-container = max(1, 20/5) = 4

因此内存配置方案:

yarn.nodemanager.resource.memory-mb = 20G

yarn.scheduler.minimum-allocation-mb = 1G

yarn.scheduler.maximum-allocation-mb = 20G

如果后期需要执行MapReduce任务,比如Hive程序,顺便也可以将MapReduce的配置进行优化。

yarn.app.mapreduce.am.resource.mb = 2*4G

yarn.app.mapreduce.am.command-opts = 0.8 2 4G

mapreduce.map.memory.mb = 4G

mapreduce.reduce.memory.mb = 2*4G

mapreduce.map.java.opts = 0.8 * 4G

mapreduce.reduce.java.opts = 0.8 2 4G

cpu配置

启动cgroup

yarn.nodemanager.container-executor.class = org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor

配置cpu核数

NM 会按照机器总的 CPU num* limit-percent 来计算 NM 总体可用的实际 CPU 资源,然后根据 NM 配置的 Vcore 数量来计算每个 Vcore 对应的实际 CPU 资源,再乘以 container 申请的 Vcore 数量计算 container 的实际可用的 CPU 资源。这里需要注意的是,在计算总体可用的 CPU 核数时,NM 默认使用的实际的物理核数,而一个物理核通常会对应多个逻辑核(单核多线程),而且我们默认的 CPU 核数通常都是逻辑核,所以我们需要设置 yarn.nodemanager.resource.count-logical-processors-as-cores 为 true 来指定使用逻辑核来计算 CPU 资源。

yarn.nodemanager.resource.cpu-vcores = 8 * 线程数

yarn.nodemanager.resource.count-logical-processors-as-cores = true

yarn.nodemanager.resource.percentage-physical-cpu-limit = 60

yarn.nodemanager.linux-container-executor.cgroups.strict-resource-usage = false

参考资料:

CDH配置YARN内存

YARN支持cgroup配置

YARN CPU资源隔离