我正在通过扩展SparkListener类来实现SparkHealthListener。
@Component
class ClusterHealthListener extends SparkListener with Logging {
val appRunning = new AtomicBoolean(false)
val executorCount = new AtomicInteger(0)
override def onApplicationStart(applicationStart: SparkListenerApplicationStart) = {
logger.info("Application Start called .. ")
this.appRunning.set(true)
logger.info(s"[appRunning = ${appRunning.get}]")
}
override def onExecutorAdded(executorAdded: SparkListenerExecutorAdded) = {
logger.info("Executor add called .. ")
this.executorCount.incrementAndGet()
logger.info(s"[executorCount = ${executorCount.get}]")
}
}
appRunning 和 executorCount 是在ClusterHealthListener类中声明的两个变量。 ClusterHealthReporterThread将仅读取值。
@Component
class ClusterHealthReporterThread @Autowired() (healthListener: ClusterHealthListener) extends Logging {
new Thread {
override def run(): Unit = {
while (true) {
Thread.sleep(10 * 1000)
logger.info("Checking range health")
logger.info(s"[appRunning = ${healthListener.appRunning.get}] [executorCount=${healthListener.executorCount.get}]"
}
}
}.start()
}
ClusterHealthReporterThread总是报告初始化值,而不管主线程对该变量所做的更改如何?我究竟做错了什么?这是因为我将healthListener注入ClusterHealthReporterThread吗?
我玩了一段时间,看起来与启动火花监听器的方式有关。
如果我这样添加火花监听器
val sparkContext = SparkContext.getOrCreate(sparkConf)
sparkContext.addSparkListener(healthListener)
父线程始终将 appRunning 显示为“ false”,但显示执行程序计数正确。子线程(运行状况报告程序)也将显示正确的执行程序计数,但 appRunning 始终像主线程一样报告“ false”。
然后我偶然发现了这个Why is SparkListenerApplicationStart never fired?,并尝试在spark配置级别设置侦听器,
.set("spark.extraListeners", "HealthListener class path")
如果我这样做,主线程将为 appRunning 报告'true',并报告正确的执行者计数,但是子线程将始终报告'false'和'0'执行者的价值。
答案 0 :(得分:1)
我无法立即看到这里出了什么问题,您可能已经找到了一个有趣的边缘案例。
我认为@ m4gic的注释可能是正确的,日志记录库可能正在缓存该插值字符串?看来您正在使用https://github.com/lightbend/scala-logging,它声称此插值“对行为没有影响”,所以也许没有。请您能按照他的建议重试而不使用该功能并返回报告吗?
第二种可能性:我想知道系统中是否只有一个ClusterHealthListener
?也许自动装配导致创建了第二个实例?您可以在两个位置记录ClusterHealthListener
引用中的object ids并验证它们是同一对象吗?
如果这些建议都不能解决此问题,您能否发布一个可以与我一起玩的工作示例?