常用技巧

本教程将指导你如何创建 CarbonData 表以及进行性能优化。 以下章节将详细介绍下面的主题:

创建 CarbonData 表的建议

比如,下面总结了行数范围在 10000 到 100 亿以及列数在 100 到 300 表格的创建分析结果。 下表介绍了使用到的一些列。

  • 表格列说明
  • 列名 数据了下 基数 属性
    msisdn
    String
    30 million
    Dimension
    BEGIN_TIME
    BigInt
    10 Thousand
    Dimension
    HOST
    String
    1 million
    Dimension
    Dime_1
    String
    1 Thousand
    Dimension
    counter_1
    Decimal
    NA
    Measure
    counter_2
    Numeric(20,0)
    NA
    Measure
    ...
    ...
    NA
    Measure
    counter_100
    Decimal
    NA
    Measure
  • 把经常使用到的过滤列放在开头
  • 比如, MSISDN 在大多数查询会用来过滤,这样我们必须将 MSISDN 放在第一列。 create table 命令可以按照以下建议进行修改:

    create table carbondata_table(
      msisdn String,
      BEGIN_TIME bigint,
      HOST String,
      Dime_1 String,
      counter_1, Decimal
      ...
    
      )STORED BY 'carbondata'
      TBLPROPERTIES ('SORT_COLUMNS'='msisdn, Dime_1')
    

    现在使用 MSISDN 进行过滤的查询效率会更高。

  • 将列按照使用频率从低到高的次序排列
  • 如果指定查询中用到的表有多个频繁用于过滤结果的列,建议将列按照使用频率从低到高的次序排列。 经常使用的列按照这种次序排序,可以提高压缩比并提高在这些列上筛选结果的查询性能。

    比如, 如果 MSISDN、HOST 和 Dime_1 是经常使用的列,那么列的顺序建议为 Dime_1>HOST>MSISDN,因为 Dime_1 使用频率最低。 create table 命令可以按照以下建议进行修改:

    create table carbondata_table(
        msisdn String,
        BEGIN_TIME bigint,
        HOST String,
        Dime_1 String,
        counter_1, Decimal
        ...
    
        )STORED BY 'carbondata'
        TBLPROPERTIES ('SORT_COLUMNS'='Dime_1, HOST, MSISDN')
    
  • 对于精度不高的测量类型的列,请将 Numeric(20,0)数据类型替换为 Double 数据类型
  • 对于测量类型(measure type)的列,不要求高精度,建议用 Double 替换数字数据类型以增强查询性能。 create table 命令可以按照以下建议进行修改:

      create table carbondata_table(
        Dime_1 String,
        BEGIN_TIME bigint,
        END_TIME bigint,
        HOST String,
        MSISDN String,
        counter_1 decimal,
        counter_2 double,
        ...
        )STORED BY 'carbondata'
        TBLPROPERTIES ('SORT_COLUMNS'='Dime_1, HOST, MSISDN')
    

    测试用例的性能分析结果显示查询执行时间从 15 秒缩短到 3 秒,因此将性能提高了近 5 倍。

  • 增量字符的列应重新排列在维度(dimensions)的末尾
  • 考虑每天加载数据的场景,每次加载 begin_time 都是增加的,建议将 begin_time 放在维度的末尾。 增量值在使用最小/最大索引时很有效。create table 命令可以按照以下建议进行修改 :

    create table carbondata_table(
      Dime_1 String,
      HOST String,
      MSISDN String,
      counter_1 double,
      counter_2 double,
      BEGIN_TIME bigint,
      END_TIME bigint,
      ...
      counter_100 double
      )STORED BY 'carbondata'
      TBLPROPERTIES ('SORT_COLUMNS'='Dime_1, HOST, MSISDN')
    

    海量数据加载性能优化的配置

    CarbonData 支持加载海量数据,在这个过程中,加载时排序数据会消耗大量的内存和磁盘IO,有时候可能出现内存不足异常。 如果你没有足够的内存可使用,那么你可能更喜欢减慢数据的加载速度,而不是数据加载失败。 你可以通过调整 carbon.properties 文件中的属性来配置 CarbonData 以便获得更好的性能。

    属性 默认值 说明/调整
    carbon.number.of.cores.while.loading
    默认值: 2. 这个值应该 >= 2
    数据加载时所用到核的个数。
    carbon.sort.size
    默认值: 100000. 这个值应该 >= 100.
    加载数据时在排序步骤中写入本地文件的阈值
    carbon.sort.file.write.buffer.size
    默认值: 50000.
    DataOutputStream 缓存。
    carbon.number.of.cores.block.sort
    默认值: 7
    如果你有足够的内存和 CPU,建议加大这个设置。
    carbon.merge.sort.reader.thread
    默认值: 3
    读取中间文件进行最终合并的最大线程数。
    carbon.merge.sort.prefetch
    默认值: true
    如果你没有足够的内存,建议将它设置为 false。

    比如,我们仅仅只有 16 个核,64GB 内存,但是有1000万条记录需要导入到 CarbonData 表中。使用默认配置总是在排序阶段失败,建议按照如下配置修改 carbon.properties:

    carbon.number.of.cores.block.sort=1
    carbon.merge.sort.reader.thread=1
    carbon.sort.size=5000
    carbon.sort.file.write.buffer.size=5000
    carbon.merge.sort.prefetch=false
    

    CarbonData 性能优化的配置

    最近我们在金融和电信领域使用 CarbonData 做了一些性能测试。它涉及详细的查询和聚合场景。影响性能的配置已经被确定,并归纳到以下表中 :

    属性 位置 使用场景 模式 训练
    carbon.sort.intermediate.files.limit
    spark/carbonlib/carbon.properties
    数据加载
    在数据加载时,排序过程中会用到一些中间文件。这个数字指定启动合并排序时需要的最小中间文件个数。
    将此值设置的更高有助于提高加载的性能。比如,当我们将这个值从 20 设置成 100,数据加载性能从 35MB/S 提高到超过 50MB/S。这个值越大,数据加载期间使用到的内存越多。
    carbon.number.of.cores.while.loading
    spark/carbonlib/carbon.properties
    数据加载
    指定在 CarbonData 加载数据期间用于数据处理的内核数量。
    如果你有很多的 CPU,那么你可以增加 CPUs 的个数,这将会提升性能。比如我们将这个值从 2 设置成 4,那么 CSV 的读性能提高大约一倍。
    carbon.compaction.level.threshold
    spark/carbonlib/carbon.properties
    数据加载和查询
    对于 minor compaction,指定阶段 1 要合并分段的数量和阶段 2 要合并的压缩分段的数量。
    每个 CarbonData 加载进程将会创建一个分段,如果每个加载进程生成的文件都很小,则会在一段时间内生成很多小文件,从而影响查询性能。配置这个参数会把小的段合并成一个大的段,它将对数据进行排序并提高性能。比如在电信的场景里,minor compaction 之后性能提高了 2 倍以上。
    spark.sql.shuffle.partitions
    spark/conf/spark-defaults.conf
    查询
    Spark 洗牌是启动任务的个数。
    这个值可以设置成 executor 核总数的 1 到 2倍。在一个聚合场景里,将这个值从 200 减少到 32,查询时间从 17 秒减少到 9 秒。
    spark.executor.instances/ spark.executor.cores/ spark.executor.memory
    spark/conf/spark-defaults.conf
    查询
    executors 和 CPU 核的个数,CarbonData 查询使用内存的大小。
    在银行场景里,我们为每个执行器提供 4 个核以及 15GB 内存得到了很不错的性能,这两个参数并不是越多越好,在资源有限的情况下需要正确配置。比如银行场景里,每个节点有 32 个核,但是只有 64GB 的内存,所以我们不能提供很多的核,但是只给很少的内存。比如每个执行器配置 4 核以及 12GB 内存。在查询过程中,有时会发生 GC,这会对查询性能产生 3 到 15秒以上的影响。这个场景下需要增加内存或者是减少核的个数。
    carbon.detail.batch.size
    spark/carbonlib/carbon.properties
    数据加载
    用于存储从块扫描返回的记录缓冲区大小。
    在使用 limit 场景下这个参数非常重要。比如你的查询限制为 1000,但是,如果我们将此值设置为 3000,这意味着我们从扫描中获得 3000 条记录,但 spark 只会获取 1000 行。所以剩下的 2000 是没用用到。在一次金融测试用例里,当我们将其设置为 100 之后,在查询限制为 1000 的情况下,相对于将这个值设置为 12000 能够得到 2 倍以上的性能提升。
    carbon.use.local.dir
    spark/carbonlib/carbon.properties
    数据加载
    是否使用 YARN 本地目录进行多表加载磁盘负载均衡
    如果这个值设置为 true,CarbonData 将使用 YARN 本地目录进行多表加载磁盘负载均衡,这将提升数据加载的性能。
    carbon.use.multiple.temp.dir
    spark/carbonlib/carbon.properties
    数据加载
    在表数据加载期间是否使用多个 YARN 本地目录来实现磁盘负载均衡。
    在启用 carbon.use.local.dir 之后,如果这个参数也设置为 true,CarbonData 将会在表数据加载期间是否使用所有 YARN 本地目录来实现磁盘负载均衡,这将提升数据加载的性能。在数据加载期间遇到磁盘热点问题时,请启用此属性。
    carbon.sort.temp.compressor
    spark/carbonlib/carbon.properties
    数据加载
    在数据加载的排序过程中指定压缩器来压缩中间排序的临时文件。
    可选的值为 'SNAPPY','GZIP','BZIP2','LZ4' 以及空。默认情况下,Carbondata 不会压缩排序生成的临时文件。如果遇到磁盘瓶颈时,设置此参数将非常有用。
    carbon.load.skewedDataOptimization.enabled
    spark/carbonlib/carbon.properties
    数据加载
    是否启用基于大小的块分配策略来加载数据。
    当加载数据时,carbondata 将使用基于文件大小的块分配策略进行任务分配。它将确保所有执行器处理相同大小的数据 -- 如果你的输入数据文件的大小差别很大(比如 1MB ~ 1GB)时很有用。

    注意: 如果你的 CarbonData 实例仅用于查询,你可以在 spark 配置文件设置 spark.speculation = true 属性。