1. 程式人生 > >kylin調優,專案中錯誤總結,知識點總結,kylin jdbc driver + 資料庫連線池druid + Mybatis專案中的整合,shell指令碼執行kylin restapi 案例

kylin調優,專案中錯誤總結,知識點總結,kylin jdbc driver + 資料庫連線池druid + Mybatis專案中的整合,shell指令碼執行kylin restapi 案例

關於本篇文章的說明:
本篇文章為筆者辛苦勞作用了一整天總結出來的文件,大家閱讀轉發的時候請不要吝嗇寫上筆者:塗作權 和 原文地址。

由於筆者所在環境沒有人用過kylin,筆者也是自學官網,閱讀書籍 將kylin用於實際專案,期間遇到了很多很多關於kylin使用的問題。為了讓後面的人在使用kylin實踐的時候能夠少走彎路,在此生成kylin的調優,錯誤總結,知識點文件,這篇文件應該是目前網上最全的kylin調優和總結文件了(除了官網)。

以下文章內容主要來自官網,書籍,博文,網友,社群,同學,以及實際專案。

1 調優方案

1.1 調優:如何提高訪問連線併發(運維層面)

根據書籍中的介紹,kylin單個的例項,支援的訪問連線併發是70個左右,所以,為了讓kylin能夠支援更多的訪問併發,可以通過增加例項的方式實現。將單例項的Kylin變成叢集方式,增加query節點的個數。
官網介紹的方式:
http://kylin.apache.org/docs/install/kylin_cluster.html
在這裡插入圖片描述
說明:
A:假設有3臺機器,分別是machine1,machine2,machine3。其中Machine的執行模式是all(即擁有 執行job+執行query的角色 (個人理解)),另外的machine2和machine3為query(主要用於查詢)。
B:注意,kylin2.0以後,kylin支援了多個job的方式,具體方式可以參考文件進行相關配置。

1.2 調優:解決kylin預處理過程gc問題(運維層面)

Kylin是基於預處理技術,如果公司資金雄厚,伺服器配置高,記憶體大,那就不要吝嗇記憶體了。給kylin足夠的記憶體分配,能夠減少很多問題。

如果處理的好,可以結合任務排程系統,比如azkaban,通過shell的方式將kylin的記憶體在資料處理空閒的時候,將記憶體多分配給kylin。

關於此部分的介紹,官網給出的建議是:
http://kylin.apache.org/docs/install/configuration.html

Allocate More Memory for Kylin
There are two sample settings for KYLIN_JVM_SETTINGS are given in $KYLIN_HOME/conf/setenv.sh.
The default setting use relatively less memory. You can comment it and then uncomment the next line to allocate more memory for Kyligence Enterprise. The default configuration is:

Export KYLIN_JVM_SETTINGS="-Xms1024M -Xmx4096M -Xss1024K -XX`MaxPermSize=512M -verbose`gc -XX`+PrintGCDetails -XX`+PrintGCDateStamps -Xloggc`$KYLIN_HOME/logs/kylin.gc.$$ -XX`+UseGCLogFileRotation - XX`NumberOfGCLogFiles=10 -XX`GCLogFileSize=64M"
# export KYLIN_JVM_SETTINGS="-Xms16g -Xmx16g -XX`MaxPermSize=512m -XX`NewSize=3g -XX`MaxNewSize=3g -XX`SurvivorRatio=4 -XX`+CMSClassUnloadingEnabled -XX`+CMSParallelRemarkEnabled -XX`+UseConcMarkSweepGC -XX `+CMSIncrementalMode -XX`CMSInitiatingOccupancyFraction=70 -XX`+UseCMSInitiatingOccupancyOnly -XX`+DisableExplicitGC -XX`+HeapDumpOnOutOfMemoryError -verbose`gc -XX`+PrintGCDetails -XX`+PrintGCDateStamps -Xloggc`$KYLIN_HOME/logs/kylin.gc. $$ -XX`+UseGCLogFileRotation -XX`NumberOfGCLogFiles=10 -XX`GCLogFileSize=64M"

筆者配置:

[xxx conf]# pwd
/data/installed/apache-kylin-2.3.1-bin/conf
[xxxx conf]# vim setenv.sh

在這裡插入圖片描述

1.3 調優+錯誤總結:配置build引擎支援Spark (運維層面)

在kylin中支援以Spark作為預處理的方式,在記憶體足夠的情況下,建議配置build引擎。使用Spark,預設的build引擎使用的是mapreduce.

由於筆者使用的hadoop版本是3.0.1(原生),當前最高版本是:v2.5.2,發現使用Kylin的時候,會報jar衝突問題,因為我環境使用的是3.x的jar包,但是在kylin發行版本目前還使用的是基於hadoop2.x的Spark。所以失敗了。

但是,若使用的是CDH,可以使用,apache-kylin-2.5.2-bin-cdh60.tar.gz for beta版本進行安裝試用。

支援Spark的配置:http://kylin.apache.org/docs/tutorial/cube_spark.html,關於具體步驟,本文不進行詳細敘述。

1.4 調優:kylin出現reduce階段記憶體異常問題(hadoop運維層面)

在kylin執行cube build的過程中,可能會出現記憶體溢位的問題,這個問題其中一個原因是hadoop的虛擬引數配置不合理導致的。
這裡在$HADOOP_HOME/etc/Hadoop/yarn-site.xml 中的配置類似如下:

