【问题标题】:Amazon EMR w/ Spark w/ Postgres: "Failed to start database 'metastore_db'"Amazon EMR w/ Spark w/ Postgres:“无法启动数据库 'metastore_db'”
【发布时间】:2017-04-21 19:59:28
【问题描述】:

我之前在自己的 Linux 服务器上使用 Apache Spark 和 PostgreSQL JDBC 驱动程序没有问题,但我无法让它在 Amazon EMR 上以同样的方式工作。

我首先下载了 Postgres 驱动程序并以这种方式设置了我的 pyspark 类路径:Adding postgresql jar though spark-submit on amazon EMR

我在使用 Spark 设置的 Amazon EMR 实例上在 pyspark 中执行了以下操作,类似于我通常在自己的服务器上执行的操作。 “myhost”是我运行 PostgreSQL 的 Amazon RDS 实例的主机名,我可以使用 psql 从我的 EMR 实例连接到它,所以我知道它应该可以工作:

# helper, gets RDD from database
def get_db_rdd(table, lower=0, upper=1000):
    db_connection = {
            "host": "myhost",
            "port": 5432,
            "database": "mydb",
            "user": "postgres",
            "password": "mypassword"
            }
    url = "jdbc:postgresql://{}:{}/{}?user={}".format(db_connection["host"],
                                                      db_connection["port"],
                                                      db_connection["database"],
                                                      db_connection["user"])
    ret = sqlContext \
        .read \
        .format("jdbc") \
        .option("url", url) \
        .option("dbtable", table) \
        .option("partitionColumn", "id") \
        .option("numPartitions", 1024) \
        .option("lowerBound", lower) \
        .option("upperBound", upper) \
        .option("password", db_connection["password"]) \
        .load()
    ret = ret.rdd
    return ret

from pyspark.sql import SQLContext
sqlContext = SQLContext(sc)

rdd = get_db_rdd("test", 0, 3) # table exists, has columns (`id bigserial, string text`)

我立即遇到这个异常的崩溃:

17/04/21 19:34:07 ERROR Schema: Failed initialising database.
Unable to open a test connection to the given database. JDBC url = jdbc:derby:;databaseName=metastore_db;create=true, username = APP. Terminating connection pool (set lazyInit to true if you expect to start your database after your app). Original Exception: ------
java.sql.SQLException: Failed to start database 'metastore_db' with class loader org.apache.spark.sql.hive.client.IsolatedClientLoader$$anon$1@3aa157b0, see the next exception for details.
        at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
        at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
[...]

在网上环顾四周,这与 Apache Hive 有关...不知道为什么会涉及到这里,但我可能会误解。我确实在我的家庭目录中看到了metastore_db。所有建议的解决方案都涉及编辑一些我什至没有在我的实例上的 Hive 配置或创建我已经拥有的目录。我的 EMR 实例具有完全默认设置。更熟悉这种环境的人能否为我指明正确的方向?

编辑:我手头没有完整的堆栈跟踪,但在我的 GNU 屏幕上还剩下一些。这里还有更多,提到德比:

Caused by: ERROR XJ040: Failed to start database 'metastore_db' with class loader org.apache.spark.sql.hive.client.IsolatedClientLoader$$anon$1@3aa157b0, see the next exception for details.
        at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
        at org.apache.derby.impl.jdbc.SQLExceptionFactory.wrapArgsForTransportAcrossDRDA(Unknown Source)
        ... 113 more
Caused by: ERROR XSDB6: Another instance of Derby may have already booted the database /home/hadoop/metastore_db.
        at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
        at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
        at org.apache.derby.impl.store.raw.data.BaseDataFileFactory.privGetJBMSLockOnDB(Unknown Source)

编辑 2:使用其他 RDD,如下所示:sc.parallelize([1, 2, 3]).map(lambda r: r * 2).collect()。问题只针对连接到 Postgres 的 RDD。

编辑 3:

>>> spark.range(5).show()
+---+
| id|
+---+
|  0|
|  1|
|  2|
|  3|
|  4|
+---+

【问题讨论】:

  • "Failed to start database 'metastore_db'" 通常发生在您已经运行了一个 Spark 实例并且假设默认元存储在幕后使用 Derby 因此例外。你能发布整个堆栈跟踪吗?我预计 Derby 会在堆栈跟踪的底部出现错误。
  • 是的,我看到了 Derby 的错误。但据我所知,我只运行了一个 Spark 实例。星期一,我会再试一次,并捕获整个堆栈跟踪。
  • 越来越好!认为我们可以很快解决它。我敢肯定,当您只需 spark-shell 并执行 spark.range(5).show 并启动 Spark 底层基础架构时,您将获得完全相同的堆栈跟踪。
  • 感谢您的帮助。我今天终于尝试了,不认为这是问题所在。如果我只是执行sc.parallelize([1, 2, 3]).map(lambda r: r * 2).collect() 之类的操作,它会起作用并返回结果。只有当 JDBC 驱动程序涉及我的 Postgres 源 RDD 函数时才会出现问题。这是整个回溯(很大):gist.github.com/anonymous/15775cc6fea23bad63150a7f30b091ab
  • 我认为我设置 Postgres 连接的方式,由于某种原因,它试图再次连接到我的 metastore_db,但我的 Spark 实例已经在使用它,所以它会引发异常.

标签: postgresql apache-spark amazon-emr


【解决方案1】:

错误信息:

原因:ERROR XSDB6:另一个 Derby 实例可能已经启动了数据库 /home/hadoop/metastore_db。

