我之前在我自己的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|
+---+
答案 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关于我的问题性质的建议,经过一些试验和错误后我开发了一个黑客解决方法。还没有能够真正解决问题,但这是有效的,这对我来说已经足够了。如果我以后遇到问题,我会报告。
正常使用Postgres驱动程序启动pyspark:pyspark --driver-class-path=/home/hadoop/postgres_driver.jar --jars=/home/hadoop/postgres_driver.jar
当打开(!)时,在单独的SSH会话中,cd到home和mv metastore_db old_metastore_db
(或者你可以在pyspark中用os.system()
执行此操作)。这一点就是释放Spark默认创建的Metastore上的锁; Spark将重新创建没有锁定的目录。
尝试按照我在问题中描述的方式创建连接到Postgres的RDD。它会给出一个关于“没有合适的驱动程序”的错误。出于某种原因,驱动程序未加载。但是在那个错误之后,现在看来驱动程序实际上已经加载了。
mv metastore_db old_metastore_db2
,原因与上述类似。我想现在已经连接了另一个Hive会话,需要将其锁定清除。
以同样的方式再次创建Postgres连接的RDD。驱动程序已加载,Metastore已解锁,似乎可以正常工作。我可以从我的表中获取,执行RDD操作,以及collect()
。
是的,我知道这很脏。使用风险自负。