<!--是否啟動一個執行緒檢查每個任務正使用的虛擬記憶體量,如果任務超出分配值,則直接將其殺掉,預設是true-->
<property>
    <name>yarn.nodemanager.vmem-check-enabled</name>
    <value>false</value>
</property>
<!-- 任務每使用1MB實體記憶體,最多可使用虛擬記憶體,預設是2.1 -->
<property>
    <name>yarn.nodemanager.vmem-pmem-ratio</name>
    <value>5</value>
</property>

<!-- 每個節點可用記憶體,單位MB  -->
<property>
     <name>yarn.nodemanager.resource.memory-mb</name>
     <!--<value>16384</value>-->
     <value>20480</value>
     <discription>每個節點可用記憶體,單位MB</discription>
</property>

<!-- 單個任務可申請最少記憶體,預設1024MB  -->
<property>
     <name>yarn.scheduler.minimum-allocation-mb</name>
     <value>1024</value>
</property>

<!-- 單個任務可申請最大記憶體,預設8192MB  -->
<property>
     <name>yarn.scheduler.maximum-allocation-mb</name>
     <!--<value>16384</value>-->
     <value>20480</value>
</property>

yarn.nodemanager.vmem-pmem-ratio :虛擬記憶體大小的一個係數,通過調整這個引數,可以增大虛擬記憶體的值,避免kylin在cube build的過程中出現失敗。

此外,也要調整:$HADOOP_HOME/etc/Hadoop/mapred-site.xml中如下的值:

<property>
     <name>mapreduce.map.java.opts</name>
     <!--<value>-Xms3g -Xmx6g</value>-->
     <value>-Xms3g -Xmx10g</value>
</property>
<property>
     <!-- mapreduce.reduce.java.opts 這個值一般是mapreduce.map.java.opts的兩倍 -->
     <name>mapreduce.reduce.java.opts</name>
     <!--<value>-Xms6g -Xmx12g</value>-->
     <value>-Xms6g -Xmx16g</value>
</property>

<!-- 每個Map任務的實體記憶體限制,這個值 * yarn.nodemanager.vmem-pmem-ratio  就是虛擬記憶體的大小-->
<property>
      <name>mapreduce.map.memory.mb</name>
      <!--<value>6144</value>-->
      <value>10240</value>
</property>
<property>
      <name>mapreduce.reduce.input.buffer.percent</name>
      <value>0.5</value>
</property>

<!-- 每個Reduce任務的實體記憶體限制,一般還是機器記憶體的80%  -->
<property>
      <name>mapreduce.reduce.memory.mb</name>
      <!--<value>12288</value>-->
      <value>16384</value>
</property>

其中官網的介紹是:
在這裡插入圖片描述

1.5 將cuboid資料轉為HFile

這一步啟動一個MR任務來講cuboid檔案(序列檔案格式)轉換為HBase的HFile格式。Kylin通過cube統計資料計算HBase的region數目,預設情況下每5GB資料對應一個region。Region越多,MR使用的reducer也會越多。如果你觀察到reducer數目較小且效能較差,你可以將“conf/kylin.properties”裡的以下引數設小一點,比如:

kylin.hbase.region.cut=2
kylin.hbase.hfile.size.gb=1

如果你不確定一個region應該是多大時,聯絡你的HBase管理員。

1.6 調優:解決kylin cube過程中的hive小檔案問題(運維層面)

Kylin中自帶檔案合併,下面的過程可以考慮設定(這個筆者沒有驗證過,有的博文中建議下面方式進行設定,但是官網是另外一種說法)
官網:
在這裡插入圖片描述
一些博文上的寫法:

[xxx conf]# pwd
/xxxx/apache-kylin-2.3.1-bin/conf
[xxxx conf]# vim kylin_hive_conf.xml 

該檔案原本的配置如下:

<property>
    <name>hive.merge.mapfiles</name>
    <value>false</value>
    <description>Disable Hive's auto merge</description>
</property>

<property>
    <name>hive.merge.mapredfiles</name>
    <value>false</value>
    <description>Disable Hive's auto merge</description>
</property>

修改成:

<property>
    <name>hive.merge.mapfiles</name>
    <value>true</value>
    <description>Enable Hive's auto merge</description>
</property>

<property>
    <name>hive.merge.mapredfiles</name>
    <value>true</value>
    <description>Enable Hive's auto merge</description>
</property>

1.7 調優:hive建表過程(數倉層面)

kylin使用的是一種預處理方式,這種方式有別於hive、spark-sql、presto、hbase、impala、druid等的即時查詢方案,kylin能夠在機器記憶體配置較少的情況下完成多維查詢,對於有多維分析需求(OLAP)的專案,是一個很不錯的選擇。

但是,不要覺得kylin在調優過程中只要保證了kylin的model和cube建立的好就能夠提升kylin的大大效率。對於kylin的資料來源hive中的hive表建立不好,會導致kylin cube build過程很漫長,這個筆者深有體會,優化的好的能夠將build過程由1天多減少到分鐘級別。

使用kylin進行多維查詢,能夠讓不熟悉HBASE二級索引,預分割槽,HBASE調優,協處理等的開發人員減少很多時間。

在此,筆者建議kylin的hive資料表在建立的時候增加分割槽(partitioned),筆者的與分割槽格式類似如下:

