ITPub博客

首页 > 数据库 > 数据库开发技术 > Spark 对比 Flink 导出相同数据量,需要多大内存?

Spark 对比 Flink 导出相同数据量,需要多大内存?

原创 数据库开发技术 作者:安瑞哥是码农 时间:2024-08-28 09:45:21 0 删除 编辑


既然前几期内容测试了 Flink 关于内存跟(MySQL)数据量之间的关系,那么这一次,在同等条件下,我们也来看看如果使用 Spark,那么它需要的内存,跟导出(MySQL)数据量之间,又一种什么样的关系呢?


之前的内容就说过,对于数据导入/导出这种事情,我一向秉承的原则就是,「能用 Flink 或者 Spark 来搞定的,就绝不用其他工具」。


原因很简单,这两者是组成大数据技术的最核心要素(至少我是这么认为的),相对其他组件,是社区支持力度最大,迭代升级最频繁,生态最广、也是成熟度最高的,几乎没有之一。


这次测试的目的,在于生产上,如果面临类似的数据导入场景,可以给你提供一个选择的依据。



0. 准备


Spark 读取 MySQL,目前官方推荐的主流方法,有仅只有一个,那就是通过 jdbc 的方式 ,而相比于 Flink,它只能是「批处理」。


可能你会问:咦?Flink 读 MySQL 是流的方式(需要binlog支持),而 Spark 读 MySQL ,就只能是离线方式,有什么可比性呢?


乍一看好像是,但你别忘了,在生产上,我们选择一个解决方案的关键,并不只是以「理论为驱动」,而更多会考虑解决方案的方便、高效、节省资源与否。


因为咱们这次的目的,是导出 MySQL 的「存量数据」,所以这里考虑用 Spark 以离线方式导出,也就有了合理性。


引入必要依赖


Spark 的 jdbc 方案,一般情况下,需要的依赖,相比 Flink 要更简单一点,这里要读 MySQL,就只需要引入 MySQL 自己的 jdbc 包就足够。



不存在跟 Flink 一样,还需要引入 Spark jdbc 的包一说。 


然后,就可以编码了,简单的数据处理流程如下:



1. 编码


相比之前测试的 Flink CDC 3.x 全程只需要通过配置文件,就能实现对 MySQL 数据导入到 Kafka 来说,当前 Spark 需要编码的这种方式,确实要更麻烦一点。


但当你写完后会发现,其实还好,因为代码都很简单。


package com.anryg.bigdata.streaming.mysql

import com.alibaba.fastjson.JSONObject
import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession

/**
  * @DESC: Spark 读取MySQL写Kafka,对比跟Flink消耗的内存情况
  * @Auther: Anryg
  * @Date: 2024/8/27 15:09
  */

object SparkReadMysql2Kafka {

    def main(args: Array[String]): Unit = {
        val conf = new SparkConf().setAppName("SparkReadMysql2Kafka").setMaster("local[*]")
        val spark = SparkSession.builder().config(conf).getOrCreate()

        /**读取MySQL数据*/
        val rawDF = spark.read
            .format("jdbc")
            .option("url", "jdbc:mysql://192.168.221.132:3306/test")
            .option("driver", "com.mysql.cj.jdbc.Driver")
            .option("user", "pcl")
            .option("password", "****")
            .option("dbtable", "test01")
            .load()

        import spark.implicits._  /**引入隐式转换对象*/

        /**因为要写Kafka,需要对数据做一点必要的转换*/
        val targetDF = rawDF.map(row => {
                        val jsonObj = new JSONObject(26)
                        val subject_common_name = row.getString(0)
                        jsonObj.put("subject_common_name",subject_common_name)
                        val serial_number = row.getString(1)
                        jsonObj.put("serial_number", serial_number)
                        /**中间字段省略*/
                        val created_at = row.getTimestamp(25)
                        jsonObj.put("created_at",created_at)
                        jsonObj.toJSONString
                    }).toDF("value") /**写到Kafka,key跟value字段,至少需要提供value*/

        /**将转换后,符合Kafka要求的格式数据写进Kafka*/
        targetDF
            .write
            .format("kafka")
            .option("kafka.bootstrap.servers", "192.168.211.107:6667")
            .option("topic", "test")
            .save()
    }
}

代码逻辑是:


1. 先把数据从 MySQL 读取出来;


