Spark TPC-DS 测试

TPC-DS 数据集是怎么回事大家可以在网上搜索一下就知道了,我在这里不做介绍,我只介绍一下如果使用spark做TPC-DS测试。

TPC-DS数据集的生成

TPC-DS数据生成需要两个项目, 一个是tpcds-kit ,另一个是 spark-sql-perf

辅助工具生成

tpcds-kit

源码地址: tpcds-kit

按照github上的文档按照步骤进行编译就可以了,编译后需要tools的两个文件: dsdgen,tpcds.idx

把文件放在所有计算节点的/tmp/tpcds 目录下,这里待后面使用,如果是不方便的话,可以使用spark local的方式进行生成数据,可以只放在本地目录。

spark-sql-perf

源码地址: GitHub - databricks/spark-sql-perf

按照github上的文档按照步骤进行编译就可以了,编译后需要的是target/scala-2.12目录下的jar包:spark-sql-perf-assembly-0.5.1-SNAPSHOT.jar

注意事项:spark-sql-perf 项目是sbt进行项目管理的可以使用阿里的源进行编译,就很容编译成功

生成数据

执行spark-submit进行生成数据,注意修改参数--dsdgenDir目录和 jar包位置。

文件格式一定使用ORC ,因为文本和Parquet 在hive表生成的时候有问题,只能使用ORC, 如果要想测试文本和qarquet的话可以不用hive进行创建外部表。

spark3-submit \
--conf spark.dynamicAllocation.enabled=false \
--conf spark.shuffle.service.enabled=false \
--class com.databricks.spark.sql.perf.tpcds.GenTPCDSData \
--deploy-mode client \
--name generate_dataset \
--master yarn \
--conf spark.yarn.submit.waitAppCompletion=true \
--conf spark.driver.cores=2 \
--conf spark.driver.memory=4G \
--conf spark.executor.cores=2 \
--conf spark.executor.memory=8G \
--conf spark.executor.instances=25 \
--conf spark.executor.memoryOverhead=2048 \
--conf spark.default.parallelism=600 \
/home/hadoop_test/tpcdb/spark-sql-perf-assembly-0.5.1-SNAPSHOT.jar \
--dsdgenDir  /tmp/tpcds \
--master yarn \
--scaleFactor 100 \
--location /user/hadoop_test/tpcdb_4 \
--format orc \
--overwrite true \
--partitionTables true \
--numPartitions 100

创建Hive 外部表

创建外部表,使用的是spark-shell ,在spark-shell中执行代码。亲测创建外部表只能使用sparksql进行查询,使用hive进行查询会有问题,猜测和本人使用的hive版本和spark版本有关系,不过对于spark跑tpc-ds 测试已经足够了

spark3-shell \
--conf spark.dynamicAllocation.enabled=false \
--name generate_dataset \
--master yarn \
--conf spark.yarn.submit.waitAppCompletion=true \
--conf spark.driver.cores=2 \
--conf spark.driver.memory=4G \
--conf spark.executor.cores=2 \
--conf spark.executor.memory=8G \
--conf spark.executor.instances=25 \
--conf spark.executor.memoryOverhead=2048 \
--conf spark.default.parallelism=600 \
--jars /home/hadoop_test/tpcdb/spark-sql-perf-assembly-0.5.1-SNAPSHOT.jar 
val databaseName = "tpcds"
sql(s"drop database if exists $databaseName cascade")
sql(s"create database $databaseName")
val scaleFactor = "10"
val format = "orc"
val useDecimal = true
val useDate = true
val filterNull = false
val shuffle = true
import com.databricks.spark.sql.perf.tpcds.TPCDSTables
val sqlContext = spark.sqlContext
val tables = new TPCDSTables(sqlContext, dsdgenDir = "/tmp/tpcds", scaleFactor = scaleFactor, useDoubleForDecimal = !useDecimal, useStringForDate = !useDate)
val rootDir="/user/hadoop_test/tpcdb_4"
tables.createExternalTables(rootDir, format, databaseName, overwrite = true, discoverPartitions = true)

// 如果是其他格式可以试试临时,本人因为要对比k8s和cdh的性能,在k8s使用的就是这种格式,亲测可以使用
// tables.createTemporaryTables(rootDir, format)