drop table if exists tb_table;
CREATE TABLE IF NOT EXISTS tb_table
(
Xxxxxxx  此處建表語句略去,
addTime bigint comment '資料生成的時間,時間戳,秒值',
createDate bigint comment '建立天,時間格式為yyyyMMdd的integer值,由addTime通過from_unixtime(actionTime,'yyyyMMdd') as createDate 得出'
)
partitioned by(pt_createDate integer comment '建立天,時間格式為yyyyMMdd的integer值,分割槽時間') 
ROW FORMAT DELIMITED 
FIELDS TERMINATED BY '\t' 
LINES TERMINATED BY '\n' 
STORED AS TEXTFILE;

其中pt_createDate 是資料入庫時間。這個值很重要,在建立Model的時候,一定要使用這個時間作為partition,而不要使用資料生成時間createDate,否則可能會出現hive中的資料在kylin增量預處理之後,kylin的資料條數小於hive的資料條數,導致分析結果偏少的問題。

1.8 調優:hive表資料型別導致kylin統計如sum出錯的問題(數倉層面)

在hive進行sum的時候,有時候發現不管怎麼設定,資料值總是1或者一些莫名其妙的值,導致這個現象的其中一個原因就是使用了hive中一個數據型別定義為tinyint的列作為度量列。所以,在使用hive建表的時候,可以將這種欄位設定成integer,然後再進行處理,發現結果正確了。
類似:

is_active_member integer comment '是否是活躍會員,1:是,0不是',   由之前的tinyint改成integer

1.9 調優:group by 欄位值,計算每個分組sum的查詢速度調優(數倉層面)

kylin有一個坑,可能是設計問題,就是kylin對sum(case when 欄位列 then 1 else 0 end) totalNum的支援很爛,它不支援。

為了處理這種場景,建議對所有以上場景或者類似group by然後計算sum結果的場景,都在資料處理結果,將這種結果1 or 0的狀態計算好,儲存在hive表中。類似筆者的一個Spark sql程式片段:

spark.sql("INSERT INTO TABLE tb_table partition(pt_createDate=" + pt_createDate + ") " +
  "SELECT " +
  "    (case when st.registWay=10 then 1 else 0 end) as selfRegiste," +
  "    (case when st.registWay=20 then 1 else 0 end) as agentRegiste," +
  "    (case when st.registWay=30 then 1 else 0 end) as youxShopRegiste," +
  "    (case when st.registWay=40 then 1 else 0 end) as salesmanRegiste," +
  "    (case when st.registWay=50 then 1 else 0 end) as headShopRegiste," +
  "    from_unixtime(registTime,'yyyyMMdd') as createDate " +
  "FROM " +
  "    tb_table_temp "
  );
spark.stop();

也就是說將registWay 的分組求總和統計變成 selfRegiste 、agentRegiste 、youxShopRegiste、salesmanRegiste、headShopRegiste 的sum求和。通過這種方式之後,發現專案查詢速度有很大的提升,可能有原來的n秒級,變成毫秒級別。

1.10 調優:使用和hive相同的partition column

在建立model的時候,指定類似如下的分割槽列:
在這裡插入圖片描述
使用增量build cube的方式。

1.11 調優:定期清理Kylin cube build過程中產生的中間檔案

在kylin 在cube build過程中會產生很多臨時檔案,現象是:在hdfs中的/hbase/data/default,會產生很多時間為過往時間的檔案,
在這裡插入圖片描述
可以使用一下命令檢視磁碟佔用大小:

[xxxx apache-kylin-2.3.1-bin]# hdfs dfs -du -s -h /hbase/data/default
WARNING: HADOOP_PREFIX has been replaced by HADOOP_HOME. Using value of HADOOP_PREFIX.

## 13.1 G  35.9 G  /hbase/data/default
[xxxx apache-kylin-2.3.1-bin]#

其中:13.1 G 表示的是一個節點中暫用磁碟的大小,35.9 G

如果這個臨時中間檔案不處理,最終將導致http://namenodeip:hdfs對應的port/dfshealth.html#tab-datanode:
在這裡插入圖片描述

官網介紹:
Kylin 在構建 cube 期間會在 HDFS 上生成中間檔案;除此之外,當清理/刪除/合併 cube 時,一些 HBase 表可能被遺留在 HBase 卻以後再也不會被查詢;雖然 Kylin 已經開始做自動化的垃圾回收,但不一定能覆蓋到所有的情況;你可以定期做離線的儲存清理:
步驟:
1. 檢查哪些資源可以清理,這一步不會刪除任何東西:

export KYLIN_HOME=/path/to/kylin_home
${KYLIN_HOME}/bin/kylin.sh org.apache.kylin.tool.StorageCleanupJob --delete false

請將這裡的 (version) 替換為你安裝的 Kylin jar 版本。
2. 你可以抽查一兩個資源來檢查它們是否已經沒有被引用了;然後加上“–delete true”選項進行清理。

${KYLIN_HOME}/bin/kylin.sh org.apache.kylin.tool.StorageCleanupJob --delete true

完成後,Hive 裡的中間表, HDFS 上的中間檔案及 HBase 中的 HTables 都會被移除。
3. 如果您想要刪除所有資源;可新增 “–force true” 選項:

${KYLIN_HOME}/bin/kylin.sh org.apache.kylin.tool.StorageCleanupJob --force true --delete true

