QueryPlanningTracker.scala

写在前面:Spark2.1.2 SparkSQL执行过程中涉及的类;后续手撕Spark2.2.0源码.

/**
*一个简单的实用工具,用于跟踪查询规划中的运行时和相关统计信息
*我们追踪两个不同的概念:
*1阶段:这些是查询规划中的大范围阶段,如下所示,即分析、优化和物理规划(仅规划)。
*2规则:这些是我们跟踪的单个催化剂规则。除了时间,我们还跟踪调用的数量和有效调用。
*/

伴生对象:

object QueryPlanningTracker {

  val PARSING = "parsing"
  val ANALYSIS = "analysis"
  val OPTIMIZATION = "optimization"
  val PLANNING = "planning"

  //规则摘要类
  class RuleSummary(
    var totalTimeNs: Long, //在此规则中所花费的总时间(以纳米秒为单位)
    var numInvocations: Long, //调用规则的次数
    var numEffectiveInvocations: Long //调用规则并导致计划更改的次数。
  ) {

    def this() = this(totalTimeNs = 0, numInvocations = 0, numEffectiveInvocations = 0)

    override def toString: String = {
      s"RuleSummary($totalTimeNs, $numInvocations, $numEffectiveInvocations)"
    }
  }

  //阶段摘要类: 包含开始时间和结束时间,以便我们可以构建一个时间轴。
  class PhaseSummary(val startTimeMs: Long, val endTimeMs: Long) {

    def durationMs: Long = endTimeMs - startTimeMs

    override def toString: String = {
      s"PhaseSummary($startTimeMs, $endTimeMs)"
    }
  }

  //一个线程局部变量,隐式地传递跟踪器。
  //这假设查询规划器是单线程的,并避免在每个函数调用中传递相同的跟踪程序上下文。
  private val localTracker = new ThreadLocal[QueryPlanningTracker]() {
    override def initialValue: QueryPlanningTracker = null
  }

  //根据线程局部变量 返回 作用域中的当前跟踪程序
  def get: Option[QueryPlanningTracker] = Option(localTracker.get())

  //为函数f的执行设置当前跟踪器。我们假设f是单线程的。
  def withTracker[T](tracker: QueryPlanningTracker)(f: => T): T = {
    //得到当前线程的局部变量
    val originalTracker = localTracker.get()
    //设置当前线程绑定tracker变量
    localTracker.set(tracker)
    //运行f函数,设置当前线程绑定原来的变量
    try f finally { localTracker.set(originalTracker) }
  }
}

伴生类

class QueryPlanningTracker {

  import QueryPlanningTracker._

  //从规则的名称映射到规则的摘要。使用Java HashMap可以减少开销。
  private val rulesMap = new java.util.HashMap[String, RuleSummary]

  //从一个阶段到它的开始时间和结束时间,单位为ms
  private val phasesMap = new java.util.HashMap[String, PhaseSummary]

  //测量一个阶段的开始和结束时间。
  //请注意,如果在同一阶段多次调用此函数,则记录的开始时间将是第一次调用的开始时间,
  //记录的结束时间将是最后一次调用的结束时间。    
  def measurePhase[T](phase: String)(f: => T): T = {
    //这三个参数获取当前的执行时间
    val startTime = System.currentTimeMillis()
    val ret = f
    val endTime = System.currentTimeMillis

    //判断是否是第一次调用这个方法,如果是就创建新的Phase,并赋值以前的初始时间,当前的结束时间,并将其put到phasesMap中
    //否则创建一个新的Phase,并赋值当前启动和结束时间,将其put到phaseMap中
    if (phasesMap.containsKey(phase)) {
      val oldSummary = phasesMap.get(phase)
      phasesMap.put(phase, new PhaseSummary(oldSummary.startTimeMs, endTime))
    } else {
      phasesMap.put(phase, new PhaseSummary(startTime, endTime))
    }
    ret
  }

  //记录规则的特定调用
  def recordRuleInvocation(rule: String, //规则名称
                           timeNs: Long, //运行此调用所需时间
                           effective: Boolean //调用是否导致计划更改
                          ): Unit = {
    //判断rule是否被rulesMap记录,如果没有记录,就记录下来
    var s = rulesMap.get(rule)
    if (s eq null) {
      s = new RuleSummary
      rulesMap.put(rule, s)
    }
	//记录规则所花费的总时间,调用次数,调用规则导致计划变更次数
    s.totalTimeNs += timeNs
    s.numInvocations += 1
    s.numEffectiveInvocations += (if (effective) 1 else 0)
  }

