我正在尝试使用 Apache Spark 2.3.1 从Oracle DB中提取数据并将其放入 AWS S3 。这项工作进展顺利,直到最后一个阶段并陷入困境。我不认为数据存在偏差,因为每个阶段都有相同数量的记录。以下是我在spark中使用的查询。
url = "jdbc:oracle:thin:@IP:PORT/SID"
user = "user"
password = "password"
driver = "oracle.jdbc.driver.OracleDriver"
table = "table"
fetchSize = 1000
partitionColumn = "num_rows"
date1 = (datetime.today() - td(days=42)).date().strftime('%d-%b-%Y')
date2 = (datetime.today() - td(days=2)).date().strftime('%d-%b-%Y')
query = "(select min(rownum) as min, max(rownum) as max from "+table+" where date>='"+str(date1)+"' and date<='"+str(date2)+"') tmp1"
print(query)
DF = spark.read.format("jdbc").option("url", url) \
.option("dbtable", query) \
.option("user", user) \
.option("password", password) \
.option("driver", driver) \
.load()
lower_bound, upper_bound = DF.first()
lower_bound = int(lower_bound)
upper_bound = int(upper_bound)
numPartitions = int(upper_bound/fetchSize)+1
print(lower_bound,upper_bound)
print(numPartitions)
query = "(select t1.*, ROWNUM as num_rows from (select * from " + table + " where date>='"+str(date1)+"' and date<='"+str(date2)+"') t1) tmp2"
print(query)
DF = spark.read.format("jdbc").option("url", url) \
.option("dbtable", query) \
.option("user", user) \
.option("password", password) \
.option("fetchSize",fetchSize) \
.option("numPartitions", numPartitions) \
.option("partitionColumn", partitionColumn) \
.option("lowerBound", lower_bound) \
.option("upperBound", upper_bound) \
.option("driver", driver) \
.load()
path = "s3://my_path"
DF.write.mode("overwrite").parquet(path)
该代码基本上提取了过去42天的数据并将其放入S3存储桶。以下是直到write语句的输出。代码在'2018年9月10日'
上运行(select min(rownum) as min, max(rownum) as max from table where date>='30-Jul-2018' and date<='08-Sep-2018') tmp1
(1, 2195427)
2196
(select t1.*, ROWNUM as num_rows from (select * from table where date>='30-Jul-2018' and date<='08-Sep-2018') t1) tmp2
如您所见,
因此该工作有 2196 个阶段,每个阶段提取1000条记录。这项工作被困在 2191/2196 上,还有5个步骤要完成。
硬件规格:
我正在使用r4.xlarge机器。我的集群是1个Master,2个r4.xlarge的Slave。以下是我的驱动程序和执行程序规范。
spark.driver.cores 8
spark.driver.memory 24g
spark.driver.memoryOverhead 3072M
spark.executor.cores 1
spark.executor.memory 3g
spark.executor.memoryOverhead 512M
spark.yarn.am.cores 1
spark.yarn.am.memory 3g
spark.yarn.am.memoryOverhead 512M
第1阶段到2191阶段在1.3小时内完成,但其余5个阶段停留了三个多小时。
请在此处找到日志: https://github.com/rinazbelhaj/stackoverflow/blob/master/Spark_Log_10_Sept_2018
我无法找出此问题的根本原因。
答案 0 :(得分:0)
我想您有两种可能的情况:
1-与Oracle DB有关的问题
我正在处理一个非常相似的问题。但是,任务没有被卡住,而是被SQL Server中断了。中断是由connection reset
引起的,它是随机发生的。
为避免这种情况,我在JDBC连接字符串上设置了一些参数。错误已停止,但任务永无止境。
jdbc:sqlserver://host:port;database=db_name;
db_url=jdbc:sqlserver://host:port;
database=db_name;
applicationIntent=readonly;
applicationName=app-name;
columnEncryptionSetting=Disabled;
disableStatementPooling=true;
encrypt=false;
integratedSecurity=false;
lastUpdateCount=true;
lockTimeout=-1;
loginTimeout=15;
multiSubnetFailover=false;
packetSize=8000;
queryTimeout=-1;
responseBuffering=adaptive;
selectMethod=direct;
sendStringParametersAsUnicode=true;
serverNameAsACE=false;
TransparentNetworkIPResolution=true;
trustServerCertificate=false;
trustStoreType=JKS;
sendTimeAsDatetime=true;
xopenStates=false;
authenticationScheme=nativeAuthentication;
authentication=NotSpecified;
socketTimeout=0;
fips=false;
enablePrepareOnFirstPreparedStatementCall=false;
serverPreparedStatementDiscardThreshold=10;
statementPoolingCacheSize=0;
jaasConfigurationName=SQLJDBCDriver;
sslProtocol=TLS;
cancelQueryTimeout=-1;
useBulkCopyForBatchInsert=false;
因此,我决定删除JDBC连接字符串上添加的参数,并开始在创建集群时传递spark配置。我将最大重试次数从4
(默认)更改为50
。
spark.task.maxFailures=50
因此,连接问题仍然存在,但至少任务成功结束了。
我建议您设置任何连接超时,因为它可能是无限的-通常设置为0
或-1
。查看Oracle的驱动程序文档,并尝试更改默认行为。
2-与S3有关的问题
我们还面临与S3上的 write 操作有关的问题。我找不到确切的错误消息,但这与An error occurred while calling o70.parquet
类似。
当我们解决上述问题时,写入速度过长。
我们团队中的一个人建议使用HDFS从数据库写入数据,然后将操作从HDFS复制到S3。性能大大提高。
destination = 'hdfs:///path-to-hdfs'
DF.write \
.mode("overwrite") \
.parquet(destination)
参考:https://docs.aws.amazon.com/emr/latest/ReleaseGuide/UsingEMR_s3distcp.html
希望对您有所帮助!我会报告任务的任何改进;)