完成後,Hive 中所有的中間表, HDFS 上所有的中間檔案及 HBase 中的 HTables 都會被移除。

1.12 調優:減少Cube Dimensions維度數

做多維資料分析的時候,一般都要涉及到SQL,在這個過程中適當控制一些SQL,使用盡可能少的欄位列以實現相同的資料查詢需求。
因為維度列越多,cuboid的數量越多,需要的記憶體越多,cube build的時候時間也越長,生成的資料也越大。對於有n個維度的cube,組合字後會產生22…*(第n個2)體量的資料。
也就是說減少如下的Dimensions數量:
在這裡插入圖片描述

1.13 調優:定義measure列

對於定義measure,結果將在cube build前就預處理好,作為度量列的欄位不要在Cube的Dimensions中出現,以減少Cuboid的數量 。這裡包括兩處:
A:Model建立過程中指定好Measures列,例如:
在這裡插入圖片描述
B:增加Cube Measures列的值
在這裡插入圖片描述

1.14 調優+錯誤總結:解決sum的時候結果莫名其妙的問題

出現這個現象的原因是在該定義measure的列上沒有定義相關的度量值。具體新增方式如上面的:定義measure列

1.15 調優:定期merge cube

在kylin的model下的cube後見面的:
在這裡插入圖片描述
另外:設定好合適的Merge週期
在這裡插入圖片描述

1.16 調優:對於維度多於12個場景

在Advanced Setting中對維度進行Aggregation Groups分組。
也就是說在下面的維度列進行分組設定。
在這裡插入圖片描述
每組只填寫好真正需要的維度列。新增新的分組的時候,可以使用:
在這裡插入圖片描述

在設定的時候一定要記著2的n次方這個問題。儘可能減少n(維度數量)這個值。

1.17 調優:建立中間平表(來自官網)

這一步將資料從源Hive表提取出來(和所有join的表一起)並插入到一箇中間平表。如果Cube是分割槽的,Kylin會加上一個時間條件以確保只有在時間範圍內的資料才會被提取。你可以在這個步驟的log檢視相關的Hive命令,比如:

hive -e "USE default;
DROP TABLE IF EXISTS kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34;

CREATE EXTERNAL TABLE IF NOT EXISTS kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34
(AIRLINE_FLIGHTDATE date,AIRLINE_YEAR int,AIRLINE_QUARTER int,...,AIRLINE_ARRDELAYMINUTES int)
STORED AS SEQUENCEFILE
LOCATION 'hdfs:///kylin/kylin200instance/kylin-0a8d71e8-df77-495f-b501-03c06f785b6c/kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34';

SET dfs.replication=2;
SET hive.exec.compress.output=true;
SET hive.auto.convert.join.noconditionaltask=true;
SET hive.auto.convert.join.noconditionaltask.size=100000000;
SET mapreduce.job.split.metainfo.maxsize=-1;

INSERT OVERWRITE TABLE kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34 SELECT
AIRLINE.FLIGHTDATE
,AIRLINE.YEAR
,AIRLINE.QUARTER
,...
,AIRLINE.ARRDELAYMINUTES
FROM AIRLINE.AIRLINE as AIRLINE
WHERE (AIRLINE.FLIGHTDATE >= '1987-10-01' AND AIRLINE.FLIGHTDATE < '2017-01-01');

在Hive命令執行時,Kylin會用conf/kylin_hive_conf.properties裡的配置,比如保留更少的冗餘備份和啟用Hive的mapper side join。需要的話可以根據叢集的具體情況增加其他配置。

如果cube的分割槽列(在這個案例中是”FIGHTDATE”)與Hive表的分割槽列相同,那麼根據它過濾資料能讓Hive聰明地跳過不匹配的分割槽。因此強烈建議用Hive的分割槽列(如果它是日期列)作為cube的分割槽列。這對於那些資料量很大的表來說幾乎是必須的,否則Hive不得不每次在這步掃描全部檔案,消耗非常長的時間。

1.18 調優:重新分發中間表(來自官網)

在之前的一步之後,Hive在HDFS上的目錄裡生成了資料檔案:有些是大檔案,有些是小檔案甚至空檔案。這種不平衡的檔案分佈會導致之後的MR任務出現數據傾斜的問題:有些mapper完成得很快,但其他的就很慢。針對這個問題,Kylin增加了這一個步驟來“重新分發”資料,這是示例輸出:

total input rows = 159869711
expected input rows per mapper = 1000000
num reducers for RedistributeFlatHiveTableStep = 160

重新分發表的命令:

hive -e "USE default;
SET dfs.replication=2;
SET hive.exec.compress.output=true;
SET hive.auto.convert.join.noconditionaltask=true;
SET hive.auto.convert.join.noconditionaltask.size=100000000;
SET mapreduce.job.split.metainfo.maxsize=-1;
set mapreduce.job.reduces=160;
set hive.merge.mapredfiles=false;

INSERT OVERWRITE TABLE kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34 SELECT * FROM kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34 DISTRIBUTE BY RAND();
"

首先,Kylin計算出中間表的行數,然後基於行數的大小算出重新分發資料需要的檔案數。預設情況下,Kylin為每一百萬行分配一個檔案。在這個例子中,有1.6億行和160個reducer,每個reducer會寫一個檔案。在接下來對這張表進行的MR步驟裡,Hadoop會啟動和檔案相同數量的mapper來處理資料(通常一百萬行資料比一個HDFS資料塊要小)。如果你的日常資料量沒有這麼大或者Hadoop叢集有足夠的資源,你或許想要更多的併發數,這時可以將conf/kylin.properties裡的kylin.job.mapreduce.mapper.input.rows設為小一點的數值,比如:

