2017-07-28 194 views
-1

我正在尝试使用数据源MySQL的Apache Spark。我有一个集群有1个主节点和1个从属节点,都有8 GB RAM和2个核心我正在提交我的SQL查询以使用spark-shell进行激发,并且该表有这么多行。我正在执行到该表上。和时间由MySQL是5.2secs和使用火花时,我正在执行查询时间是21Secs。为什么发生这种情况?为什么spark还比mysql慢?

我还设置了一些配置,如partitionColumn,upperBound,lowerBound和numofPartitions但仍然没有变化。

我也曾尝试与执行使用1,2,4内核的查询,但在火花所花费的时间是相同的21Secs

发生这个问题是因为我的MySQL数据库在单台机器上,而所有的火花节点都试图将数据查询到单台机器上?

任何人都可以帮我解决这个问题吗?

有一个名为demo_call_stats上我试图查询表的数据库是:

val jdbcDF = spark.read.format("jdbc").options(Map("url" -> "jdbc:mysql://192.168.0.31:3306/cmanalytics?user=root&password=","zeroDateTimeBehaviour"->"convertToNull", "dbtable" -> "cmanalytics.demo_call_stats", "fetchSize" -> "10000", "partitionColumn" -> "newpartition", "lowerBound" -> "0", "upperBound" -> "4", "numPartitions" -> "4")).load() 

jdbcDF.createOrReplaceTempView("call_stats") 

val sqlDF = sql("select Count(*), classification_id from call_stats where campaign_id = 77 group by classification_id") 

sqlDF.show() 

任何帮助将非常感激。

感谢

+1

如果数据不在RAM中,Spark在执行计算之前需要将其拉出。因此,网络IO可能是一个瓶颈。由于我不确定你是如何衡量你的查询性能的,也不知道你的查询是什么,也不知道你的数据分布,所以我们在这里帮不了你的忙。 – eliasah

+0

考虑共享一些代码和一些关于你的数据的信息!你可能没有得到一个具体的解决方案,但也许我可以帮助你一些指针。 – eliasah

+0

@eliasah我正在测量使用火花Web UI的查询性能。 –

回答

5

有几件事情你应该明白这里:

尽管你可能已经听说过,Spark是不是“比MySQL快”,仅仅是因为这种一般性的不意味着什么。 对于某些查询,Spark比MySQL更快,MySQL对于其他人来说比Spark快。 一般来说,MySQL是一个关系数据库,这意味着它已被设想为 作为应用程序的后端。只要对索引进行索引,它就可以高效地访问记录。

在考虑数据库时,我喜欢把它们想象成一个图书馆,有一个图书管理员来帮助你获得你想要的图书 (我在这里讲一个非常古老的学校图书馆,没有任何计算机来帮助图书管理员) 。

如果你问你的图书馆员: “我想知道你多少书是关于地缘政治”, 馆员可以到地缘政治货架和计数的那个书架上图书的数量。

如果你问你的图书馆员: “我想知道你多少书有至少有500页的”, 图书管理员将不得不看每一个在图书馆看书回答您的查询。 在SQL中,这称为全表扫描。 当然,您可以让一些图书管理员(处理器)在查询上工作得更快, ,但您的图书馆(计算机)中不能超过其中的一部分(我们假设多达16个)。

现在,Spark已被设计为处理大量数据,即如此大的图书馆 以至于它们不适合单个建筑物,并且即使这样,它们也会如此之多以至于甚至可以达到16个图书馆员需要几天时间才能回答你的第二个问题。

让Spark比MySQL更快的原因是:如果你把你的书放在几栋建筑物中,你可以有16个馆员每栋工作你的答案。 你也可以处理更多的书籍。

此外,由于星火主要是回答第二类查询,而不是像这样的查询“请带上我'肖像灰色',由奥斯卡王尔德”,这意味着Spark不关心,至少默认情况下,以任何特定的方式分类您的书籍。 这意味着如果你想用火花找到那本特定的书,你的图书馆员将有 通过整个图书馆来找到它。

当然,Spark使用许多其他类型的优化来更有效地执行某些查询,但索引不是其中之一。 (如果您熟悉mySQL中的主键的概念,则Spark中没有这样的东西) 其他优化包括像Parquet和ORC这样的存储格式,它允许您只读取有用的列 以回答您的查询,并且压缩(例如Snappy),它们旨在增加图书馆的数量,您可以在图书馆中放入 而无需推墙。

我希望这个比喻对你有所帮助,但请记住,这只是一个比喻,并且 完全不符合现实。

现在,要回你的问题的具体细节:

假设campaign_id是你的主键或您在此列创建的索引,MySQL将只 来读取其中campaign_id = 77行。另一方面,Spark将不得不要求mySQL将该表中的所有行发送到Spark。 如果Spark很聪明,它只会询问campaign_id = 77,并且可能会向mySQL发送多个查询以并行获取范围。 但是这意味着MySQL只能读取和聚合的所有数据都将被序列化,发送到Spark,并由Spark进行聚合。 我希望你明白为什么这会花更长的时间。

如果您希望Spark比MySQL更快地回答您的查询,您应该尝试以另一种格式复制表格。

// replace this line : 
// jdbcDF.createOrReplaceTempView("call_stats") 
// with : 
jdbcDF.write.format("orc").saveAsTable("call_stats") 

另一件事你可以尝试是缓存数据是这样的:

jdbcDF.cache().createOrReplaceTempView("call_stats") 

缓存不会带来任何改善的第一个查询的同时执行它,它会缓存数据,但如果你继续质疑同样的观点,它可能会更快。但是正如我上面所解释的,这并不意味着Spark对于任何事情都会比mySQL更快。

对于小数据和本地部署,您还可以通过更改此配置 参数spark.sql.shuffle.partitions=4(默认为200)来获得perf改进。

希望这会有所帮助。