本文介绍了Impala在3.3版本对元数据性能方面做的一些优化和改善,主要结合官方的文档和测试结果进行说明。
在之前的Impala版本中,每个coordinator都会在自己的内存中保存一份catalogd的全量元数据缓存,而这会消耗很大的内存,并且这些元数据缓存都会一直保存在coordinator中。 元数据信息是通过statestored服务来进行传播的,并且是顺序加载的,例如一个用户加载一个大表,会阻塞另一个用户加载一个小表。
使用该新功能,coordinator可以根据需要从catalogd中获取元数据,并将其缓存到本地,并且缓存的元数据也会在内存使用过高的情况下自动失效。
目前,按需获取元数据功能在coordinator和catalogd之间的传播粒度为分区级别。常见的像add/drop partition操作,不会引起不必要的元数据的序列化/反序列化。
按需获取元数据功能目前主要涉及到两个参数项配置:catalog_topic_mode需要配置在catalogd中;use_local_catalog需要配置在coordinator。根据catalog_topic_mode配置的不同,会有如下几种模式:
–catalog_topic_mode=minimal
–use_local_catalog=true
–catalog_topic_mode=mixed
对于需要开启按需获取元数据功能的coordinator节点配置:
–use_local_catalog=true
不需要开启此功能的配置:
–use_local_catalog=false
当我们开启了该功能之后,coordinator端的元数据缓存称之为LocalCatalog,相关的代码实现位于CatalogdMetaProvider.java文件中。其中缓存使用的是goole Guava提供的缓存库我们可以在coordinator配置如下的两个参数:
值得注意的是,如果开启了该功能,那么在coordinator的web页面,无法看到库/表的详细元数据信息,只有简单的库名和表名:
请注意,启用按需获取元数据功能后,不支持全局的INVALIDATE操作。
相关JIRA:IMPALA-7935、IMPALA-7469、IMPALA-7447、IMPALA-7137
注:由于该功能涉及到的改动比较多,因此这里列举出的JIRA可能不完整,请见谅。
在3.1版本中,Impala推出了元数据缓存自动失效功能,该功能可以限制元数据的大小,catalogd会定期扫描所有的表,并将最近未使用的表标记为失效状态。主要有以下两种策略:
通过在impalad和catalogd中配置invalidate_tables_timeout_s(单位是秒),如果表在该指定的时间段内没有使用,则catalogd会将该表的元数据缓存置为失效(即对表执行invalidate操作)
基于内存的元数据缓存失效策略有以下三个参数需要了解:
元数据缓存自动失效功能,通过在表中增加了一个最后访问时间lastUsedTime_,并且额外启动一个线程来不断扫描是否有表满足了以上的两个策略对应的条件,如果满足的话,则主动调用invalidateTable方法来使表的元数据缓存失效。注意,在使用元数据缓存自动失效功能的时候,最好将load_catalog_in_background参数设置为false,否则可能会影响该功能的使用。
元数据缓存自动失效功能,对于表很多,但是没有及时清理的场景非常合适,可以控制元数据缓存的大小,将不用的表及时从catalogd中去掉。但是也存在以下的问题:
相关JIRA:IMPALA-7448
在先前的Impala版本中,如果使用Hive/Spark进行了DDL/DML操作,例如create/drop,alter table add/drop partition等,Impala是无法主动感知这种变化的,需要我们手动提交invalidate metadata/refresh xxx命令。
在Impala的最新版本中,提供了对于元数据的自动invalidate/refresh。在启动该功能之后,通过配置hms_event_polling_interval_s参数项(默认为0,设置为正整数表示正常的轮训频率,官方建议设置小于5s),catalogd可以以指定的间隔轮询HMS的通知事件,并处理以下的变更操作:
注意:这是Impala 3.3中的预览功能,通常不可用。
以下情况目前是不支持的:
Seq((1, 2)).toDF("i", "j").write.save("/user/hive/warehouse/spark_etl.db/customers/date=01012019")
为了使用上面提到的元数据自动invalidate/refresh功能,我们需要在HMS中进行相应的配置,操作如下:
hive.metastore.transactional.event.listeners
org.apache.hive.hcatalog.listener.DbNotificationListener
hive.metastore.dml.events
true
目前,最新的Impala源码提供的mini cluster环境已经可以对该功能进行验证,在相应的测试HMS和HiveServer2服务对应的hive-site.xml中,我们可以看到上面提到的配置项(配置文件位于$IMPALA_HOME/fe/src/test/resources/)。当mini cluster都启动之后,我们可以通过beeline或者hive client创建测试表,然后连接至impala集群,查询新建的测试表是否已经被同步到impala。
将catalogd的hms_event_polling_interval_s参数设置为非0值之后,自动元数据同步功能就会对所有的库和表生效。如果希望对哪个库/表进行同步有更细粒度的控制,可以通过在库/表级别设置impala.disableHmsSync属性来禁用事件处理。
在DBPROPERTIES或者TBLPROPERTIES中,通过设置impala.disableHmsSync可以控制自动元数据同步功能的开关。impala.disableHmsSync这个属性的值,会决定特定的库/表是否会禁用事件处理。
CREATE DATABASE WITH DBPROPERTIES ('impala.disableHmsSync'='true');
CREATE TABLE WITH TBLPROPERTIES ('impala.disableHmsSync'='true' | 'false');
ALTER TABLE WITH TBLPROPERTIES ('impala.disableHmsSync'='true' | 'false');
如果同时设置了库和表的属性,则表级别的属性优先考虑。如果表级别的属性未设置,那么库级别的属性会进行考虑。
如果属性从true(表示跳过事件处理)改成了false(表示不跳过事件处理),则需要通过手动执行invalidate metadata来重置事件处理。因为事件处理器并不知道之前跳过了多少事件,也无法确定当前事件中的对象是否为最新的(个人对这段话的理解是,最开始为true的时候,事件处理器会一直跳过event,即使是设置false这个事件可能也会被跳过,所以需要手动INVALIDATE)。在这种情况下,事件处理器的状态会变成NEEDS_INVALIDATE。
同样,我们通过mini cluster可以对该功能进行验证,当我们使用hive client执行如下两条命令的时候:
CREATE TABLE student_test_01(id int) TBLPROPERTIES ('impala.disableHmsSync'='true');
CREATE TABLE student_test_02(id int) TBLPROPERTIES ('impala.disableHmsSync'='false');
通过impala shell连接查看,会发现student_test_01已经被同步,但是student_test_02没有被同步。
可以通过catalogd的webui(默认是http://hostname:25020)页面来查看事件处理器的状态。在WebUI有两个页面是跟自动元数据同步相关的,分别是:
这个页面提供了事件处理器metrics的详细视图,包括/metrics#events页面上列出的所有计数器的持续时间和速率指标的最小值,最大值,平均值,中位数。