kylin.job.mapreduce.mapper.input.rows=500000

其次,Kylin會執行 “INSERT OVERWRITE TABLE … DISTRIBUTE BY “ 形式的HiveQL來分發資料到指定數量的reducer上。

在很多情況下,Kylin請求Hive隨機分發資料到reducer,然後得到大小相近的檔案,分發的語句是”DISTRIBUTE BY RAND()”。

如果你的cube指定了一個高基數的列,比如”USER_ID”,作為”分片”維度(在cube的“高階設定”頁面),Kylin會讓Hive根據該列的值重新分發資料,那麼在該列有著相同值的行將被分發到同一個檔案。這比隨機要分發要好得多,因為不僅重新分佈了資料,並且在沒有額外代價的情況下對資料進行了預先分類,如此一來接下來的cube build處理會從中受益。在典型的場景下,這樣優化可以減少40%的build時長。在這個案例中分發的語句是”DISTRIBUTE BY USER_ID”:

請注意: 1)“分片”列應該是高基數的維度列,並且它會出現在很多的cuboid中(不只是出現在少數的cuboid)。 使用它來合理進行分發可以在每個時間範圍內的資料均勻分佈,否則會造成資料傾斜,從而降低build效率。典型的正面例子是:“USER_ID”、“SELLER_ID”、“PRODUCT”、“CELL_NUMBER”等等,這些列的基數應該大於一千(遠大於reducer的數量)。 2)”分片”對cube的儲存同樣有好處,不過這超出了本文的範圍。

1.19 調優:提取事實表的唯一列(來自官網)

在這一步驟Kylin執行MR任務來提取使用字典編碼的維度列的唯一值。
實際上這步另外還做了一些事情:通過HyperLogLog計數器收集cube的統計資料,用於估算每個cuboid的行數。如果你發現mapper執行得很慢,這通常表明cube的設計太過複雜,請參考

優化cube設計來簡化cube。如果reducer出現了記憶體溢位錯誤,這表明cuboid組合真的太多了或者是YARN的記憶體分配滿足不了需要。如果這一步從任何意義上講不能在合理的時間內完成,你可以放棄任務並考慮重新設計cube,因為繼續下去會花費更長的時間。

你可以通過降低取樣的比例(kylin.job.cubing.inmen.sampling.percent)來加速這個步驟,但是幫助可能不大而且影響了cube統計資料的準確性,所有我們並不推薦。

1.20 調優:構建維度字典(來自官網)

有了前一步提取的維度列唯一值,Kylin會在記憶體裡構建字典。通常這一步比較快,但如果唯一值集合很大,Kylin可能會報出類似“字典不支援過高基數”。對於UHC型別的列,請使用其他編碼方式,比如“fixed_length”、“integer”等等。

1.21 調優:構建基礎cuboid,調整map大小 和reduce的數量

這一步用Hive的中間表構建基礎的cuboid,是“逐層”構建cube演算法的第一輪MR計算。Mapper的數目與第二步的reducer數目相等;Reducer的數目是根據cube統計資料估算的:預設情況下每500MB輸出使用一個reducer;如果觀察到reducer的數量較少,你可以將kylin.properties裡的“kylin.job.mapreduce.default.reduce.input.mb”設為小一點的數值以獲得過多的資源,比如:

kylin.job.mapreduce.default.reduce.input.mb=200

1.22 調優:設定好Mandatory Dimensions 列

這種維度意味著每次查詢的group by中都會攜帶的,將某一個dimension設定為mandatory可以將cuboid的個數減少一半

因為我們確定每一次group by都會攜帶欄位A,將A設定成Mandatory Dimensions後,那麼就可以省去所有不包含A這個維度的cuboid了

好的技術文章:
http://kyligence.io/zh/2017/04/21/apache-kylin-advanced-setting-mandatory-dimension-principle/

1.23 調優:設定Joint Dimensions

很好的一篇博文:
http://kyligence.io/zh/2017/04/07/apache-kylin-advanced-setting-joint-dimension-principle/

1.24 調優:設定Hierarchy Dimension

以下文章很好的介紹瞭如何關於Hierarchy Dimension的調優策略

http://kyligence.io/zh/2017/04/14/apache-kylin-advanced-setting-hierarchy-dimension-principle/

1.25 調優:Configuration Overwrites 高階設定

參考官網更詳細介紹:
http://kylin.apache.org/cn/docs/install/advance_settings.html

另外在裡面最好設定資料壓縮方式,以減少磁碟佔用

1.26 調優:改變kylin中Advanced Setting的維度順序

對於kylin中頻繁使用,或著一定使用的維度列,在設定Includes的時候,將這些配置的靠前一些。因為kylin內部機制是越靠前的越優先被找到,從而加快查詢速度。
在這裡插入圖片描述
就是上面紅色區域的維度列的順序。

1.27 調優:Build Cube With Spark