TPC-DS数据集性能SQL运行

性能测试运行也是使用的spark-shell ,启动命令值前面一直 , 如果是使用临时表的话可以使用上面那个spark 应用继续往下执行。

注意事项, 本段scala代码有两段多行的语句,需要使用:paste 进行执行,直接粘贴会有报错

val databaseName = "tpcds"
val scaleFactor = "100"
val useDecimal = true
val useDate = true
val iterations = 2
val timeout = 60
val query_filter = Seq()
val randomizeQueries = false
val resultLocation = "/user/hadoop_test/tpcdb_4_results"
sql(s"use $databaseName")
import com.databricks.spark.sql.perf.tpcds.TPCDS
val sqlContext = spark.sqlContext
val tpcds = new TPCDS (sqlContext = sqlContext)

def queries = {
  val filtered_queries = query_filter match {
    case Seq() => tpcds.tpcds2_4Queries
    case _ => tpcds.tpcds2_4Queries.filter(q => query_filter.contains(q.name))
  }
  if (randomizeQueries) scala.util.Random.shuffle(filtered_queries) else filtered_queries
}


val experiment = tpcds.runExperiment(
  queries, 
  iterations = iterations,
  resultLocation = resultLocation,
  tags = Map("runtype" -> "benchmark", "database" -> databaseName, "scale_factor" -> scaleFactor))

println(experiment.toString)
experiment.waitForFinish(timeout*60*60)

查看执行结果

对应目录:resultLocation = "/user/hadoop_test/tpcdb_4_results" 下有一个时间目录下是一个json文件。

json文件会存放结果,这个结果会有运行迭代次数据的行数,建议使用json格式化每行数,进行查看比较方便,也可以自己写一个小程序生成CSV,用EXCEL 进行查看。

本人写了一个小程序,可以进行结果,如果大家有好的方式欢迎大家写在评论区中。

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import lombok.Data;

@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@Data
public class Result {

  private String name;
  private Integer executionTime;
}





// //
// 
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.opencsv.CSVWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;

public class TpcdsResultAnalytis {

  public static void main(String[] args) throws Exception {

    String rootDir = "D:\\test\\tpcds\\result";
    String resultDir = "D:\\test\\tpcds\\result-result";

    File[] files = new File(rootDir).listFiles();

    List<String> headers = new ArrayList<>();

    headers.add("name");
    ObjectMapper mapper = new ObjectMapper();
    Map<String, List<Result>> resultMap = new HashMap<>();
    for (File file : files) {
      String fileName = file.getName();
      if (!fileName.endsWith(".json")) {
        System.out.println(fileName + "is not a json");
        continue;
      }

      String nameKey = fileName.substring(0, fileName.length() - 5);

      List<String> lines = IOUtils.readLines(new FileReader(file));


      for (String line : lines) {
        JsonNode node = mapper.readTree(line);
        int iteration = node.get("iteration").asInt();
        JsonNode results = node.get("results");
        List<Result> resultsObject = mapper
            .convertValue(results, new TypeReference<List<Result>>() {
            });
        String header = nameKey + "-" + iteration;
        headers.add(header);
        resultMap.put(header, resultsObject);
      }
    }
    File resultDirFile = new File(resultDir);
    if (!resultDirFile.exists()) {
      resultDirFile.mkdirs();
    }
    CSVWriter csvWriter = new CSVWriter(new FileWriter(new File(resultDir, "tmp.csv")));
    csvWriter.writeNext(headers.toArray(new String[0]));

    List<Result> oneResults = resultMap.get(headers.get(1));

    for (int i = 0; i < oneResults.size(); i++) {
      String tmpResult [] = new String[headers.size()];
      tmpResult[0] = oneResults.get(i).getName();

      for (int j = 1; j < headers.size(); j++) {
        Result tmp = resultMap.get(headers.get(j)).get(i);
        if(!tmp.getName().equals(tmpResult[0])){
          System.out.println("========================1========================");
          System.out.println(tmp);
          System.out.println(oneResults.get(i));
          System.out.println("========================2========================");
        }else{
          tmpResult[j]=tmp.getExecutionTime()+"";
        }

      }
      csvWriter.writeNext(tmpResult);
    }
    csvWriter.close();
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值