2. 再根据 Kafka 的数据写入要求,把数据处理成只有「key」和「value」两个字段,或者只有「value」一个字段的 DataFrame。这里为了方便,把 MySQL 表中的 26 个字段,揉成一个 json string 对象,然后塞给 value 字段;


3. 最后,把符合 Kafka 格式要求的数据,写进 Kafka,数据格式跟之前 Flink CDC 写 Kafka 一样。



2. 几个需要注意的地方


但凡编码涉及到数据转换之类的操作,如果你的数据类型复杂一点点,都几乎会碰到一些不大不小的问题。


2.1 注意点01


对「Row」对象获取数据时,需要注意对应的类型,并不是所有的类型,都可以直接转为 String 的。


比如,「Boolean」、「TimeStamp」等类型就不行。



编码的时候需要注意。


2.2 注意点02


当 Spark 用 jdbc 把数据从 MySQL 读出来的时候,对应 DataFrame 的字段个数,是跟原始 MySQL 的字段个数保持一致的(这里是26个)。


但是,你不能直接就把它往 Kafka 里怼,因为格式不符合要求,这里估计有同学会犯这样的错,别问我怎么知道的,因为我开始就这么干过。


把这26个字段的数据,合成为一个 json 对象,再写到 Kafka,是一个比较主流的玩法。



3. 内存对比


在结论揭晓之前,你可以先猜一下,同样的数据量,Spark 跟 Flink 谁消耗的内存更大一些?


3.1 原始数据1倍量时


还记得上次测试用 Flink 导出的 MySQL 表的数据量不。


初始表的数据条数


初始表的数据存储大小


当时在我极致压榨 Flink 的内存之后,把这些数据导出成功,依然需要大概 10G 的内存空间。


Flink cdc需要的内存大小


而 Spark 同样被我多次调整内存之后,能成功导出这些数据量需要的内存大小如下:

 

当前 Spark 需要的内存大小


而且当前只用了一个 executor,executor 的内存大小为:


--executor-memory 3g


上次用 Flink 需要的时间为:4分30秒。


Flink cdc需要的时间


而这一次用 Spark 的效率要更高一点。


Spark 启动前的时间


Spark 任务完成时的时间

总耗时:3分27秒,比 Flink 快整整 1分钟。


小结:当 MySQL 表为原始数据量大小时,Spark 消耗的内存只需要 Flink 的一半不到,且效率也要比 Flink 快 1分钟。


3.2 原始数据2倍量时



通过调整 Spark 的 executor 内存,最终能跑成功时,executor 的内存设置为:


--executor-memory 5g

消耗的 yarn 总内存为:



由这一点可以看出来,它跟之前的 Flink CDC 进程不一样(内存需求不变),Spark 进程在数据量翻倍的情况下,导出时需要的内存也随之增加,增加了2G。


此时消耗的时间为:10分钟。(截图就不放了,麻烦)


小结:随着 MySQL 数据量的翻倍,Spark 需要的内存也随之增加了 2G(约一个原始数据文件的大小),导出效率也只有原来的一半不到。


3.3 原始数据3倍量时



通用调整 executor 的内存大小,还是加了 2G 之后才能跑通的:


--executor-memory 7g

此时,消耗的 yarn 总内存为:



可以看出来,当数据量再次增加1倍时,增加的内存还是 2G。


时间消耗为:16分钟。


小结:随着 MySQL 的数据量再增加一倍,executor 需要的内存再增加 2G,效率也同比例下降。



最后


通过这次用 Spark 导出 MySQL 表数据到 Kafka 的测试可以得出如下结论:


1,同样数据量情况下(当数据量较小时),Spark 需要的内存总量,要明显小于 Flink,而且导出效率还更高;


2,随着数据量的翻倍,Spark 需要的内存总量,会同比例增加(这里是2G,约一个原始数据文件大小),导出的效率同样呈同比例下降趋势;


3,而 Flink CDC 的导出特点是,一开始需要的内存很大,但当达到一定阈值之后,这个内存大小就不变了,跟 Spark 在使用表现上有很大不同;


4,Flink CDC 导出 MySQL 数据读取的是 binlog,而 Spark 则读取的是数据文件本身。


那么对于这种数据库的存量数据导出任务,Flink 跟 Spark,你会选哪个?




你可以添加我的私人微信,拉你入技术讨论群,跟一群热爱技术的小伙伴一起成长...


原文作者:安瑞哥是码农;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2022-02-16

  • 博文量
    228
  • 访问量
    115434