kylin.engine.spark.rdd-partition-cut-mb = 10 (預設 200)
在這裡插入圖片描述
直接影響 spark 的分割槽數,首先大概清楚 cuboid 資料總大小,例如 6032mb,那麼 partitions = 6032/10 = 600,即會產生 600 個小檔案,隨後在 step8 跑 mr 時,就會拉起 600 個 map,使得 伺服器負載驟增,發生報警。

調整引數後執行,如何跟蹤伺服器情況?只需跟蹤 step8 的 mr 情況即可
http://bgnode1:8088/cluster/scheduler 找到對應的 application
② %of Cluster 是否過高
③ 進入詳情檢視 map 數量是否過多,若過多則很可能是 rdd-partition-cut-mb 設定過 小導致,此時要調大引數 因此,合理的調整 rdd-partition-cut-mb 能防止機器報警。 這一步是對每一層的 cuboid 依次進行計算並寫入 hdfs,耗時會比較長
在這裡插入圖片描述

kylin.engine.spark-conf.spark.executor.cores = 2 
kylin.engine.spark-conf.spark.executor.memory = 4G 

這兩個引數自行根據資料大小來調整,cores 和 memory 都不是越大越好,需根據要 build 的資料量,再三調整測試最優值。

1.28 調優:Rowkey調優

為什麼要優化 Rowkey? Apache Kylin 使用 HBase 做為 Cube 的儲存引擎。而 HBase 是 Key-Value 資料庫,這個 Key 在 HBase 中稱為 Rowkey。為了能夠支援按多個維度進行查詢,Kylin 需要將多個維度值以某 種次序組成 Rowkey。HBase Scan Range,排在 Rowkey 靠前部分的維度,將比排在靠後部分 的維度更易於做篩選,查詢效率更高。

那些維度適合排在前部分?

  1. 基數高的排前面 在 Load Hive Table 時,勾選 Calculate column cardinality,即可在 load 時計算各欄位的基 數,並在 Data Source -> Tables -> 點選相應的 table 檢視

1.29 調優:在查詢中被用做過濾條件的維度放在非過濾條件維度的前面

這一個環節如果 rowkey 沒設計好,會導致以下問題:

  1. Cuboid 轉 hfile 後,會因資料分佈不均勻,導致單點問題,使得伺服器記憶體過高,觸發報 警
  2. Hbase 定址慢,查詢效能下降 除了各維度在 Rowkey 上的次序外,維度的編碼方法對於空間佔用及查詢效能也有著顯 著的影響。 合適的編碼能減少維度對空間的佔用,同時編碼值也會加速查詢過濾。

1.30 調優:羅列幾個顯著影響效能的引數

以下都是預設值:

kylin.engine.spark.rdd-partition-cut-mb = 10
kylin.engine.spark-conf.spark.executor.memory = 4G
kylin.storage.hbase.region-cut-gb = 5

官網提供的可設定引數:http://kylin.apache.org/docs/install/configuration.html

1.31 調優:其它調優思路

通過./kylin.sh org.apache.kylin.engine.mr.common.CubeStatsReader [cubeName] 檢視 cuboid 總大小,然後再根據以下步驟進行對引數的調整:

1. 3 種降維選項是否有根據業務實際情況調整 
2. 有沒合理的使用分割槽列 
3. 小檔案是否過多 
4. reducer 是否過少 
5. spark partitions 是否合適 
6. spark 的 excutor 記憶體和 cores 數量分配是否合理 
7. cuboid 檔案轉 hfile 時,map 是否過多,reducer 是否過少(region 塊的大小和數量是否合 理)

2 Kylin錯誤總結,知識點

2.1 錯誤總結:變更kylin.metadata.url的值之後問題(運維層面)

在kylin安裝過程中,如果變更了kylin.metadata.url,比如:

kylin.metadata.url=bigdata

那麼在$KYLIN_HOME/bin/kylin.sh start的時候會報錯。解決辦法是:

cd $KYLIN_HOME
mkdir bigdata

然後再啟動kylin,發現已經可以啟動成功了。

2.2 知識點:Kylin通過JDBC Driver連線

Jar的maven依賴:

<kylin-jdbc.version>2.3.1</kylin-jdbc.version>


<!-- 查詢kylin jdbc driver -->
<dependency>
   <groupId>org.apache.kylin</groupId>
   <artifactId>kylin-jdbc</artifactId>
   <version>${kylin-jdbc.version}</version>
</dependency>

Spring Cloud專案中的資料庫連線池配置

spring.datasource.name=data-center
#使用druid資料來源
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#資料來源連線url
spring.datasource.url=jdbc:kylin://xxx.xxx.xxx.xxx:7070/kylinProject
spring.datasource.username=ADMIN
spring.datasource.password=KYLIN
spring.datasource.driver-class-name=org.apache.kylin.jdbc.Driver
spring.datasource.filters=stat
spring.datasource.maxActive=60
spring.datasource.initialSize=10
spring.datasource.maxWait=60000
spring.datasource.minIdle=10
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxOpenPreparedStatements=10

可以使用MyBatis寫SQL的方式獲取到Kylin中的資料。
SQL示例:

