背景
最近笔者需要通过 beeline 测试 Spark on Yarn 的多租户架构,但由于测试服务器设置了非活动超时时间,导致在终端调用 beeline 执行 SQL 的脚本由于会话长时间不活动而被中止了。笔者第一时间想到的是将调用 beeline 的脚本挂后台运行,但是跟同事交流时,却被告知 beeline 不支持后台运行,至于具体的原因,同事也不是很清楚。于是,勾起了笔者的好奇心,想揭开这神秘的面纱。
分析
通常情况下,遇到问题首先习惯地 google 一下 ,看看有没有网友遇到了类似的问题。在 google 搜索 beeline not running in background
关键字会可以看到 Hive 的 JIRA 问题单 有提及该问题出现的原因和解决方案 。当然,笔者在 Spark 的 JIRA问题单 中也找到了对于该问题的描述,问题单提到的解决方案沿用了 Hive 的 JIRA 问题单提及的方案。为了避免混淆读者的思路,在此笔者简单地说明一下 Spark 和 Hive 的关系。Spark 的 beeline 是基于 Hive 的 beeline 进行开发的。因此适用于 Hive 的 beeline 问题修复方法通常情况下也适用于 Spark 的 beeline。
在 Hive 的 JIRA 问题单中提到,beeline 为了更好地展示漂亮的表格,使用 jline.Terminal.setupTerminal().getTerminalWidth()
获得终端的宽度,而该方法是通过调用 stty 来设置终端属性。当 beeline
以后台模式运行,调用 stty 时,内核的终端驱动程序在会发送一个 SIGTTOU 信号,该信号在没有被捕获进行特殊处理时,默认是中止当前进程。
后台模式运行 beeline 更多是因为通过编写脚本的方式来调用,因此对于表格格式,我们并不 care 它是否漂亮,而 jline 库提供 -Djline.terminal=jline.UnsupportedTerminal
参数,可以将终端类型设置为 UnsupportedTerminal
,不再调用 stty
,进而避免了 beeline 以后台模式运行时,接收到 SIGTTOU
信号。
问题的解决方案已经找到了,那么应该在哪里添加 -Djline.terminal=jline.UnsupportedTerminal
呢?熟悉 Java 的读者可能已经想到 JVM 允许通过 -D
来设置系统变量,因此该参数应该在调用 java 命令时进行设置。
beeline 启动过程
接下来,我们来看看 beeline 的启动过程。当我们在命令行终端中执行 beeline
脚本时,beeline
脚本首先判断 ${SPARK_HOME}
环境变量是否为空,若为空,则调用 find-spark-home
脚本查找 ${SPARK_HOME}
,然后通过 spark-class
脚本调用 org.apache.hive.beeline.Beeline
类 。
# Figure out if SPARK_HOME is set
if [ -z "${SPARK_HOME}" ]; then
source "$(dirname "$0")"/find-spark-home
fi
CLASS="org.apache.hive.beeline.BeeLine"
exec "