友情链接:
Orc transaction表是一种inceptor中可以支持CRUD操作的的ORC表,其基本原理是对于每个crud操作(insert,update,delete,merge into),都会生成一个对应版本,同时系统中存在compact机制对每个orc transaction进行compact,将多个版本合并成一个版本。
下面以具体例子来说明多版本与compact的过程,并基于这个例子展开诊断tips。
首先创建一张orc transaction表
create table orc_transaction_table(id int, value1 int, value2 int, value3 int) clustered by (id) into 2 buckets stored as orc tblproperties('transactional'='true');
建好表之后用desc formatted orc_transaction_table来获取该表在hdfs上的位置
通过hdfs命令来看当前表所在目录下的内容
可以看到表创建好时,目录是空的。
用insert语句向该表插入一条数据:
这时候再看表目录:
可以看到下面多了一个delta开始的目录,这种delta目录就对应了表的一个版本,delta中的数字代表该crud操作的transaction号。
用update命令更新该表并观察hdfs上的内容:
可见update操作为表添加了一个新的版本。
对于orc表的多个版本,inceptor系统中专门有compact机制来负责在合适的时候对多版本进行合并。
目前compact由metastore的compact thread在后台自动检测并合并。同时也可以通过命令alter table tablename compact compactType来手动触发compact,例如:
注意:alter table compact命令是异步的,该命令本身只是发出一个compact请求,其本身并不做compact操作,所以很快会结束。compactType有两种,分别是'major'和'minor,major compact之后,该表所有版本均被合并成一个新版本,而minor compact只是对部分版本合并,其结束后该表仍然有多个版本的存在。现在由于我们引入了orc crud列级优化,minor compact与这个优化不兼容,所以minor compact是默认disable的。
目前,compact任务根据配置可以是一个mapreduce任务,也可以是spark任务。
当
orc.compact.service.provider=metastore
时,compact threads内嵌在metastore中,compact任务是一个mapreduce任务,我们可以在yarn的8088页面上看到(compact任务的名称类似与test-02-23-compactor-crud001.orc_transaction_table)
当
orc.compact.service.provider=server
时,compact threads内嵌在server中,compact任务是一个spark任务,我们可以在spark的4040页面上看到(compact任务的sql类似于compact xxx ‘major’)
在compact任务成功结束之后,在观察hdfs上的内容:
可见major compact后,系统会产生一个base开始的目录,记录了到transaction号246405为止,该表的全部内容。
如果在往该表插入新的记录,则会生产新的delta版本:
一段时间之后在查看hdfs目录可以发现这两个版本被自动合并成了一个新版本:
这是compact thread在后台自动做的compact,目前后台的compact触发条件是:
这些触发条件都是可以配置的,分别对应于参数:
正常情况下,系统里orc transaction表大部分都会存在一个base目录,如果发现orc transaction表里有很多delta目录(>10)却没有自动compact,则说明该系统已经发生问题了,此时可以按照一下步骤来进行初步诊断。
1. 首先在inceptor里用select语句检查该表能否被正常的select,如果select出错,则问题定位为orc表本身的问题。如果能select出来则说明compact系统出现问题;
2. compact系统出现问题时,首先查看compact所在服务的进程的jstack,检查里面是否有以下3种thread:
a. Initiator thread: 负责检查每个orc transaction表是否符合compact条件
b. Worker thread: 负责向yarn提交mapreduce任务对表进行compact
c. Cleaner thread: 负责清除冗余的版本,例如上面的例子中生成base_0246405后delta_0246404_0246404与delta_0246405_0246405就可以被删除掉了
如果没有initiator thread,系统不能对表进行自动的compact,但通过alter table还能手动触发compact,如果没有worker thread,系统将无法进行compact,这两种情况都会导致orc transaction表的相关信息在metastore里面积压,大幅影响系统性能甚至会导致系统挂掉。cleaner thread相对比较不重要,但是没有cleaner,hdfs上就会有太多冗余版本,故我们应该保证metastore进程中这三种thread都是处于正常状态,如果发现metastore中少了某个thread,应该重启metastore。
以metastore的jstack为例,这些thread在jstack的表现如下:
3. 如果compact所在进程中这三种thread都处于正常状态,对于基于mapreduce的compact,还要检查yarn上compact任务是否正常,之前碰到的情况是yarn分配给inceptor的资源太多,导致compact任务一直无法完成,碰到这种情况需要调整yarn的资源分配来确保有足够的资源进行compact。
4.对于带分区(partition)的ORC事务表,可以使用以下命令手动出发compaction:
4.1 单值分区(singl-key partition)
alter table single_key_partition_table partition col compact 'major'; //对partition spec col 进行compact;
alter table single_key_partition_table partition(col='value') compact 'major'; //对partition spec col=value 进行compact;
4.2 多值分区表(multi-key partition)
alter table multi_key_partition_table partition(col1='value1', col2='value2') compact 'major';
alter table multi_key_partition_table partition col compact 'major'; //对partition spec col 进行compact;
4.3 单值范围分区(single-key and range partition )
alter table range_partition_table partition part_key compact 'major'; -- 其中的单引号' ' 是需要的。
5.手动合并失败,查看metastore中的日志报错如下:
这是因为表已经进入了黑名单,进入黑名单的表是不能合并的。
进入黑名单是因为之前自动合并失败很多次,需要手动从黑名单中释放。
alter table table_name_xxxxxx enable compact; -- 'table_name_xxxxxx'替换为表名
为了保证上述语句运行成功,防止delta数量过多的极端情况下合并失败,需要适当调整参数来设置一次性合并的delta版本数量上限:
SET hive.compactor.max.num.delta=50; -- 默认值为500
如果一个表或者分区在多次尝试compact并且失败,compaction 服务会认为后续再对这个表或分区compact同样会失败。为了避免浪费资源,comapction服务会将这个表或分区加入compaction blacklist。
目前失败次数由参数orc.compact.blacklist.threshold控制,默认值是3。
表或分区一旦加入黑名单,无论自动或手动触发compaction,都不会执行compact操作。
目前还没有从compaction blacklist中自动移除的机制。
可以在beeline通过以下命令查看:
show compact blacklist
如果将某个表或分区从compaction blacklist中移除,可以通过:
在beeline,从blacklist中移除某个表或分区,执行
也可以在mysql中,直接删除COMPACTION_BLACKLIST中记录
可以手动将某个表或分区加入黑名单,不让其做compaction。