<select id="selectMemberDataStatisticsByPage" resultType="xxx.MemberDataStatisticsDto">
    SELECT
        areaName as areaName,
        agentName as agentName,
        COUNT(agentId) as totalMemberNum,
        SUM(commonMember) as commonMemberNum,
        SUM(storedMember) as storedMemberNum,
        SUM(popularizeMember) as popularizeMemberNum
    FROM
        tb_member_buyback_cycle
    <trim prefix="WHERE" suffixOverrides="AND">
        <if test="areaCode != null and areaCode != '' ">
            areaCode LIKE #{areaCode} AND
        </if>
        <if test="agentId != null and agentId != '' ">
            agentId=#{agentId} AND
        </if>
        <if test="startTime != null">
            <![CDATA[
                addTime >= #{startTime} AND
            ]]>
        </if>
        <if test="endTime != null">
            <![CDATA[
                addTime <=  #{endTime} AND
            ]]>
        </if>
    </trim>
    GROUP BY
        areaName,
        agentName
    LIMIT ${pageSize} OFFSET ${(page - 1) * pageSize}
</select>

2.3 錯誤總結:分頁問題

Kylin中分頁查詢和MySQL中的方式不太一樣,使用下面的語法:

LIMIT ${pageSize} OFFSET ${(page - 1) * pageSize}

這個語法和Phoenix的查詢語法一樣。

但是,需要注意的是,這裡的為 p a g e S i z e {pageSize},為 符號,而MyBatis中防注入的是通過#,所以需要在傳遞引數的時候做好相應的控制。如果寫成了#發現最後獲取不到自己想獲取的值(這個地方可能是其它原因)。

2.4 錯誤總結:版本相容問題

在筆者部署線上環境過程中,筆者使用的hive是hive-2.3.2 (原生),然後使用最新的: apache-kylin-2.5.2-source-release.zip ,發現其中出現了hive中有資料,但是直到kylin cube build完成之後也不能將資料拉取到kylin,發現Source Records 的條數為0,然後筆者將版本降低到:apache-kylin-2.3.1,問題現象不再出現,cube build正常了。

2.5 知識點:Cube的構建引數檢視方法

在這裡插入圖片描述

各層代表不同數量級的維度組合。每一層的計算都是一個單獨的Map Reduce任務。

2.5.1 Cube的構建引數檢視方法

可以看出,cuboid越多,build cube就越慢,可通過命令檢視cuboid個數:

./kylin.sh org.apache.kylin.engine.mr.common.CubeStatsReader [cubeName]

在這裡插入圖片描述

在這裡可以看出,該cube在構建之後得到的cuboids為63,大小約188mb

2.5.2 Build區間的資料來源大小,可以在下圖檢視

在這裡插入圖片描述
可以通過上面的提示看出:

Source Table Size:3.06GB    :原始資料大小
Expansion Rate:211.61%    :現在的大小時原始資料的211.61%倍

一般Cube的膨脹率應該在0%~1000%之間,如果Cube的膨脹率超過了1000%,那麼就需要查詢其中的原因了,導致膨脹率高的原因一般為以下幾點:

A:Cube的維度數量較多了,沒有進行良好的剪枝降維
B:Cube中存在較高基數的維度,導致這類維度每個Cuboid佔用的空間很大,從而造成Cube體積變大
C:存在比較佔用空間的(度量就是被聚合的統計值,也是聚合運算的結果),例如Count distinct、max()、sum(),需要在cuboid的每一行中都為其儲存一個較大的暫存器,導致整個體積變大。

Cube體積直接影響整個build效能,所以在建立時需要再三注意有無可減少的度量和維度。

如果有 10 個維度,那麼就會生成 2^10=1024-1 個 Cuboid,如果有 20 個維度那麼將會 生 成 2^20=1048576-1 個 Cuboid , 是 指 數 級 增 長 , kylin.properties 中 參 數 kylin.cube.aggrgroup.max-combination=4096,也就是說當 Cuboid 數量大於 4096 時, Cube 定義是無法儲存的的,會報 TooManyCuboidException 異常。所以預設維度不能超過 12 個,若非得超過 12 個,那必須降維:

3 Kylin RestAPI使用

使用kylin Rest API在shell指令碼中執行cube build/rebuid

Centos7上安裝jq工具

Jq原始碼位置:https://github.com/stedolan/jq

下載安裝地址:https://stedolan.github.io/jq/download/

Centos下安裝jq
wget -O jq https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64
chmod +x ./jq
cp jq /usr/bin

3.1 一個shell指令碼案例:

env.sh 內容:



#!/bin/bash

#kylin的引數
export kylinUserInfo="--user ADMIN:KYLIN"
export kylinCubeUrl="http://xxx:7070/kylin/api/cubes/"
export kylinJobsUrl="http://xxxx:7070/kylin/api/jobs/"
export startTime="2015-01-01 00:00"
export startTimeTimeStamp=`date -d "$startTime" +%s`
export startTimeTimeStampMs=$(($startTimeTimeStamp * 1000))
export endTime=`date +%Y-%m-%d -d "+1days"`
export endTimeTimeStamp=`date -d "$endTime" +%s`
#將時間戳程式設計毫秒值
export endTimeTimeStampMs=$(($endTimeTimeStamp * 1000))

export tradeInfoArgs="dataName=tradeInfo&dataType="    #$dataType"&dataTime="$yesterday
#json的url資訊儲存的檔案路徑
export tradeInfoJsonUrls=$current/tmpfile/tradeInfoJsonUrls
#json的url儲存位置字首
export tradeInfoJsonUrlPrefix=$current/tmpfile/tradeInfoJsonUrlPrefix
export tradeAnalyzeCubeName="xxxx"
export tradeCollectMoneyCubeName="xxxx"
#用於儲存是否下載了的變數檔案
export tradeInfoVariableFile=$current/tmpfile/tradeInfoVariableFile

