处理步骤
3.8 CarbonData FAQ
3.8.1 为什么对 decimal 数据类型进行带过滤条件的查询时会出现异 常输出?
问题
当对decimal数据类型进行带过滤条件的查询时,输出结果不正确。
例如,
select * from carbon_table where num = 1234567890123456.22;
输出结果:
+---+---+--+
| name | num | +---+---+--+
| IAA | 1234567890123456.22 |
| IAA | 1234567890123456.21 | +---+---+--+
回答
为了得到准确的输出结果,需在数字后面加上“BD”。
例如,
select * from carbon_table where num = 1234567890123456.22BD;
输出结果:
+---+---+--+
| name | num | +---+---+--+
| IAA | 1234567890123456.22 | +---+---+--+
3.8.2 如何避免对历史数据进行 minor compaction?
问题
如何避免对历史数据进行minor compaction?
回答
如果要先加载历史数据,后加载增量数据,则以下步骤可避免对历史数据进行minor compaction:
1. 加载所有历史数据。
2. 将major compaction大小配置为小于历史数据segment大小的值。
3. 对历史数据进行一次major compaction,之后将不会考虑这些segments进行 minor compaction。
4. 加载增量数据。
5. 用户可以根据自己的需要配置minor compaction阈值。
配置示例和预期输出:
1. 用户将所有历史数据加载到CarbonData,此数据的一个segment的大小假定为 500GB。
2. 用户设置major compaction参数的阈值:“carbon.major.compaction.size” =
“491520(480gb * 1024)”。其中,491520可配置。
3. 运行major compaction。由于每个segment的大小超过配置值的大小,因此这些 segments将会被压缩。
4. 加载增量负载。
5. 配置minor compaction参数的阈值:“compaction.level.threshold” =
“6,6”。
6. 运行minor compaction。此时只考虑增量负载。
3.8.3 如何在 CarbonData 数据加载时修改默认的组名?
问题
如何在CarbonData数据加载时修改默认的组名?
回答
CarbonData数据加载时,默认的组名为“ficommon”。可以根据需要修改默认的组 名。
1. 编辑“carbon.properties”文件。
2. 根据需要修改关键字“carbon.dataload.group.name”的值。其默认值为
“ficommon”。
3.8.4 为什么 INSERT INTO CARBON TABLE 失败?
问题
为什么INSERT INTO CARBON TABLE命令无法在日志文件中记录以下信息?
Data load failed due to bad record
回答
在以下场景中,INSERT INTO CARBON TABLE命令会失败:
● 当源表和目标表的列数据类型不同时,源表中的数据将被视为Bad Records,则 INSERT INTO命令会失败。
● 源列上的aggregartion函数的结果超过目标列的最大范围,则INSERT INTO命令 会失败。
解决方法:
在进行插入操作时,可在对应的列上使用cast函数。
示例:
a. 使用DESCRIBE命令查询目标表和源表。
DESCRIBE newcarbontable; 结果:
col1 int col2 bigint
DESCRIBE sourcetable;
结果:
col1 int col2 int
b. 添加cast函数以将BigInt类型数据转换为Integer类型数据。
INSERT INTO newcarbontable select col1, cast(col2 as integer) from sourcetable;
3.8.5 为什么含转义字符的输入数据记录到 Bad Records 中的值与原 始数据不同?
问题
为什么含转义字符的输入数据记录到Bad Records中的值与原始数据不同?
回答
转义字符以反斜线"\"开头,后跟一个或几个字符。如果输入记录包含类似\t,\b,
\n,\r,\f,\',\",\\的转义字符,Java将把转义符'\'和它后面的字符一起处理得到转 义后的值。
例如:如果CSV数据类似“2010\\10,test”,将这两列插入“String,int”类型时,因 为“test”无法转换为int类型,表会将这条记录重定向到Bad Records中。但记录到 Bad Records中的值为“2010\10”,Java会将原始数据中的“\\”转义为“\”。
3.8.6 为什么 Bad Records 导致数据加载性能降低?
问题
为什么Bad Records导致数据加载性能降低?
回答
如果数据中存在Bad Records,并且“BAD_RECORDS_LOGGER_ENABLE”参数值为
“true”或“BAD_RECORDS_ACTION”参数值为“redirect”,则由于将失败原因写 入日志文件中或将Bad Records重定向到原始CSV文件中导致的额外的I/O开销,数据加 载性能就会降低 。
3.8.7 当初始 Executor 为 0 时,为什么 INSERT INTO/LOAD DATA 任务分配不正确,打开的 task 少于可用的 Executor?
问题
当初始Executor为0时,为什么INSERT INTO/LOAD DATA任务分配不正确,打开的 task少于可用的Executor?
回答
在这种场景下,CarbonData会给每个节点分配一个INSERT INTO或LOAD DATA任 务。如果Executor不是不同的节点分配的,CarbonData将会启动较少的task。
解决措施:
您可以适当增大Executor内存和Executor核数,以便YARN可以在每个节点上启动一个 Executor。具体的配置方法如下:
1. 配置Executor核数。
– 将“spark-defaults.conf”中的“spark.executor.cores”配置项或者“spark-env.sh”中的“SPARK_EXECUTOR_CORES”配置项设置为合适大小。
– 在使用spark-submit命令时,添加“--executor-cores NUM”参数设置核 数。
2. 配置Executor内存。
– 将“spark-defaults.conf”中的“spark.executor.memory”配置项或者
“spark-env.sh”中的“SPARK_EXECUTOR_MEMORY”配置项设置为合适大 小。
– 在使用spark-submit命令时,添加“--executor-memory MEM”参数设置内 存。
3.8.8 为什么并行度大于待处理的 block 数目时,CarbonData 仍需 要额外的 executor?
问题
为什么并行度大于待处理的block数目时,CarbonData仍需要额外的executor?
回答
CarbonData块分布对于数据处理进行了如下优化:
1. 优化数据处理并行度。
2. 优化了读取块数据的并行性。
为了优化并行数据处理及并行读取块数据,CarbonData根据块的局域性申请 executor,因此CarbonData可获得所有节点上的executor。
为了优化并行数据处理及并行读取块数据,运用动态分配的用户需配置以下特性。
1. 使用参数“spark.dynamicAllocation.executorIdleTimeout”并将此参数值设置为 15min(或平均查询时间)。
2. 正确配置参数“spark.dynamicAllocation.maxExecutors”,不推荐使用默认值
(2048),否则CarbonData将申请最大数量的executor。
3. 对于更大的集群,配置参数“carbon.dynamicAllocation.schedulerTimeout”为 10~15sec,默认值为5sec。
4. 配置参数“carbon.scheduler.minRegisteredResourcesRatio”为0.1~1.0,默认 值为0.8。只要达到此参数值,块分布可启动。
3.8.9 为什么在 off heap 时数据加载失败?
问题
为什么在off heap时数据加载失败?
回答
YARN Resource Manager将(Java堆内存 + “spark.yarn.am.memoryOverhead”)
作为内存限制,因此在off heap时,内存可能会超出此限制。您需配置参数
“spark.yarn.am.memoryOverhead”以增加memory。
3.8.10 为什么创建 Hive 表失败?
问题
为什么创建Hive表失败?
回答
当源表或子查询具有大数据量的Partition时,创建Hive表失败。执行查询需要很多的 task,此时输出的文件数就会很多,从而导致driver OOM。
可以在创建Hive表的语句中增加distribute by子句来解决这个问题,其中distribute by的字段要选取合适的cardinality(即distinct值的个数)。
distribute by子句限制了Hive表的Partition数量。增加distribute by 子句后,最终的 输出文件数取决于指定列的cardinality和“spark.sql.shuffle.partitions”参数值。但如 果distribute by的字段的cardinality值很小,例如,“spark.sql.shuffle.partitions”参 数值为200,但distribute by字段的cardinality只有100,则输出的200个文件中,只 有其中100个文件有数据,剩下的100个文件为空文件。也就是说,如果选取的字段的 cardinality过低,如1,则会造成严重的数据倾斜,从而严重影响查询性能。
因此,建议选取的distribute by字段的cardinality个数要大于
“spark.sql.shuffle.partitions”参数,可大于2~3倍。
示例:
create table hivetable1 as select * from sourcetable1 distribute by col_age;
3.8.11 为什么在 V100R002C50RC1 版本中创建的 CarbonData 表 不具有 Hive 特权为非所有者提供的特权?
问题
为什么在V100R002C50RC1版本中创建的CarbonData表不具有Hive特权为非所有者提 供的特权?
回答
Hive ACL在V100R002C50RC1版本之后实现,因此无法体现Hive ACL特权。
为了支持在V100R002C50RC1中创建的CarbonData表的HIVE ACL特权,必须由表的 所有者执行以下两个ALTER TABLE命令。
ALTER TABLE $dbname.$tablename SET LOCATION '$carbon.store/$dbname/
$tablename';
ALTER TABLE $dbname.$tablename SET SERDEPROPERTIES ('path'='$carbon.store/$dbname/$tablename');
示例:
假设数据库名称为"carbondb",表名为"carbontable",Carbon的储存位置为
“hdfs://hacluster/user/hive/warehouse/carbon.store”,执行如下命令:
ALTER TABLE carbondb.carbontable SET LOCATION 'hdfs://hacluster/user/hive/
warehouse/carbon.store/carbondb/carbontable';
ALTER TABLE carbondb.carbontable SET SERDEPROPERTIES ('path'='hdfs://
hacluster/user/hive/warehouse/carbon.store/carbondb/carbontable');
3.8.12 如何在不同的 namespaces 上逻辑地分割数据
问题
▪
fs.defaultFS - 默认文件系统的名称。URI模式必须设置为“viewfs”。当使用“viewfs”模式时,权限部分必须是“ClusterX”。
▪
fs.viewfs.mountable.ClusterX.homedir - 主目录基本路径。每个用户都 可以使用在“FileSystem/FileContext”中定义的getHomeDirectory()方 法访问其主目录。▪
fs.viewfs.mountable.default.link.<dir_name> - ViewFS安装表。示例:
– Hive和Spark中的配置
fs.defaultFS - 默认文件系统的名称。URI模式必须设置为“viewfs”。 当使 用“viewfs”模式时,权限部分必须是“ClusterX”。
● 命令格式:
LOAD DATA INPATH 'path to data' INTO TABLE table_name OPTIONS ('...');
说明
每当Spark配置有viewFS文件系统时,当尝试从HDFS加载数据时,用户必须在LOAD语句 中指定如“viewfs://”这样的路径或相对路径作为文件路径。
● 示例:
– viewFS路径举例:
LOAD DATA INPATH 'viewfs://ClusterX/dir/data.csv' INTO TABLE table_name OPTIONS ('...');
– 相对路径举例:
LOAD DATA INPATH '/apps/input_data1.txt' INTO TABLE table_name;
3.8.13 为什么 drop 数据库抛出 Missing Privileges 异常?
问题
为什么drop数据库抛出以下异常?
Error: org.apache.spark.sql.AnalysisException: Missing Privileges;(State=,code=0)
回答
当数据库的所有者执行drop database <database_name> cascade命令(包含其他 用户创建的表)时,会抛出此错误。
3.8.14 为什么在 Spark Shell 中不能执行更新命令?
问题
为什么在Spark Shell中不能执行更新命令?
回答
本文档中给出的语法和示例是关于Beeline的命令,而不是Spark Shell中的命令。
若要在Spark Shell中使用更新命令,可以使用以下语法。
● 语法1
<carbon_context>.sql("UPDATE <CARBON TABLE> SET (column_name1, column_name2, ... column_name n) = (column1_expression ,
column2_expression , column3_expression ... column n_expression) [ WHERE { <filter_condition> } ];").show
● 语法2
<carbon_context>.sql("UPDATE <CARBON TABLE> SET (column_name1, column_name2,) = (select sourceColumn1, sourceColumn2 from
sourceTable [ WHERE { <filter_condition> } ] ) [ WHERE { <filter_condition> } ];").show
示例:
如果CarbonData的context是“carbon”,那么更新命令如下:
carbon.sql("update carbonTable1 d set (d.column3,d.column5) = (select s.c33 ,s.c55 from sourceTable1 s where d.column1 = s.c11) where d.column1 = 'country' exists( select * from table3 o where o.c2 > 1);").show
3.8.15 如何在 CarbonData 中配置非安全内存?
问题
如何在CarbonData中配置非安全内存?
回答
在Spark配置中,“spark.yarn.executor.memoryOverhead”参数的值应大于 CarbonData配置参数“sort.inmemory.size.inmb” 与“Netty offheapmemory required”参数值的总和,或者“carbon.unsafe.working.memory.in.mb” 、
“carbon.sort.inememory.storage.size.in.mb” 与 “Netty offheapmemory required”参数值的总和。否则,如果堆外(off heap)访问超出配置的executor内 存,则YARN可能会停止executor。
“Netty offheapmemory required”说明:当“spark.shuffle.io.preferDirectBufs”设 为true时,Spark中netty 传输服务从"spark.yarn.executor.memoryOverhead"中拿掉 部分堆内存[~ 384 MB or 0.1 x 执行器内存]。
详细信息请参考常见配置executor堆外内存大小。
3.8.16 设置了 HDFS 存储目录的磁盘空间配额,CarbonData 为什 么会发生异常?
问题
设置了HDFS存储目录的磁盘空间配额,CarbonData为什么会发生异常。
回答
创建、加载、更新表或进行其他操作时,数据会被写入HDFS。若HDFS目录的磁盘空 间配额不足,则操作失败并抛出以下异常。
org.apache.hadoop.hdfs.protocol.DSQuotaExceededException: The DiskSpace quota of /user/tenant is exceeded: quota = 314572800 B = 300 MB but diskspace consumed = 402653184 B = 384 MB at
org.apache.hadoop.hdfs.server.namenode.DirectoryWithQuotaFeature.verifyStoragespaceQuota(DirectoryWit hQuotaFeature.java:211) at
org.apache.hadoop.hdfs.server.namenode.DirectoryWithQuotaFeature.verifyQuota(DirectoryWithQuotaFeatu re.java:239) at org.apache.hadoop.hdfs.server.namenode.FSDirectory.verifyQuota(FSDirectory.java:941) at org.apache.hadoop.hdfs.server.namenode.FSDirectory.updateCount(FSDirectory.java:745)
若发生此异常,请为租户配置足够的磁盘空间配额。
例如:
需要的磁盘空间配置可以按照如下方法计算:
如果HDFS的副本数为3, HDFS默认的块大小为128MB,则最小需要384MB的磁盘空 间用于写表的schema文件到HDFS上。计算公式:no. of block x block_size x
replication_factor of the schema file = 1 x 128 x 3 = 384 MB 说明
数据加载时,由于默认块大小为1024MB,每个fact文件需要的最小空间为3072MB。
3.8.17 为什么数据查询/加载失败,且抛出
“org.apache.carbondata.core.memory.MemoryException: Not enough memory”异常?
问题
为什么数据查询/加载失败,且抛出
“org.apache.carbondata.core.memory.MemoryException: Not enough memory”
异常?
回答
当执行器中此次数据查询和加载所需要的堆外内存不足时,便会抛出此异常。
在这种情况下,请增大“carbon.unsafe.working.memory.in.mb”和
“spark.yarn.executor.memoryOverhead”的值。
详细信息请参考如何在CarbonData中配置非安全内存?
该内存被数据查询和加载共享。所以如果加载和查询需要同时进行,建议将
“carbon.unsafe.working.memory.in.mb”和
“spark.yarn.executor.memoryOverhead”的值配置为2048 MB以上。
可以使用以下公式进行估算:
数据加载所需内存:
(“carbon.number.of.cores.while.loading”的值[默认值 = 6]) x 并行加载数据的表格 x (“offheap.sort.chunk.size.inmb”的值[默认值 = 64 MB] +
“carbon.blockletgroup.size.in.mb”的值[默认值 = 64 MB] + 当前的压缩率[64 MB/
3.5])
= ~900 MB 每表格 数据查询所需内存:
(SPARK_EXECUTOR_INSTANCES. [默认值 = 2]) x ( carbon.blockletgroup.size.in.mb [默认值 = 64 MB] +“carbon.blockletgroup.size.in.mb”解压内容[默认值 = 64 MB * 3.5]) x (每个执行器核数[默认值 = 1])
= ~ 600 MB