spark 并行 oracle,只有单线程使用多处理p执行PySpark的并行SQL查询

博主遇到一个问题,尝试使用PySpark从多个没有主键的Oracle数据库表中提取数据并保存为Parquet文件。他们首先尝试了Sqoop,但由于问题转向PySpark。在本地模式下,他们能够执行JDBC查询并将数据保存到Parquet,但发现只有一个线程在执行,导致并行处理失效。问题可能是由于文件锁定或其他并发控制问题。尽管他们考虑使用连接池和JayDeBeAPI,但寻求解决方案以实现并行查询和数据保存,同时利用Spark的并行处理能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我有一个例子,我使用PySpark(或者Spark,如果我不能使用Python,则需要使用Scala或Java)从几百个缺少主键的数据库表中提取数据。(为什么甲骨文会创建一个包含主键表的ERP产品是另一个主题。。。但是无论如何,我们需要能够提取数据并将每个数据库表中的数据保存到Parquet文件中。)我最初尝试使用Sqoop而不是PySpark,但是由于我们遇到了许多问题,尝试使用PySpark/Spark更有意义。在

理想情况下,我希望计算集群中的每个任务节点:取一个表的名称,从数据库中查询该表,并将该表另存为S3中的Parquet文件(或Parquet文件集)。我的第一步是让它在独立模式下本地工作。(如果我对每个给定的表都有一个主键,那么我可以将查询和文件保存过程划分为给定表的不同行集,并将行分区分布到计算集群中的任务节点上,以并行执行文件保存操作,但这是因为Oracle的ERP产品缺少表的主键值得关注的是,这不是一个选择。)

我能够用PySpark成功地查询目标数据库,并且能够使用多线程将数据成功地保存到parquet文件中,但是由于某些原因,只有一个线程可以执行任何操作。如果另一个线程只执行了一个文件名,则只会将该文件保存为一个单独的文件名。我猜可能发生了某种类型的锁定问题。

如果我正确理解这里的评论:How to run multiple jobs in one Sparkcontext from separate threads in PySpark?

那么我要做的应该是可能的,除非有与执行并行jdbcsql查询相关的特定问题。在

编辑:我正在寻找一种方法,允许我使用某种类型的线程池,这样我就不需要为需要处理的每个表手动创建线程,并在集群中的任务节点之间手动平衡它们。在

即使我试着设置:--master local[*]

以及

^{pr2}$

问题依然存在。在

另外,为了简单地解释我的代码,我需要使用一个自定义的JDBC驱动程序,并且我在Windows上的Jupyter笔记本中运行代码,所以我使用了一个解决方法来确保PySpark以正确的参数启动。

(我没有反对其他操作系统的记录,但我的Windows机器是我最快的工作站,所以我才使用它。)

以下是我的设置:driverPath = r'C:\src\NetSuiteJDBC\NQjc.jar'

os.environ["PYSPARK_SUBMIT_ARGS"] = (

"--driver-class-path '{0}' --jars '{0}' --master local[*] --conf 'spark.scheduler.mode=FAIR' --conf 'spark.scheduler.allocation.file=C:\\src\\PySparkConfigs\\fairscheduler.xml' pyspark-shell".format(driverPath)

)

import findspark

findspark.init()

from pyspark import SparkContext, SparkConf

from pyspark.sql import SparkSession, Column, Row, SQLContext

from pyspark.sql.functions import col, split, regexp_replace, when

from pyspark.sql.types import ArrayType, IntegerType, StringType

spark = SparkSession.builder.appName("sparkNetsuite").getOrCreate()

spark.sparkContext.setLogLevel("INFO")

spark.sparkContext.setLocalProperty("spark.scheduler.pool", "production")

sc = SparkContext.getOrCreate()

然后,为了测试多重处理,我创建了这个文件sparkMethods.py在我运行Jupyter笔记本的目录中,并将此方法放入其中:def testMe(x):

return x*x

当我跑步时:from multiprocessing import Pool

import sparkMethods

if __name__ == '__main__':

pool = Pool(processes=4) # start 4 worker processes

