在工作中我们针对大数据的任务,最头疼的就是运行参数的配置,OOM等问题层出不穷,而且很多人都不是很清楚资源到底该怎么决定,下面我给大家说一下
在当今凡是大数据的项目,数据集群核心都是hadoop+hive,但是我们往常在项目建设的时候,不可能直接使用原生的东西,不同的厂商都会将这些原生的东西包装成自己的产品,换一个名字,但是其实万变不离其中,无论它怎么变,它底层仍然是使用的这些原生的技术,所以无论是配置还是使用,其实都是差不多的,当然也会有一些,符合自己公司特色的一些使用方法,不过都是些浅的东西,没有代替核心
我现在用当下最火的批流一体化的hive+hadoop+spark on yarn的框架模式给大家举例,首先生产环境框架规模肯定都会使完全分布式,除非是有特殊用途,也说通常情况下hadoop和spark集群都是大于等于三个节点的,所以资源肯定不会像我们自己测试环境那样小,下面我们开始正体
对于原生的spark来说,任务在提交时,有着默认的如下五个参数值,这五个参数值是最核心的五个,其他所有的配置都是为了优化这五个或者是基于这五个而延伸的配置
spark.executor.memory 默认值1g
spark.executor.cores 默认值1核
spark.executor.instances 默认值2个
spark.yarn.am.memory 默认值512m
spark.yarn.am.cores 默认值1核
这几个配置是核心配置的意思从上到下是,每1个executor使用1g内存以及1核数,1个任务对应2个executor实例,applicationmaster使用520m内存以及1核数
从如上配置来看大家可以先自己算一算,总共占了多少资源
如果我所料不差,按照这个思维顺下来,我如果不说,大家会算成3核2.5g,其实我先告诉大家正确答案,这个任务一旦运行,会占用yarn3核7g资源,下面我给大家说下,是为什么
原因一,按照上面的默认配置来运行时,在初始化executor的时候,每一个executor除了后期要运行任务的1g,它本身的运行以及初始化还要多占一点内存,就是说实际上不止申请了1g
原因二,大家如果熟悉的了解mr的运行原理 ,就会知道applicationmaster不是直接生成的,它是在第一个接受task的任务的子节点的executor中生成的,就是说默认配置虽然是一个任务对应两个executor,但用算上用来初始化applicationmaster的executor,其实在任务进行总共启动了三个executor
原因三,在yarn中,为了更加完善充分的利用资源,在yarn中有着两个属性,一是最小申请资源数,二是规整划因子,规整化因子不接受单独配它等于最小可申请资源数,最小申请资源数默认为1024,规整化因子的作用,就是按照最小可申请资源的量,将资源分成一份,一份的
也正是因为如上的三个原因,才导致了实际上整个任务中有三个executor,并且在实例化的时候申请的资源数其实超出了1G,又因为规整化因子使得申请的资源被规整化,最终到达2+2+2=6个g
不过这6个g不是直接一次性申请的,大家有兴趣可以再提交任务之后马上去yarn页面的submitted查看,如果刚好这个任务没有被开始运行,就可以发现任务刚提交在初始化阶段,只会先申请一个executor的内存加上applicationmaster的资源,注意初始化阶段不会申请第一个executor的核数,因为没有用,而applicationmaster对内存只申请了512M,所以规整化英子直接给了1g,导致最后默认配置的任务初始化阶段,首次所申请的资源是1个executor +1核数 + 3g内存
而在applicationmaster初始化之后,它占用的executor并不会因它的初始化完成而kill,而是会用来运行applicationmaster等必要功能,而另外两个实际运行任务的executor也会由applicationmaster和yarn交互生成,且每个都会因为规整化因子而总占用2g+1核数,这也就造成了任务最终资源占用1+2+2+2=7g,1+1+1=3核的结果
本篇博文到此资源的思路就说完了,其他的就向我开始时候说的那样都是围绕这个思路起到优化的作用,也提倡大家可以按照这个思维去发散自己的配置知识,就比方说spark其实可以配置弹性executor个数,也可以控制弹性生成时的最大最小值
我虽然是用的spark on yarn的框架,但是其实所有的框架都是一样的,大家配制的时候要先去琢磨,每一个配置项用来干什么的?知道了用来干什么的那配置起来就简单了
且配置任务的时候,尽量不要想的将资源100%使用,或者是负荷使用,不然迟早出问题,就比如三台子节点,那么每次任务运行,最好是有两个运行任务,一个运行applicationmaster就可以了,除非特别需要,否则不要让一台子节点在一个中任务担任多重任务,毕竟本来任务就很多了集群一个遭不住,崩掉就完了
最后给大家一个经验,工作中绝大多数时候你的思维其实是正确的,但是你任务提交上去之后,你发现占用资源显示还是不对,会有一些偏差,哪怕是优化了集群,这个时候不要哭闹,确实是有这种情况,普遍是三种原因
第一个是,集群的优化问题,比如资源调度器资源把控方案,就不可能说100%一定合适,和在日常生活中一样,不可以存在一定的事情,所以任务跑起来不可能次次使用资源刚刚好就是我们自己理论计算的那么多,这个问题,我们要运行它的发生,不要太钻牛角尖,对于资源配置我们只能说尽量考虑的多一些,使得结果是我们想要的,或者是接近我们逾期结果,不要差太多就好,毕竟机器和人脑还是有差别的
第二个原因是最普遍的,出现在各种非原生工具上,我们现在开发都会用工具的,这些工具有好有坏,毕竟我们做开发的都知道一个道理封装的越完整,能实现的东西就越浅显,就拿我之前使用过一个工具,内置着优化策略,提交的配置参数,内部优化策略认为不是很合适,给进行优化了,当时我头都大,所以大家遇到差异可以考虑去找一找,最后触发任务执行的那条命令,看看和你配置的是不是一样,在工具这方面有的厂家的产品,配置的参数被限制死了,只能配置那么几个,所以有可能大家自定义的其他操作根本没起效,只是生效了工具运行的那一部分
第三种,是业务方面,大家在提交任务配置的时候,从业务方面进行优化确实有时候会和所想的理论占用资源不一样,比如开了spark的动态扩充executor,那么动态增加有时候不会直接申请定死的资源数,但是也不会超出,而是很大的可能会小
对于占用资源这个问题,最后总结一句话,我们的理论占用资源做一个参考就好,我们的最终目的不是任务用了多少,而是尽量的用最优的分配资源状态运行我们的任务