#!/bin/bash

source /etc/profile

#引用公共檔案中定義的引數變數
source $PWD/env.sh

jobId=

#是否執行過初始化程式了的控制邏輯
function isInited() {
   #如果檔案存在,讀取相應的資料型別
   if [[ `ls $tradeInfoVariableFile | grep tradeInfoVariableFile | grep -v grep` != "" ]];then
		dataType=`cat $tradeInfoVariableFile | grep kylinTradeAnalyzeCubeInited | sed 's/kylinTradeAnalyzeCubeInited=//g'`
	    #如果沒有,說明這個Spark程式還沒有初始化過	
		if [[ $dataType == "" ]];then
		    echo -e "\n" >> $tradeInfoVariableFile
			echo "kylinTradeAnalyzeCubeInited=inited" >> $tradeInfoVariableFile
			return 0;
		else
		    return 1;
		fi
	else
	    mkdir -p $current/tmpfile
		cd $current/tmpfile
	    #如果沒有這個檔案,則是在這個檔案中新增
		echo "kylinTradeAnalyzeCubeInited=inited" > $tradeInfoVariableFile
		return 0;
	fi 
}

#Spark處理
function kylinHandler() {
    isInited
	if [[ $? == 0 ]];then
	    #上傳資料檔案到HDFS中
		cd $current
		#1、Disable Cube
		curl -X PUT $kylinUserInfo -H "Content-Type: application/json;charset=utf-8" $kylinCubeUrl$tradeAnalyzeCubeName/disable
		echo ""
		echo ""
		
		#2、Purge Cube
		curl -X PUT $kylinUserInfo -H "Content-Type: application/json;charset=utf-8" $kylinCubeUrl$tradeAnalyzeCubeName/purge
		echo ""
		echo ""
		
		#3、Enable Cube
		curl -X PUT $kylinUserInfo -H "Content-Type: application/json;charset=utf-8" $kylinCubeUrl$tradeAnalyzeCubeName/enable
		echo ""
		echo ""
		
		#4、Build cube
		cubeBuildInfo=`curl -X PUT $kylinUserInfo -H "Content-Type: application/json;charset=utf-8" -d '{ "startTime":'$startTimeTimeStampMs',"endTime":'$endTimeTimeStampMs', "buildType": "BUILD"}' $kylinCubeUrl$tradeAnalyzeCubeName/build`
		echo ""
		echo ""
	else
	    cubeBuildInfo=`curl -X PUT $kylinUserInfo -H "Content-Type: application/json;charset=utf-8" -d '{"endTime":'$endTimeTimeStampMs', "buildType": "BUILD"}' $kylinCubeUrl$tradeAnalyzeCubeName/rebuild`
		echo ""
		echo ""
	fi

    
	echo "cube build的狀態結果:"
	echo $cubeBuildInfo
	echo ""
	echo ""
	#檢視是否build好了,如果build好了,發現last_build_time變成了build的最後時間了。
	jobId=$(echo $cubeBuildInfo |jq '.uuid')
	echo $jobId > $jobId
	sed -i 's/"//g' $jobId
	realJobId=`cat $jobId`
	echo $realJobId
	rm -rf $jobId
	echo ""
	echo ""
	
	while :
	do
	    sleep 1m
	    cubeJobInfo=`curl -X GET --user ADMIN:KYLIN $kylinJobsUrl$realJobId`
		echo "獲取cube job執行的狀態"
		echo $cubeJobInfo
		echo ""
	    echo ""
		
	    jobStatus=$(echo $cubeJobInfo | jq ".job_status")
		echo "jobStatus"
		echo $jobStatus > $realJobId
		sed -i 's/"//g' $realJobId
		realJobStatus=`cat $realJobId`
		echo "$realJobStatus"
	    echo ""
		
		
		if [[ $realJobStatus == "NEW" ]];then
		    echo "kylin cube build job status:NEW; sleep 1m;"
		elif [[ $realJobStatus == "PENDING" ]];then
		    echo "kylin cube build job status:PENDING; sleep 1m;"
		elif [[ $realJobStatus == "RUNNING" ]];then
		    echo "kylin cube build job status:RUNNING; sleep 1m;"
		elif [[ $realJobStatus == "STOPPED" ]];then
		    echo "kylin cube build job status:STOPPED"
			#如果stop了,停掉kylin指令碼的執行
			break;
		elif [[ $realJobStatus == "FINISHED" ]];then
		    echo "kylin cube build job status:FINISHED"
			break;
	    elif [[ $realJobStatus == "ERROR" ]];then
		    echo "kylin cube build job status:ERROR"
			break;
	    elif [[ $realJobStatus == "DISCARDED" ]];then
		    echo "kylin cube build job status:DISCARDED"
			break;
		else 
		    echo "kylin cube build job status:OTHER UNKNOWN STATUS"
			break;
		fi
	done
	
	#刪除檔案
	rm -rf $realJobId
}

#上傳資料檔案到HDFS中
kylinHandler

#清理Linux系統中不用的垃圾暫用的記憶體
sync
echo 3 > /proc/sys/vm/drop_caches

4 參考資料

http://kylin.apache.org/cn/
http://kyligence.io/zh/blog-zh/