# print "[0, 1, 4,..., 81]"

print(pool.map(sparkMethods.testMe, range(10)))

在我的Jupyter笔记本中,我得到了预期的输出:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

此方法包含用于建立JDBC连接的逻辑:# In sparkMethods.py file:

def getAndSaveTableInPySpark(tableName):

import os

import os.path

from pyspark.sql import SparkSession, SQLContext

spark = SparkSession.builder.appName("sparkNetsuite").getOrCreate()

spark.sparkContext.setLogLevel("INFO")

spark.sparkContext.setLocalProperty("spark.scheduler.pool", "production")

jdbcDF = spark.read \

.format("jdbc") \

.option("url", "OURCONNECTIONURL;") \

.option("driver", "com.netsuite.jdbc.openaccess.OpenAccessDriver") \

.option("dbtable", tableName) \

.option("user", "USERNAME") \

.option("password", "PASSWORD") \

.load()

filePath = "C:\\src\\NetsuiteSparkProject\\" + tableName + "\\" + tableName + ".parquet"

jdbcDF.write.parquet(filePath)

fileExists = os.path.exists(filePath)

if(fileExists):

return (filePath + " exists!")

else:

return (filePath + " could not be written!")

然后,回到我的Jupyter笔记本,我运行:import sparkMethods

from multiprocessing import Pool

if __name__ == '__main__':

with Pool(5) as p:

p.map(sparkMethods.getAndSaveTableInPySpark, top5Tables)

问题是似乎只有一个线程在执行。

当我在控制台输出中执行它时,我看到它最初包括以下内容:The process cannot access the file because it is being used by another process.

The system cannot find the file

C:\Users\DEVIN~1.BOS\AppData\Local\Temp\spark-class-launcher-output-3662.txt.

. . .

这让我怀疑,可能是某种类型的锁定发生了。在

雷加尔德斯s、 其中一个线程将始终成功运行并成功地查询其对应的表,并根据需要将其保存到Parquet文件中。进程中存在一些不确定性,因为不同的执行会导致不同的线程赢得竞争,从而处理不同的表。

有趣的是,只有一个作业被执行,如Spark UI所示:

KdfEW.png

但是,这里的文章:https://medium.com/@rbahaguejr/threaded-tasks-in-pyspark-jobs-d5279844dac0

这意味着如果Spark UI成功启动了多个作业,我应该会看到它们。在

现在,如果问题是PySpark实际上不能跨不同的任务节点并行运行多个JDBC查询,那么我的解决方案可能是使用JDBC连接池,甚至只为每个表打开一个连接(只要我在线程末尾关闭连接)。

当获取要处理的表列表时,我成功地通过jaydebeapi库连接到数据库,如下所示:import jaydebeapi

conn = jaydebeapi.connect("com.netsuite.jdbc.openaccess.OpenAccessDriver",

"OURCONNECTIONURL;",

["USERNAME", "PASSWORD"],

r"C:\src\NetSuiteJDBC\NQjc.jar")

top5Tables = list(pd.read_sql("SELECT TOP 5 TABLE_NAME FROM OA_TABLES WHERE TABLE_OWNER != 'SYSTEM';", conn)["TABLE_NAME"].values)

conn.close()

top5Tables

输出为:['SALES_TERRITORY_PLAN_PARTNER',

'WORK_ORDER_SCHOOLS_TO_INSTALL_MAP',

'ITEM_ACCOUNT_MAP',

'PRODUCT_TRIAL_STATUS',

'ACCOUNT_PERIOD_ACTIVITY']

因此,可以想象的是,如果问题是PySpark不能用于像这样跨任务节点分布多个查询,那么也许我可以使用jaydebeapi库来建立连接。但是,在这种情况下,我仍然需要一种方法来将jdbcsql查询的输出写入Parquet文件(这在理想情况下可以利用Spark的模式推理功能),但是如果可行的话,我愿意采用这种方法。在

那么,如何在主节点不按顺序执行所有查询的情况下,成功地查询数据库并并行地将输出保存到Parquet文件(即分布在任务节点上)?在

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值