Spark作业在从Oracle DB导入的最后阶段被卡住-数据不倾斜

时间:2018-09-10 10:38:53

标签: apache-spark pyspark apache-spark-sql

我正在尝试使用 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

如您所见,

  • 记录总数= 2195427
  • 每个分区的记录= 1000
  • 分区数= 2196

因此该工作有 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

Spark Executor UI

第1阶段到2191阶段在1.3小时内完成,但其余5个阶段停留了三个多小时。

请在此处找到日志: https://github.com/rinazbelhaj/stackoverflow/blob/master/Spark_Log_10_Sept_2018

我无法找出此问题的根本原因。

1 个答案:

答案 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。性能大大提高。

  • 将HDFS设置为目标(可能需要增加主节点的磁盘大小)
destination = 'hdfs:///path-to-hdfs'

DF.write                \
  .mode("overwrite")    \
  .parquet(destination)
  • 执行从HDFS到S3的复制

参考:https://docs.aws.amazon.com/emr/latest/ReleaseGuide/UsingEMR_s3distcp.html

希望对您有所帮助!我会报告任务的任何改进;)