背景介紹
Kylin 作為OLAP中主流的框架之一,其優勢是在於利用Cube對數據做預計算。在離線計算的場景中,數據源為Hive表,使用Spark/MR對源數據進行折疊,將結果存儲在HBase中。用戶在查詢的時候,元數據使用的是折疊后的維度(同步自Hive),實際查詢的是HBase的結果。
這就帶來了一個問題,某些場景下,用戶需要查詢折疊前的原始數據作為樣本,或者查詢未經折疊的列,Kylin就無法很好的支持了。
v2.3.0之前的版本,Kylin measure中有RAW這個函數,支持在HBase中存儲原始列的值。但是經過社區的討論,將RAW隱藏起來了,主要的理由是當cell中列數據過大,容易引起BufferOverflow,這個問題到現在也沒有很好解決,只能通過修改RowConstants.ROWVALUE_BUFFER_SIZE的值。
具體討論如下:
RAW measure in Apache Kylin
[Discuss] Disable/hide "RAW" measure in Kylin web GUI
Grow ByteBuffer Dynamically in Cube Building and Query
因此,尋找一個合適且高效的方法,用來完成特定查詢就顯得很重要了。
Kylin支持將不在預計算之中的查詢下推到Hive中,這種方式很符合目前的使用場景。但是,Hive的計算需要向Yarn申請資源,耗費大量的時間,使得稍微復雜的查詢在1min以上。通過調研Kylin查詢下壓的方式和官網對於配置的介紹,發現理論上支持所有JDBC連接方式的查詢引擎,例如Impala和Presto。
因為生產環境沒有Presto,只好使用Impala來測試一下了。
相關配置
1.修改kylin.properties
vim $KYLIN_HOME/conf/kylin.properties
#### QUERY PUSH DOWN ###
#
kylin.query.pushdown.runner-class-name=org.apache.kylin.query.adhoc.PushDownRunnerJdbcImpl
#
##kylin.query.pushdown.update-enabled=false
kylin.query.pushdown.jdbc.url=jdbc:impala://<impala-daemon-ip>:21050/default
kylin.query.pushdown.jdbc.driver=com.cloudera.impala.jdbc41.Driver
kylin.query.pushdown.jdbc.username=root
##kylin.query.pushdown.jdbc.password=
#
kylin.query.pushdown.jdbc.pool-max-total=150
kylin.query.pushdown.jdbc.pool-max-idle=100
kylin.query.pushdown.jdbc.pool-min-idle=50
2.下載並添加Impala依賴
Impala JDBC Connector 2.6.12 for Cloudera Enterprise
unzip ClouderaImpala_JDBC_2.6.12.1013.zip
cd ClouderaImpala_JDBC_2.6.12.1013
unzip ClouderaImpalaJDBC41-2.6.12.1013.zip
mv ImpalaJDBC41.jar $KYLIN_HOME/lib
3.重啟Kylin
修改代碼
1.經過壓力測試,發現並發數並不是很理想,通過jstack分析,存在死鎖,修改部分代碼,死鎖消失。目前並發數在每秒50左右(SELECT *)。
(此修改未經過功能測試,僅做參考)
JdbcPushDownConnectionManager
public Connection getConnection() {
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
2.如果需要支持任意無法匹配的SQL下壓,需要修改以下代碼
PushDownUtil
private static Pair<List<List<String>>, List<SelectedColumnMeta>> tryPushDownQuery(String project, String sql,
String defaultSchema, SQLException sqlException, boolean isSelect, boolean isPrepare) throws Exception {
KylinConfig kylinConfig = ProjectManager.getInstance(KylinConfig.getInstanceFromEnv()).getProject(project).getConfig();
if (!kylinConfig.isPushDownEnabled())
return null;
if (isSelect) {
logger.info("Query failed to utilize pre-calculation, routing to other engines", sqlException);
if (!isExpectedCause(sqlException)) {
logger.info("quit doPushDownQuery because prior exception thrown is unexpected");
// 注釋該行,使得所有無法解析的SQL均下壓,如果SQL出錯,會在下壓引擎中報錯
// return null;
}
} else {
Preconditions.checkState(sqlException == null);
logger.info("Kylin cannot support non-select queries, routing to other engines");
}
...