spark使用多线程并行多个独立job,job中Accumulator的最终结果

1.问题:

spark中使用多线程并行执行多个独立的job,每个线程中分别在foreachPartition算子中使用累加器LongAccumulator。众所周知,累加器是在每个excutor中改变值然后在driver中汇总得到最终累加器的值。问题来了,返回到driver中累加器的结果,是每个线程执行结果累加的值,还是所有线程执行完后结果累加,也可以理解为多个累加器的结果在driver中是独立的,还是多个累加器结果累加?

2、结论:

diver中,多个累加器的结果是分别独立的,而不是把所有累加器的结果累加汇总,多线程中累加器是独立的。

3、测试:

下面使用项目中的代码片段说明:

3.1 多线程代码片段:每个线程调用distribution(tableName, p, prop, spark, brandinfoBro)方法

 val countDownLatch = new CountDownLatch(passengerDatabases.length)
      passengerDatabases.foreach(p => {
        val runnable: Runnable = new Runnable {
          override def run(): Unit = {
            try {
                distribution(tableName, p, prop, spark, brandinfoBro)
            } catch {
              case e: Exception => {
              }
            } finally {
              countDownLatch.countDown();
            }
          }
        }
        pool.execute(runnable)
      })
      //等待全部表执行结束
      countDownLatch.await(10, TimeUnit.MINUTES);
    }
    pool.shutdown()
spark.close()

 3.2 distribution(tableName, p, prop, spark, brandinfoBro)方法中代码片段:

定义累加器,再调用distributionToMysql方法,在其中改变累加器的值,通过查看下面日志推测结果

 val errorCount: LongAccumulator = spark.sparkContext.longAccumulator("errorCount")
      println(s"${dateUtils.currentTime()} 表:${tableName} 分发到${p.id}_${p.branchId}_${p.source_name} 数据库,${errorCount}累加器初始值:${errorCount.count}")
        distributionToMysql(p, finalDF, tableName, prop, errorCount)
      println(s"${dateUtils.currentTime()} 表:${tableName} 分发到${p.id}_${p.branchId}_${p.source_name} 数据库,${errorCount}累加器最终值:${errorCount.count}")

3.3 distributionToMysql(p, finalDF, tableName, prop, errorCount)方法中代码片段:

foreachPartition中操作如果发生错误则累加器值加1,errorCount.add(1)。测试时手动修改代码使其报错。

    updateDF.foreachPartition(split => {
      try {
        Class.forName(p.driver_class)
        conn = ConnectUtils.getConnection2(p.user_name, p.user_pass, p.jdbc_url)
          insertPstmt = conn.prepareStatement(insertSql)
          updatePstmt = conn.prepareStatement(updateSql)
          selectPstmt = conn.prepareStatement(selectSql)
          split.foreach(x => {
              updatePstmt = setPrepareStatement(updatePstmt, x, columnTypes)
              updatePstmt.setObject(columnTypes.length + 1, x.getAs(uniqueKey), Types.INTEGER)
              //更新行数
              val updateNum: Int = updatePstmt.executeUpdate()
 
          })
        }
      } catch {
        case e: Exception => {
          logger.error(s"${dateUtils.currentTime()} 表:${tableName} 分发到 ${p.id}_${p.branchId}_${p.source_name}  数据库失败,原因:", e)
          errorCount.add(1)
        }
      } finally {
        ConnectUtils.close(conn, updatePstmt)
        ConnectUtils.close(conn, selectPstmt)
        ConnectUtils.close(conn, insertPstmt)
      }
    })

3.4 通过查看累加器数值的日志得到结论:

2022-07-22 10:01:20 表:plazainfo 分发到157_420_杭州富阳 数据库,LongAccumulator(id: 406, name: Some(errorCount), value: 0)累加器初始值:0
2022-07-22 10:01:21 表:plazainfo 分发到157_420_杭州富阳 数据库,LongAccumulator(id: 406, name: Some(errorCount), value: 1)累加器最终值:1
2022-07-22 10:01:21 表:plazainfo 分发到13_181_北京丰科 数据库,LongAccumulator(id: 216, name: Some(errorCount), value: 1)累加器最终值:1
2022-07-22 10:01:21 表:plazainfo 分发到422_459_咸阳秦都 数据库,LongAccumulator(id: 436, name: Some(errorCount), value: 0)累加器初始值:0
2022-07-22 10:01:23 表:plazainfo 分发到422_459_咸阳秦都 数据库,LongAccumulator(id: 436, name: Some(errorCount), value: 1)累加器最终值:1

发现每个线程的累加器初始值是1,最终值是1,并没有将结果值全部汇总到driver端累加为3.

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值