  // ------------ reporting functions below ------------

  //将java类型转换为scala类型
  def rules: Map[String, RuleSummary] = rulesMap.asScala.toMap

  def phases: Map[String, PhaseSummary] = phasesMap.asScala.toMap

  //返回前k个最昂贵的规则(按时间度量)。
  //如果k大于目前看到的规则,则返回所有规则。如果到目前为止没有看到规则或k<=0,则返回空seq
  def topRulesByTime(k: Int): Seq[(String, RuleSummary)] = {
    if (k <= 0) {
      Seq.empty
    } else {
 		//取元组中的第二个元素的totalTimeNs,作为排序规则
      val orderingByTime: Ordering[(String, RuleSummary)] = Ordering.by(e => e._2.totalTimeNs)
      //第一个参数是取前k个,第二个参数是隐式排序规则,即上面定义的
      val q = new BoundedPriorityQueue(k)(orderingByTime)
          
      //调用BoundedPriorityQueue中的+=函数
      rulesMap.asScala.foreach(q.+=)
          
      //疑问:这里的-r是什么意思?
      q.toSeq.sortBy(r => -r._2.totalTimeNs)
    }
  }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Exception in thread "main" java.lang.RuntimeException: java.lang.NoSuchFieldException: DEFAULT_TINY_CACHE_SIZE at org.apache.spark.network.util.NettyUtils.getPrivateStaticField(NettyUtils.java:131) at org.apache.spark.network.util.NettyUtils.createPooledByteBufAllocator(NettyUtils.java:118) at org.apache.spark.network.server.TransportServer.init(TransportServer.java:95) at org.apache.spark.network.server.TransportServer.<init>(TransportServer.java:74) at org.apache.spark.network.TransportContext.createServer(TransportContext.java:114) at org.apache.spark.rpc.netty.NettyRpcEnv.startServer(NettyRpcEnv.scala:118) at org.apache.spark.rpc.netty.NettyRpcEnvFactory$$anonfun$4.apply(NettyRpcEnv.scala:454) at org.apache.spark.rpc.netty.NettyRpcEnvFactory$$anonfun$4.apply(NettyRpcEnv.scala:453) at org.apache.spark.util.Utils$$anonfun$startServiceOnPort$1.apply$mcVI$sp(Utils.scala:2237) at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:160) at org.apache.spark.util.Utils$.startServiceOnPort(Utils.scala:2229) at org.apache.spark.rpc.netty.NettyRpcEnvFactory.create(NettyRpcEnv.scala:458) at org.apache.spark.rpc.RpcEnv$.create(RpcEnv.scala:56) at org.apache.spark.SparkEnv$.create(SparkEnv.scala:246) at org.apache.spark.SparkEnv$.createDriverEnv(SparkEnv.scala:175) at org.apache.spark.SparkContext.createSparkEnv(SparkContext.scala:257) at org.apache.spark.SparkContext.<init>(SparkContext.scala:432) at org.apache.spark.SparkContext$.getOrCreate(SparkContext.scala:2509) at org.apache.spark.sql.SparkSession$Builder$$anonfun$6.apply(SparkSession.scala:909) at org.apache.spark.sql.SparkSession$Builder$$anonfun$6.apply(SparkSession.scala:901) at scala.Option.getOrElse(Option.scala:121) at org.apache.spark.sql.SparkSession$Builder.getOrCreate(SparkSession.scala:901) at com.cssl.scala720.KafkaSparkStreamingHBase$.main(KafkaSparkStreamingHBase.scala:28) at com.cssl.scala720.KafkaSparkStreamingHBase.main(KafkaSparkStreamingHBase.scala) Caused by: java.lang.NoSuchFieldException: DEFAULT_TINY_CACHE_SIZE at java.lang.Class.getDeclaredField(Class.java:2070) at org.apache.spark.network.util.NettyUtils.getPrivateStaticField(NettyUtils.java:127) ... 23 more Process finished with exit code 1
07-24

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值