告诉我们嵌入式单线程 Derby 实例已在使用中。我对 Hive 不是很熟悉,但在 Spark 启动启用 Hive 的 SparkSession 时使用,您可以在堆栈跟踪中看到:

    at org.apache.hadoop.hive.ql.session.SessionState.start(SessionState.java:503)
    at org.apache.spark.sql.hive.client.HiveClientImpl.<init>(HiveClientImpl.scala:192)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.apache.spark.sql.hive.client.IsolatedClientLoader.createClient(IsolatedClientLoader.scala:264)
    at org.apache.spark.sql.hive.HiveUtils$.newClientForMetadata(HiveUtils.scala:366)
    at org.apache.spark.sql.hive.HiveUtils$.newClientForMetadata(HiveUtils.scala:270)
    at org.apache.spark.sql.hive.HiveExternalCatalog.<init>(HiveExternalCatalog.scala:65)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.apache.spark.sql.internal.SharedState$.org$apache$spark$sql$internal$SharedState$$reflect(SharedState.scala:166)
    at org.apache.spark.sql.internal.SharedState.<init>(SharedState.scala:86)
    at org.apache.spark.sql.SparkSession$$anonfun$sharedState$1.apply(SparkSession.scala:101)
    at org.apache.spark.sql.SparkSession$$anonfun$sharedState$1.apply(SparkSession.scala:101)
    at scala.Option.getOrElse(Option.scala:121)
    at org.apache.spark.sql.SparkSession.sharedState$lzycompute(SparkSession.scala:101)
    at org.apache.spark.sql.SparkSession.sharedState(SparkSession.scala:100)
    at org.apache.spark.sql.internal.SessionState.<init>(SessionState.scala:157)
    at org.apache.spark.sql.hive.HiveSessionState.<init>(HiveSessionState.scala:32)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.apache.spark.sql.SparkSession$.org$apache$spark$sql$SparkSession$$reflect(SparkSession.scala:978)
    at org.apache.spark.sql.SparkSession.sessionState$lzycompute(SparkSession.scala:110)
    at org.apache.spark.sql.SparkSession.sessionState(SparkSession.scala:109)
    at org.apache.spark.sql.DataFrameReader.<init>(DataFrameReader.scala:549)
    at org.apache.spark.sql.SparkSession.read(SparkSession.scala:605)
    at org.apache.spark.sql.SQLContext.read(SQLContext.scala:516)

我复制了最相关的行(以消除噪音)。

旁注:这些天您并不真正需要 Hive 功能,因为 Spark 支持大多数本机(在 Spark 2.2 中大多数 Hive“基础架构”will get away)。

正如您在堆栈跟踪中看到的,multi-threads-accessing-single-threaded-Derby 异常只会在您使用 SparkSession 时引发,它是 Spark SQL 的入口点。

    at org.apache.spark.sql.SparkSession.sessionState$lzycompute(SparkSession.scala:110)
    at org.apache.spark.sql.SparkSession.sessionState(SparkSession.scala:109)
    at org.apache.spark.sql.DataFrameReader.<init>(DataFrameReader.scala:549)
    at org.apache.spark.sql.SparkSession.read(SparkSession.scala:605)
    at org.apache.spark.sql.SQLContext.read(SQLContext.scala:516)

这就是您在使用 RDD API 时看不到它的原因。 RDD API 根本不使用 Hive。

Local/Embedded Metastore Database (Derby)阅读 Hive 的官方文档。

【讨论】:

  • 是的,问题是亚马逊在其构建/配置中默认包含 Hive。如果在为 Postgres 设置 SQLContext 之前禁用 Hive 或断开默认连接,似乎可以避免该问题。文档没有建议任何方法来做到这一点。我尝试 del sqlContext 使原始 Hive 上下文 pyspark 创建断开连接,没有运气。
【解决方案2】:

感谢 Jacek 就我的问题性质提出的建议,经过反复试验,我开发了一种 hack 解决方法。还没有真正解决这个问题,但这有效,这对我来说已经足够了。以后遇到问题我会反馈的。

  1. 正常使用 Postgres 驱动启动 pyspark:pyspark --driver-class-path=/home/hadoop/postgres_driver.jar --jars=/home/hadoop/postgres_driver.jar

  2. 当它打开时 (!),在单独的 SSH 会话中,cd 到 home 和 mv metastore_db old_metastore_db(或者您可以在 pyspark 中使用 os.system() 执行此操作)。这样做的目的是释放 Spark 默认创建的 Metastore 上的锁; Spark 将在没有锁定的情况下重新创建目录。

  3. 尝试按照我在问题中描述的方式创建一个连接到 Postgres 的 RDD。它会给出一个关于“没有合适的驱动程序”的错误。由于某种原因,驱动程序未加载。但在那次错误之后,似乎驱动程序现在实际上已加载。

  4. mv metastore_db old_metastore_db2,原因与上述类似。我猜另一个 Hive 会话现在已连接,需要清除其锁定。

  5. 以同样的方式再次创建 Postgres 连接的 RDD。驱动程序已加载,metastore 已解锁,它似乎可以工作。我可以从我的表中获取数据、执行 RDD 操作和collect()

是的,我知道这很脏。使用风险自负。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-28
    • 2020-03-22
    • 2018-06-19
    • 2010-10-16
    • 1970-01-01
    • 1970-01-01
    • 2013-10-06
    相关资源
    最近更新 更多