Amazon EMR w / Spark w / Postgres:"无法启动数据库&#cos; metastore_db'"

时间:2017-04-21 19:59:29

标签: postgresql apache-spark amazon-emr

我之前在我自己的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|
+---+

2 个答案:

答案 0 :(得分:1)

错误消息:

  

引起:错误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)

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

旁注:由于Spark支持大多数本地(以及Spark 2.2大多数Hive“基础架构”will get away),因此您最近并不需要Hive功能。

正如您在堆栈跟踪中所看到的,只有当您使用SparkSession(它是Spark SQL的入口点)时,才会抛出多线程访问单线程Derby异常。

    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的官方文档。

答案 1 :(得分:0)

感谢Jacek关于我的问题性质的建议,经过一些试验和错误后我开发了一个黑客解决方法。还没有能够真正解决问题,但这是有效的,这对我来说已经足够了。如果我以后遇到问题,我会报告。

  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()

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