精华内容
下载资源
问答
  • 近20年来,对大通湖的开发利用己明显产生成效,但就如何更加科学合理地综合利用与开发该湖泊,仍然是面临的重大问题。为此,从大通湖自然资源调查着手,在充分调查与分析研究的基础上,提出了大通湖综合开发利用以及大通湖...
  • 如何合理确定线程池的大小

    千次阅读 2018-05-07 22:10:21
    开发过程中,合理的使用线程池能够带来3个好处 首先是降低资源消耗。通过重复利用已创建的线程降低创建线程和销毁线程所带来的开销。 提高相应速度。当任务到达时,任务可以不需要等待线程创建就立即执行。 提高...

    在java中,几乎所有需要异步或者并发执行任务的程序都可以使用线程池。在开发过程中,合理的使用线程池能够带来3个好处

    1. 首先是降低资源消耗。通过重复利用已创建的线程降低创建线程和销毁线程所带来的开销。
    2. 提高相应速度。当任务到达时,任务可以不需要等待线程创建就立即执行。
    3. 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅消耗系统资源,同时降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。

    如何合理的使用线程池,如何合理的给出线程池的大小,是非常重要的。
    对于线程池的大小不能过大,也不能过小。过大会有大量的线程在相对较少的CPU和内存上竞争,过小又会导致空闲的处理器无法工作,浪费资源,降低吞吐率。

    对于线程池大小的设定,我们需要考虑的问题有:

    • CPU个数
    • 内存大小
    • 任务类型,是计算密集型(CPU密集型)还是I/O密集型
    • 是否需要一些稀缺资源,像数据库连接这种等等
    • 等等

    有种简单的估算方式,设N为CPU个数

    • 对于CPU密集型的应用,线程池的大小设置为N+1
    • 对于I/O密集型的应用,线程池的大小设置为2N+1
      这种设置方式适合于一台机器上的应用的类型是单一的,并且只有一个线程池,实际情况还需要根据实际的应用进行验证。

    在I/O优化中,以下的估算公式可能更合理
    最佳线程数量 = ((线程等待时间+线程CPU时间)/ 线程CPU时间)* CPU个数

    由公式可得,线程等待时间所占比例越高,需要越多的线程。
    线程CPU时间所占比例越高,所需的线程数越少。

    展开全文
  • 分析了秦岭植物资源的...对秦岭植物资源的现状、保护、利用如何进行可持续发展作了分析研究,总结出合理发展旅游业、利用森林草场资源、保护经济植物及发展优势植物的培育是秦岭植物资源利用和可持续发展的有效途径
  • 在分布式系统开发中,我们经常会遇到服务器负载均衡的问题,我们需要将用户的请求均匀的分摊到每一台服务器,从而保证系统资源的有效利用。那么如何将请求均匀的进行分配呢?比较常见的就是 Hash 算法了,但是普通的...

    在分布式系统开发中,我们经常会遇到服务器负载均衡的问题,我们需要将用户的请求均匀的分摊到每一台服务器,从而保证系统资源的有效利用。那么如何将请求均匀的进行分配呢?比较常见的就是 Hash 算法了,但是普通的余数hash(hash(比如用户id)%服务器机器数)算法伸缩性很差,当新增或者下线服务器机器时候,用户id与服务器的映射关系会大量失效。一致性hash则利用hash环对其进行了改进。

    1. Hash 算法

    Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。

    常用的 Hash 算法如下:

    (1)MD4

    MD4(RFC 1320)是 MIT 的Ronald L. Rivest在 1990 年设计的,MD 是 Message Digest(消息摘要) 的缩写。它适用在32位字长的处理器上用高速软件实现——它是基于 32位操作数的位操作来实现的。

    (2)MD5

    MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好。

    (3)SHA-1及其他

    SHA1是由NIST NSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。

    2. 一致性 Hash 算法

    一致性哈希算法在1997年由麻省理工学院提出,是一种特殊的哈希算法,目的是解决分布式缓存的问题。在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系。一致性哈希解决了简单哈希算法在分布式哈希表( Distributed Hash Table,DHT) 中存在的动态伸缩等问题 。

    我们通过算法来实现一个一致性 Hash:

    初始化哈希环
    对哈希环的key进行排序
    通过hash值匹配node节点
    package main
    
    import (
    	"fmt"
    	"hash/crc32"
    	"math/rand"
    	"sort"
    	"strconv"
    	"sync"
    	"time"
    )
    
    // 一致性 Hash 节点副本数量
    const DEFAULT_REPLICAS = 100
    
    // SortKeys 存储一致性 Hash 的值
    type SortKeys []uint32
    
    // Len 一致性哈希数量
    func (sk SortKeys) Len() int {
    	return len(sk)
    }
    
    // Less Hash 值的比较
    func (sk SortKeys) Less(i, j int) bool {
    	return sk[i] < sk[j]
    }
    
    // Swap 交换两个 Hash 值
    func (sk SortKeys) Swap(i, j int) {
    	sk[i], sk[j] = sk[j], sk[i]
    }
    
    // Hash 环,存储每一个节点的信息
    type HashRing struct {
    	Nodes map[uint32]string
    	Keys  SortKeys
    	sync.RWMutex
    }
    
    // New 根据node新建一个Hash环
    func (hr *HashRing) New(nodes []string) {
    	if nodes == nil {
    		return
    	}
    	hr.Nodes = make(map[uint32]string)
    	hr.Keys = SortKeys{}
    	for _, node := range nodes {
    		// Hash 通过 node 节点名称生成哈希值,该Hash值指向对应 node 节点
    		hr.Nodes[hr.Hash(str)] = node
    		// 将哈希值保存在key列表中
    		hr.Keys = append(hr.Keys, hr.Hash(str))
    	}
    	// 对 Hash 值进行排序,后面计算的 Hash 值与 Keys 进行比较,取大于等于计算所得的Hash值所对应的node节点
    	sort.Sort(hr.Keys)
    }
    
    // hashStr 根据Key计算Hash值
    func (hr *HashRing) Hash(key string) uint32 {
    	return crc32.ChecksumIEEE([]byte(key))
    }
    
    // GetNode 根据key找出对应的node节点
    func (hr *HashRing) GetNode(key string) string {
    	hr.RLock()
    	defer hr.RUnlock()
    	hash := hr.Hash(key)
    	i := hr.get_position(hash)
    	return hr.Nodes[hr.Keys[i]]
    }
    
    // get_position 找出第一个大于等于 hash 的key
    func (hr *HashRing) get_position(hash uint32) (i int) {
    	i = sort.Search(len(hr.Keys), func(i int) bool {
    		return hr.Keys[i] >= hash
    	})
    	if i >= len(hr.Keys) {
    		return 0
    	}
    	return
    }
    
    func main() {
    	var nodes []string
    	// 初始化 node 节点
    	for i := 1; i < 6; i++ {
    		nodes = append(nodes, fmt.Sprintf("Server%d", i))
    	}
    	hashR := new(HashRing)
    	// 生成 hash 环
    	hashR.New(nodes)
    	rand.Seed(time.Now().Unix())
    	// 寻找匹配的 node 节点
    	fmt.Println("random1", " 发送到 ", hashR.GetNode("random1"))
    }
    

    3. 一致性 Hash 算法的改进

    在服务器数量比较少的情况下,一致性 Hash 非常容易出现数据倾斜的问题,为了解决这个问题,人们引入了一致性 Hash 来解决这个问题。

    // New 根据node新建一个Hash环
    func (hr *HashRing) New(nodes []string) {
    	if nodes == nil {
    		return
    	}
    	hr.Nodes = make(map[uint32]string)
    	hr.Keys = SortKeys{}
    	for _, node := range nodes {
    		// 每个节点生成 DEFAULT_REPLICAS 个虚拟节点
    		for i := 0; i < DEFAULT_REPLICAS; i++ {
    			str := node + strconv.Itoa(i)
    			// Hash 通过 node 虚拟节点名称生成哈希值,该Hash值指向对应 node 节点
    			hr.Nodes[hr.Hash(str)] = node
    			// 将哈希值保存在key列表中
    			hr.Keys = append(hr.Keys, hr.Hash(str))
    		}
    	}
    	// 对 Hash 值进行排序,后面计算的 Hash 值与 Keys 进行比较,取大于等于计算所得的Hash值所对应的node节点
    	sort.Sort(hr.Keys)
    }
    // Hash 根据Key计算Hash值
    func (hr *HashRing) Hash(key string) uint32 {
    	return crc32.ChecksumIEEE([]byte(key))
    }
    
    展开全文
  • Spark资源调优

    千次阅读 2017-12-23 13:24:32
    0. 概述 在开发完Spark作业之后,就该为作业配置合适的资源了。...资源参数设置的不合理,可能会导致没有充分利用集群资源,作业运行会极其缓慢;或者设置的资源过大,队列没有足够的资源来提供,进而导致各种异常。总

    0. 概述

      在开发完Spark作业之后,就该为作业配置合适的资源了。Spark的资源参数,基本都可以在spark-submit命令中作为参数设置。很多Spark初学者,通常不知道该设置哪些必要的参数,以及如何设置这些参数,最后就只能胡乱设置,甚至压根儿不设置。资源参数设置的不合理,可能会导致没有充分利用集群资源,作业运行会极其缓慢;或者设置的资源过大,队列没有足够的资源来提供,进而导致各种异常。总之,无论是哪种情况,都会导致Spark作业的运行效率低下,甚至根本无法运行。因此我们必须对Spark作业的资源使用原理有一个清晰的认识,并知道在Spark作业运行过程中,有哪些资源参数是可以设置的,以及如何设置合适的参数值。

    1. Spark作业基本运行原理

      详细原理见上图。我们使用spark-submit提交一个Spark作业之后,这个作业就会启动一个对应的Driver进程。根据你使用的部署模式(deploy-mode)不同,Driver进程可能在本地启动,也可能在集群中某个工作节点上启动。Driver进程本身会根据我们设置的参数,占有一定数量的内存和CPU core。而Driver进程要做的第一件事情,就是向集群管理器(可以是Spark Standalone集群,也可以是其他的资源管理集群,美团•大众点评使用的是YARN作为资源管理集群)申请运行Spark作业需要使用的资源,这里的资源指的就是Executor进程。YARN集群管理器会根据我们为Spark作业设置的资源参数,在各个工作节点上,启动一定数量的Executor进程,每个Executor进程都占有一定数量的内存和CPU core。

      在申请到了作业执行所需的资源之后,Driver进程就会开始调度和执行我们编写的作业代码了。Driver进程会将我们编写的Spark作业代码分拆为多个stage,每个stage执行一部分代码片段,并为每个stage创建一批task,然后将这些task分配到各个Executor进程中执行。task是最小的计算单元,负责执行一模一样的计算逻辑(也就是我们自己编写的某个代码片段),只是每个task处理的数据不同而已。一个stage的所有task都执行完毕之后,会在各个节点本地的磁盘文件中写入计算中间结果,然后Driver就会调度运行下一个stage。下一个stage的task的输入数据就是上一个stage输出的中间结果。如此循环往复,直到将我们自己编写的代码逻辑全部执行完,并且计算完所有的数据,得到我们想要的结果为止。

      Spark是根据shuffle类算子来进行stage的划分。如果我们的代码中执行了某个shuffle类算子(比如reduceByKey、join等),那么就会在该算子处,划分出一个stage界限来。可以大致理解为,shuffle算子执行之前的代码会被划分为一个stage,shuffle算子执行以及之后的代码会被划分为下一个stage。因此一个stage刚开始执行的时候,它的每个task可能都会从上一个stage的task所在的节点,去通过网络传输拉取需要自己处理的所有key,然后对拉取到的所有相同的key使用我们自己编写的算子函数执行聚合操作(比如reduceByKey()算子接收的函数)。这个过程就是shuffle。

      当我们在代码中执行了cache/persist等持久化操作时,根据我们选择的持久化级别的不同,每个task计算出来的数据也会保存到Executor进程的内存或者所在节点的磁盘文件中。

      因此Executor的内存主要分为三块:第一块是让task执行我们自己编写的代码时使用,默认是占Executor总内存的20%;第二块是让task通过shuffle过程拉取了上一个stage的task的输出后,进行聚合等操作时使用,默认也是占Executor总内存的20%;第三块是让RDD持久化时使用,默认占Executor总内存的60%。

      task的执行速度是跟每个Executor进程的CPU core数量有直接关系的。一个CPU core同一时间只能执行一个线程。而每个Executor进程上分配到的多个task,都是以每个task一条线程的方式,多线程并发运行的。如果CPU core数量比较充足,而且分配到的task数量比较合理,那么通常来说,可以比较快速和高效地执行完这些task线程。

      以上就是Spark作业的基本运行原理的说明,大家可以结合上图来理解。理解作业基本原理,是我们进行资源参数调优的基本前提。

    2. 资源参数调优

      了解完了Spark作业运行的基本原理之后,对资源相关的参数就容易理解了。所谓的Spark资源参数调优,其实主要就是对Spark运行过程中各个使用资源的地方,通过调节各种参数,来优化资源使用的效率,从而提升Spark作业的执行性能。以下参数就是Spark中主要的资源参数,每个参数都对应着作业运行原理中的某个部分,我们同时也给出了一个调优的参考值。

    2.1 num-executors

    • 参数说明:该参数用于设置Spark作业总共要用多少个Executor进程来执行。Driver在向YARN集群管理器申请资源时,YARN集群管理器会尽可能按照你的设置来在集群的各个工作节点上,启动相应数量的Executor进程。这个参数非常之重要,如果不设置的话,默认只会给你启动少量的Executor进程,此时你的Spark作业的运行速度是非常慢的。

    • 调优建议:每个Spark作业的运行一般设置50~100个左右的Executor进程比较合适,设置太少或太多的Executor进程都不好。设置的太少,无法充分利用集群资源;设置的太多的话,大部分队列可能无法给予充分的资源。

    2.2 executor-memory

    • 参数说明:该参数用于设置每个Executor进程的内存。Executor内存的大小,很多时候直接决定了Spark作业的性能,而且跟常见的JVM OOM异常,也有直接的关联。

    • 调优建议:每个Executor进程的内存设置4G~8G较为合适。但是这只是一个参考值,具体的设置还是得根据不同部门的资源队列来定。可以看看自己团队的资源队列的最大内存限制是多少,num-executors乘以executor-memory,是不能超过队列的最大内存量的。此外,如果你是跟团队里其他人共享这个资源队列,那么申请的内存量最好不要超过资源队列最大总内存的1/3~1/2,避免你自己的Spark作业占用了队列所有的资源,导致别的同学的作业无法运行。

    2.3 executor-cores

    • 参数说明:该参数用于设置每个Executor进程的CPU core数量。这个参数决定了每个Executor进程并行执行task线程的能力。因为每个CPU core同一时间只能执行一个task线程,因此每个Executor进程的CPU core数量越多,越能够快速地执行完分配给自己的所有task线程。

    • 调优建议:Executor的CPU core数量设置为2~4个较为合适。同样得根据不同部门的资源队列来定,可以看看自己的资源队列的最大CPU core限制是多少,再依据设置的Executor数量,来决定每个Executor进程可以分配到几个CPU core。同样建议,如果是跟他人共享这个队列,那么num-executors * executor-cores不要超过队列总CPU core的1/3~1/2左右比较合适,也是避免影响其他同学的作业运行。

    2.4 driver-memory

    • 参数说明:该参数用于设置Driver进程的内存。

    • 调优建议:Driver的内存通常来说不设置,或者设置1G左右应该就够了。唯一需要注意的一点是,如果需要使用collect算子将RDD的数据全部拉取到Driver上进行处理,那么必须确保Driver的内存足够大,否则会出现OOM内存溢出的问题。

    2.5 spark.default.parallelism

    • 参数说明:该参数用于设置每个stage的默认task数量。这个参数极为重要,如果不设置可能会直接影响你的Spark作业性能。

    • 调优建议:Spark作业的默认task数量为500~1000个较为合适。很多同学常犯的一个错误就是不去设置这个参数,那么此时就会导致Spark自己根据底层HDFS的block数量来设置task的数量,默认是一个HDFS block对应一个task。通常来说,Spark默认设置的数量是偏少的(比如就几十个task),如果task数量偏少的话,就会导致你前面设置好的Executor的参数都前功尽弃。试想一下,无论你的Executor进程有多少个,内存和CPU有多大,但是task只有1个或者10个,那么90%的Executor进程可能根本就没有task执行,也就是白白浪费了资源!因此Spark官网建议的设置原则是,设置该参数为num-executors * executor-cores的2~3倍较为合适,比如Executor的总CPU core数量为300个,那么设置1000个task是可以的,此时可以充分地利用Spark集群的资源。

    2.6 spark.storage.memoryFraction

    • 参数说明:该参数用于设置RDD持久化数据在Executor内存中能占的比例,默认是0.6。也就是说,默认Executor 60%的内存,可以用来保存持久化的RDD数据。根据你选择的不同的持久化策略,如果内存不够时,可能数据就不会持久化,或者数据会写入磁盘。

    • 调优建议:如果Spark作业中,有较多的RDD持久化操作,该参数的值可以适当提高一些,保证持久化的数据能够容纳在内存中。避免内存不够缓存所有的数据,导致数据只能写入磁盘中,降低了性能。但是如果Spark作业中的shuffle类操作比较多,而持久化操作比较少,那么这个参数的值适当降低一些比较合适。此外,如果发现作业由于频繁的gc导致运行缓慢(通过spark web ui可以观察到作业的gc耗时),意味着task执行用户代码的内存不够用,那么同样建议调低这个参数的值。

    2.7 spark.shuffle.memoryFraction

    • 参数说明:该参数用于设置shuffle过程中一个task拉取到上个stage的task的输出后,进行聚合操作时能够使用的Executor内存的比例,默认是0.2。也就是说,Executor默认只有20%的内存用来进行该操作。shuffle操作在进行聚合时,如果发现使用的内存超出了这个20%的限制,那么多余的数据就会溢写到磁盘文件中去,此时就会极大地降低性能。

    • 调优建议:如果Spark作业中的RDD持久化操作较少,shuffle操作较多时,建议降低持久化操作的内存占比,提高shuffle操作的内存占比比例,避免shuffle过程中数据过多时内存不够用,必须溢写到磁盘上,降低了性能。此外,如果发现作业由于频繁的gc导致运行缓慢,意味着task执行用户代码的内存不够用,那么同样建议调低这个参数的值。

    资源参数的调优,没有一个固定的值,需要同学们根据自己的实际情况(包括Spark作业中的shuffle操作数量、RDD持久化操作数量以及spark web ui中显示的作业gc情况),同时参考本篇文章中给出的原理以及调优建议,合理地设置上述参数。

    3. 资源参数参考示例

      以下是一份spark-submit命令的示例,大家可以参考一下,并根据自己的实际情况进行调节:

    ./bin/spark-submit \
      --master yarn-cluster \
      --num-executors 100 \
      --executor-memory 6G \
      --executor-cores 4 \
      --driver-memory 1G \
      --conf spark.default.parallelism=1000 \
      --conf spark.storage.memoryFraction=0.5 \
      --conf spark.shuffle.memoryFraction=0.3 \



    对机器学习和人工智能感兴趣,请扫码关注微信公众号!
    这里写图片描述

    展开全文
  • 科学的环境保护管理要有健全的环境保护法律法规作支撑,有法可依,同时发挥煤企资源与环境保护管理的能动性,力求最大程度降低煤炭开采给地区生态环境造成的污染和破坏影响,合理开发利用煤炭资源,促进社会经济与环境...
  • 资源参数设置的不合理,可能会导致没有充分利用集群资源,作业运行会极其缓慢;或者设置的资源过大,队列没有足够的资源来提供,进而导致各种异常。总之,无论是哪种情况,都会导致Spark作业的运行效率低下,甚至...
  • Spark资源调优篇

    2020-11-24 20:23:48
    资源参数设置的不合理,可能会导致没有充分利用集群资源,作业运行会极其缓慢;或者设置的资源过大,队列没有足够的资源来提供,进而导致各种异常。总之,无论是哪种情况,都会导致Spark作业的运行效率低下,甚至...

    在开发完Spark作业之后,就该为作业配置合适的资源了。Spark的资源参数,基本都可以在spark-submit命令中作为参数设置。很多Spark初学者,通常不知道该设置哪些必要的参数,以及如何设置这些参数,最后就只能胡乱设置,甚至压根儿不设置。资源参数设置的不合理,可能会导致没有充分利用集群资源,作业运行会极其缓慢;或者设置的资源过大,队列没有足够的资源来提供,进而导致各种异常。总之,无论是哪种情况,都会导致Spark作业的运行效率低下,甚至根本无法运行。因此我们必须对Spark作业的资源使用原理有一个清晰的认识,并知道在Spark作业运行过程中,有哪些资源参数是可以设置的,以及如何设置合适的参数值。

    1、Spark作业基本运行原理

    在这里插入图片描述

      详细原理见上图。我们使用spark-submit提交一个Spark作业之后,这个作业就会启动一个对应的Driver进程。根据你使用的部署模式(deploy-mode)不同,Driver进程可能在本地启动,也可能在集群中某个工作节点上启动。Driver进程本身会根据我们设置的参数,占有一定数量的内存和CPU core。而Driver进程要做的第一件事情,就是向集群管理器(可以是Spark Standalone集群,也可以是其他的资源管理集群,美团•大众点评使用的是YARN作为资源管理集群)申请运行Spark作业需要使用的资源,这里的资源指的就是Executor进程。YARN集群管理器会根据我们为Spark作业设置的资源参数,在各个工作节点上,启动一定数量的Executor进程,每个Executor进程都占有一定数量的内存和CPU core。
    

    在申请到了作业执行所需的资源之后,Driver进程就会开始调度和执行我们编写的作业代码了。Driver进程会将我们编写的Spark作业代码分拆为多个stage,每个stage执行一部分代码片段,并为每个stage创建一批task,然后将这些task分配到各个Executor进程中执行。task是最小的计算单元,负责执行一模一样的计算逻辑(也就是我们自己编写的某个代码片段),只是每个task处理的数据不同而已。一个stage的所有task都执行完毕之后,会在各个节点本地的磁盘文件中写入计算中间结果,然后Driver就会调度运行下一个stage。下一个stage的task的输入数据就是上一个stage输出的中间结果。如此循环往复,直到将我们自己编写的代码逻辑全部执行完,并且计算完所有的数据,得到我们想要的结果为止。

    Spark是根据shuffle类算子来进行stage的划分。如果我们的代码中执行了某个shuffle类算子(比如reduceByKey、join等),那么就会在该算子处,划分出一个stage界限来。可以大致理解为,shuffle算子执行之前的代码会被划分为一个stage,shuffle算子执行以及之后的代码会被划分为下一个stage。因此一个stage刚开始执行的时候,它的每个task可能都会从上一个stage的task所在的节点,去通过网络传输拉取需要自己处理的所有key,然后对拉取到的所有相同的key使用我们自己编写的算子函数执行聚合操作(比如reduceByKey()算子接收的函数)。这个过程就是shuffle。

    当我们在代码中执行了cache/persist等持久化操作时,根据我们选择的持久化级别的不同,每个task计算出来的数据也会保存到Executor进程的内存或者所在节点的磁盘文件中。

    因此Executor的内存主要分为三块:第一块是让task执行我们自己编写的代码时使用,默认是占Executor总内存的20%;第二块是让task通过shuffle过程拉取了上一个stage的task的输出后,进行聚合等操作时使用,默认也是占Executor总内存的20%;第三块是让RDD持久化时使用,默认占Executor总内存的60%。

    task的执行速度是跟每个Executor进程的CPU core数量有直接关系的。一个CPU core同一时间只能执行一个线程。而每个Executor进程上分配到的多个task,都是以每个task一条线程的方式,多线程并发运行的。如果CPU core数量比较充足,而且分配到的task数量比较合理,那么通常来说,可以比较快速和高效地执行完这些task线程。

    以上就是Spark作业的基本运行原理的说明,大家可以结合上图来理解。理解作业基本原理,是我们进行资源参数调优的基本前提。
    2、资源参数调优

      了解完了Spark作业运行的基本原理之后,对资源相关的参数就容易理解了。所谓的Spark资源参数调优,其实主要就是对Spark运行过程中各个使用资源的地方,通过调节各种参数,来优化资源使用的效率,从而提升Spark作业的执行性能。以下参数就是Spark中主要的资源参数,每个参数都对应着作业运行原理中的某个部分,我们同时也给出了一个调优的参考值。
    

    num-executors

    参数说明:该参数用于设置Spark作业总共要用多少个Executor进程来执行。Driver在向YARN集群管理器申请资源时,YARN集群管理器会尽可能按照你的设置来在集群的各个工作节点上,启动相应数量的Executor进程。这个参数非常之重要,如果不设置的话,默认只会给你启动少量的Executor进程,此时你的Spark作业的运行速度是非常慢的。

    参数调优建议:每个Spark作业的运行一般设置50~100个左右的Executor进程比较合适,设置太少或太多的Executor进程都不好。设置的太少,无法充分利用集群资源;设置的太多的话,大部分队列可能无法给予充分的资源。
    executor-memory

    参数说明:该参数用于设置每个Executor进程的内存。Executor内存的大小,很多时候直接决定了Spark作业的性能,而且跟常见的JVM OOM异常,也有直接的关联。

    参数调优建议:每个Executor进程的内存设置4G8G较为合适。但是这只是一个参考值,具体的设置还是得根据不同部门的资源队列来定。可以看看自己团队的资源队列的最大内存限制是多少,num-executors乘以executor-memory,就代表了你的Spark作业申请到的总内存量(也就是所有Executor进程的内存总和),这个量是不能超过队列的最大内存量的。此外,如果你是跟团队里其他人共享这个资源队列,那么申请的总内存量最好不要超过资源队列最大总内存的1/31/2,避免你自己的Spark作业占用了队列所有的资源,导致别的同学的作业无法运行。
    executor-cores

    参数说明:该参数用于设置每个Executor进程的CPU core数量。这个参数决定了每个Executor进程并行执行task线程的能力。因为每个CPU core同一时间只能执行一个task线程,因此每个Executor进程的CPU core数量越多,越能够快速地执行完分配给自己的所有task线程。

    参数调优建议:Executor的CPU core数量设置为2~4个较为合适。同样得根据不同部门的资源队列来定,可以看看自己的资源队列的最大CPU core限制是多少,再依据设置的Executor数量,来决定每个Executor进程可以分配到几个CPU core。同样建议,如果是跟他人共享这个队列,那么num-executors * executor-cores不要超过队列总CPU core的1/3~1/2左右比较合适,也是避免影响其他同学的作业运行。
    driver-memory

    参数说明:该参数用于设置Driver进程的内存。

    参数调优建议:Driver的内存通常来说不设置,或者设置1G左右应该就够了。唯一需要注意的一点是,如果需要使用collect算子将RDD的数据全部拉取到Driver上进行处理,那么必须确保Driver的内存足够大,否则会出现OOM内存溢出的问题。
    spark.default.parallelism

    参数说明:该参数用于设置每个stage的默认task数量。这个参数极为重要,如果不设置可能会直接影响你的Spark作业性能。

    参数调优建议:Spark作业的默认task数量为500~1000个较为合适。很多同学常犯的一个错误就是不去设置这个参数,那么此时就会导致Spark自己根据底层HDFS的block数量来设置task的数量,默认是一个HDFS block对应一个task。通常来说,Spark默认设置的数量是偏少的(比如就几十个task),如果task数量偏少的话,就会导致你前面设置好的Executor的参数都前功尽弃。试想一下,无论你的Executor进程有多少个,内存和CPU有多大,但是task只有1个或者10个,那么90%的Executor进程可能根本就没有task执行,也就是白白浪费了资源!因此Spark官网建议的设置原则是,设置该参数为num-executors * executor-cores的2~3倍较为合适,比如Executor的总CPU core数量为300个,那么设置1000个task是可以的,此时可以充分地利用Spark集群的资源。
    spark.storage.memoryFraction

    参数说明:该参数用于设置RDD持久化数据在Executor内存中能占的比例,默认是0.6。也就是说,默认Executor 60%的内存,可以用来保存持久化的RDD数据。根据你选择的不同的持久化策略,如果内存不够时,可能数据就不会持久化,或者数据会写入磁盘。

    参数调优建议:如果Spark作业中,有较多的RDD持久化操作,该参数的值可以适当提高一些,保证持久化的数据能够容纳在内存中。避免内存不够缓存所有的数据,导致数据只能写入磁盘中,降低了性能。但是如果Spark作业中的shuffle类操作比较多,而持久化操作比较少,那么这个参数的值适当降低一些比较合适。此外,如果发现作业由于频繁的gc导致运行缓慢(通过spark web ui可以观察到作业的gc耗时),意味着task执行用户代码的内存不够用,那么同样建议调低这个参数的值。
    spark.shuffle.memoryFraction

    参数说明:该参数用于设置shuffle过程中一个task拉取到上个stage的task的输出后,进行聚合操作时能够使用的Executor内存的比例,默认是0.2。也就是说,Executor默认只有20%的内存用来进行该操作。shuffle操作在进行聚合时,如果发现使用的内存超出了这个20%的限制,那么多余的数据就会溢写到磁盘文件中去,此时就会极大地降低性能。

    参数调优建议:如果Spark作业中的RDD持久化操作较少,shuffle操作较多时,建议降低持久化操作的内存占比,提高shuffle操作的内存占比比例,避免shuffle过程中数据过多时内存不够用,必须溢写到磁盘上,降低了性能。此外,如果发现作业由于频繁的gc导致运行缓慢,意味着task执行用户代码的内存不够用,那么同样建议调低这个参数的值。
    资源参数的调优,没有一个固定的值,需要同学们根据自己的实际情况(包括Spark作业中的shuffle操作数量、RDD持久化操作数量以及spark web ui中显示的作业gc情况),同时参考本篇文章中给出的原理以及调优建议,合理地设置上述参数。
    3、资源参数参考示例

      以下是一份spark-submit命令的示例,大家可以参考一下,并根据自己的实际情况进行调节:
    
    ./bin/spark-submit \
      --master yarn-cluster \
      --num-executors 100 \
      --executor-memory 6G \
      --executor-cores 4 \
      --driver-memory 1G \
      --conf spark.default.parallelism=1000 \
      --conf spark.storage.memoryFraction=0.5 \
      --conf spark.shuffle.memoryFraction=0.3 \
    
    展开全文
  • Spark-资源调优

    2020-06-17 19:40:51
    资源参数设置的不合理,可能会导致没有充分利用集群资源,作业运行会极其缓慢;或者设置的资源过大,队列没有足够的资源来提供,进而导致各种异常。总之,无论是哪种情况,都会导致Spark作业的运行效率低下,甚至...
  • 随着人们环保意识的提高,如何处理处置制药行业产生的废菌渣,实现废菌渣的无害化、资源化成为亟待解决的难题。对青霉素、土霉素菌渣的研究利用现状进行了总结,现有研究利用情况均存在一定的问题,需进一步研究开发新的...
  • 近年来,国家土地资源遭受违法滥用现象突出,各种土地合理利用问题日益显现,土地利用不当,导致各类地质灾害不断加剧,良田受损,森林资源遭到乱砍滥伐,煤矿开采不合理、各种城市开发区非法建筑等,都对国家的每一...
  • Spark调优之资源调优

    2017-06-13 09:46:02
    开发完Spark作业之后,就该为作业配置合适的资源...资源参数设置的不合理,可能会导致没有充分利用集群资源,作业运行会极其缓慢;或者设置的资源过大,队列没有足够的资源来提供,进而导致各种异常。总之,无论是哪
  • 开发完Spark作业之后,就该为作业配置合适的资源...资源参数设置的不合理,可能会导致没有充分利用集群资源,作业运行会极其缓慢;或者设置的资源过大,队列没有足够的资源来提供,进而导致各种异常。总之,无论是哪
  • 在项目开发过程中项目开发文档13种

    热门讨论 2010-10-30 10:44:13
     ◇ 项目开发总结报告:软件项目开发完成以后,应与项目实施计划对照,总结实际执行的情况,如进度、成果、资源利用、成本和投入的人力,此外,还需对开发工作做出评价,总结出经验和教训。  ◇ 软件维护手册:...
  • 开发完Spark作业之后,就该为作业配置合适的...资源参数设置的不合理,可能会导致没有充分利用集群资源,作业运行会极其缓慢;或者设置的资源过大,队列没有足够的资源来提供,进而导致各种异常。总之,无论是哪...
  • 受多煤层赋存条件和煤矿井下回采工艺影响,采空区内的大量遗煤导致废弃矿井或老采空区内赋存丰富煤层气资源,对这一资源的准确评估、合理开发和高效利用是我国进行非常规油气资源开发的重大需求,如何准确评估废弃矿井...
  • 软件开发文档范例

    热门讨论 2015-03-16 14:34:25
    如进度、成果、资源利用、成本和投入的人力,此外,还需对开发工作做出评价, 总结出经验和教训。  11.◇ 软件维护手册:  主要包括软件系统说明、程序模块说明、操作环境、支持软件的说明、维护 过程的说明...
  • 开发完Spark作业之后,就该为作业配置合适的资源...资源参数设置的不合理,可能会导致没有充分利用集群资源,作业运行会极其缓慢;或者设置的资源过大,队列没有足够的资源来提供,进而导致各种异常。总之,无论是哪
  • 转载: 在开发完Spark作业之后,就该为作业配置合适的资源了。...设置的不合理,可能会导致没有充分利用集群资源,作业运行会极其缓慢;或者设置的资源过大,队列没有足够的资源来提供,进 而导致各...
  • **Android高级应用开发第二章---屏幕适配** 一.什么是屏幕适配 ...屏幕适配通过对尺寸、图片、文字、布局这四种类型的资源进行合理设计和规划,在布局时合理利用各种类型资源,让布局拥有适应能力,能在...
  • Spark性能调优-资源

    2016-08-10 11:29:31
    开发完Spark作业之后,就该为作业配置合适的资源...资源参数设置的不合理,可能会导致没有充分利用集群资源,作业运行会极其缓慢;或者设置的资源过大,队列没有足够的资源来提供,进而导致各种异常。总之,无论是哪

空空如也

空空如也

1 2 3 4 5 ... 13
收藏数 248
精华内容 99
关键字:

如何合理开发利用资源