常用技巧

本教程将指导你如何创建 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 属性。