使用spark生成测试大数据

一、大数据场景下一份测试数据可能要几十G、几百G,用单机生成即浪费空间时间还长。可以用mapreduce或者spark来并行生成。

需求:使用spark生成1份几百G的测试数据,根据一年12个月均匀分布。

  1. 一开始没拐过弯来的是:spark要先有rdd,这个rdd怎么建,建个hdfs上空目录的rdd?此处利用rdd的惰性,先把整个大数据在内存中建好,然后在各个分区执行。
  2. 如果上面行不通(因为在创建rdd之前就要在内存创建好数据,这个数据很大,此时还没有牵扯到rdd,可能会内存溢出),就先在driver用parallelize创建1个以12个月份为key的rdd,这个rdd一共就12条数据,然后给这个rdd用HashPartitioner(12)来分成12个区,然后在rdd.mapPartitionsWithIndex中分别创建,这个方法100%会成功。
    这个思路普遍适用于用分布式程序(不一定是分布式分析和计算)

二、使用spark

1.利用rdd的惰性,先在driver中用parallelize创建数据的rdd,然后分区,然后用mapPartition或者mapPartitionsWithIndex在各个分区将数据写入到同一个hdfs目录下。

2.须知:

  1. 分区号是从0开始计数的
  2. partitionBy(Partitioner)中的org.apache.spark.HashPartitioner(12)是根据key分区的。

3.example1

package cn.dc.mockdata

import java.io.{BufferedWriter, FileOutputStream, OutputStreamWriter}

import org.apache.spark.sql.SparkSession

import scala.collection.mutable.ListBuffer

object SparkMockData {
  def main(args: Array[String]): Unit = {

    val ss = SparkSession.builder().master("local[*]").appName("mock").getOrCreate()

    case class Test(date: Int, name: String, id: String)

    val list = ListBuffer(Test(1, "1", "1"), Test(2, "2", "2"))

    list += Test(3, "3", "3")
    list += Test(3, "4", "4")
    list.append(Test(3, "4", "4"))
    list :+ Test(3, "4", "4")

    val rdd = ss.sparkContext.parallelize(list).map(test => (test.date -> test.name)).partitionBy(new org.apache.spark.HashPartitioner(12))

    rdd.mapPartitionsWithIndex(
      (partIdx, iter) => {
        val writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("test/",true)))
        val part_map = scala.collection.mutable.Map[Int, Test]()
        while (iter.hasNext) {
          val next = iter.next
          println(s"$partIdx : $next")
          writer.append(s"$partIdx").write(next.toString())
        }
        writer.flush()
        writer.close()
        part_map.iterator
      }).take(1)
  }
}

4.example2

package cn.dc.mockdata

import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.fs.{FileSystem, Path}
import org.apache.spark.Partitioner
import org.apache.spark.sql.SparkSession
import org.slf4j.LoggerFactory

object SparkMockData2 {
  val log = LoggerFactory.getLogger(classOf[SparkMockData2])
  def main(args: Array[String]): Unit = {

    val ss = SparkSession.builder().appName("mock-tencent-data").getOrCreate()
    val sc = ss.sparkContext

    val seq = Seq(1 to 12)

    /*
    构建rdd
      将RDD转成pairRDD
      如果想要更多的分区,比如24个分区,可以设置24个数,然后MyPartitioner中对12取余即可。
     */
    val rdd = sc.parallelize(seq).map(num => num -> num).partitionBy(new MyPartitioner(12))
    /*
    广播fs,12减少为3
    亲测,会报错,并发相关的错,只能一个partition创建1个fs
    val broadcast = sc.broadcast(FileSystem.get(new Configuration()))
     */

    rdd.mapPartitionsWithIndex(

      (partIdx, iter) => {
        val fs = FileSystem.get(new Configuration())

        val dirPath = new Path(f"/user/hive/dctest/tencent_big_all")
        if (!fs.exists(dirPath)) fs.mkdirs(dirPath)
        val filePath = new Path(f"$dirPath/2018${partIdx + 1}%02d")
        if (fs.exists(filePath)) fs.delete(filePath,false)
        val writer = fs.create(filePath)
        //这里必须创建1个无关的map返回,直接返回iter会报错,原因未知
        val part_map = scala.collection.mutable.Map[Int, Int]()

        for (i <- 0 until 1000) {
          val template = s"2018${partIdx + 1}" + "1"+"2"
          if (i == 999) writer.write(template.getBytes("UTF-8"))
          else writer.write((template + "\n").getBytes("UTF-8"))
        }

        part_map.iterator
      }).take(1)
  }
}

class MyPartitioner(numParts: Int) extends Partitioner {
  //设置总分区数,使用设置的总分区数覆盖默认的分区数
  override def numPartitions: Int = numParts

  //根据key返回分区号,从0开始计数,比如12个分区,就是0~11
  override def getPartition(key: Any): Int = key.toString.toInt - 1

}

class SparkMockData2{}

分布式场景下生成唯一id

  1. 尽量不用UUID,占空间,join时浪费性能。
  2. 一开始用的是时间戳+随机数+分区号,即使是5位随机数的情况下,并行度50的情况下,1亿条会有2.5万的重复,这是不可接受的,时间戳精确到毫秒,1毫秒会生成260多条数据。而且这个策略占用很多空间,时间戳的前半部分但部分是重复的,总长度也在20以上。
  3. 实际上亿只有9位,理论上10位就足够了。这里借鉴了zipWithUniqueId里的分布式递增生成主键的算法。每个分区初始值为分区号,然后每个分区递增的步长为分区数,假设总数为1亿,分区数为20,这种算法相当于把1亿分成了20份,每个分区间隔占有自己的部分。完美的分布式唯一id生成算法。

example1

一开始想在driver创建1个(o until 100000000)的rdd,然后用zipWithUniqueId,但运行时发现因为资源不够,直接卡住,给driver增加到7G内存和5个core都不行,而且这种方式本身就违反了spark的设计初衷。但小数据量下是正常运行的。

example2

创建0 until 20的rdd,然后mapPartitionWithIndex,在里面用for(i <- Range(partIdx,sum,partNum))的方式创建id,完美解决问题

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码 毕业设计 课程设计 项目开发 系统开发 Spark 机器学习 大数据 算法 源码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值