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
筆者配置:
[xxx conf]# pwd /data/installed/apache-kylin-2.3.1-bin/conf [xxxx conf]# vim setenv.sh1.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 中的配置類似如下:
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中自帶文件合并,下面的過程可以考慮設置(這個筆者沒有驗證過,有的博文中建議下面方式進行設置,但是官網是另外一種說法)
官網:
一些博文上的寫法:
該文件原本的配置如下:
<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,然后再進行處理,發現結果正確了。
類似:
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,會產生很多時間為過往時間的文件,
可以使用一下命令查看磁盤占用大小:
其中:13.1 G 表示的是一個節點中暫用磁盤的大小,35.9 G
如果這個臨時中間文件不處理,最終將導致http://namenodeip:hdfs對應的port/dfshealth.html#tab-datanode:
官網介紹:
Kylin 在構建 cube 期間會在 HDFS 上生成中間文件;除此之外,當清理/刪除/合并 cube 時,一些 HBase 表可能被遺留在 HBase 卻以后再也不會被查詢;雖然 Kylin 已經開始做自動化的垃圾回收,但不一定能覆蓋到所有的情況;你可以定期做離線的存儲清理:
步驟:
1. 檢查哪些資源可以清理,這一步不會刪除任何東西:
請將這里的 (version) 替換為你安裝的 Kylin jar 版本。
2. 你可以抽查一兩個資源來檢查它們是否已經沒有被引用了;然后加上“–delete true”選項進行清理。
完成后,Hive 里的中間表, HDFS 上的中間文件及 HBase 中的 HTables 都會被移除。
3. 如果您想要刪除所有資源;可添加 “–force 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=2001.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,耗時會比較長
這兩個參數自行根據數據大小來調整,cores 和 memory 都不是越大越好,需根據要 build 的數據量,再三調整測試最優值。
1.28 調優:Rowkey調優
為什么要優化 Rowkey? Apache Kylin 使用 HBase 做為 Cube 的存儲引擎。而 HBase 是 Key-Value 數據庫,這個 Key 在 HBase 中稱為 Rowkey。為了能夠支持按多個維度進行查詢,Kylin 需要將多個維度值以某 種次序組成 Rowkey。HBase Scan Range,排在 Rowkey 靠前部分的維度,將比排在靠后部分 的維度更易于做篩選,查詢效率更高。
那些維度適合排在前部分?
1.29 調優:在查詢中被用做過濾條件的維度放在非過濾條件維度的前面
這一個環節如果 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 塊的大小和數量是否合 理)1.32 調優:輸出壓縮(來自官網)
使用 Snappy 壓縮 HBase Cube:
另一個選項為 Gzip:
壓縮輸出的結果為:
Snappy 和 Ggzip 的區別在時間上少于 1% 但是在大小上有 18% 差別
1.33 調優:壓縮Hive表(來自官網)
時間分布如下:
按概念分組的詳細信息 :
67 % 用來 build / process flat 表且遵守 30% 用來 build cube
大量時間用在了第一步。
這種時間分布在有很少的 measures 和很少的 dim (或者是非常優化的) 的 cube 中是很典型的
嘗試在 Hive 輸入表中使用 ORC 格式和壓縮(Snappy):
前三步 (Flat Table) 的時間已經提升了一半。
其他列式格式可以被測試:
? ORC
? 使用 Snappy 的 ORC 壓縮
但結果比使用 Sequence 文件的效果差。
請看:Shaofengshi in MailList 關于這個的評論
第二步是重新分配 Flat Hive 表:
是一個簡單的 row count,可以做出兩個近似值
- 如果其不需要精確,fact 表的 row 可以被統計→ 這可以與步驟 1 并行執行 (且 99% 的時間將是精確的)
? 將來的版本中 (KYLIN-2165 v2.0),這一步將使用 Hive 表數據實現。
1.34 調優:Hive 表 (失敗) 分區(來自官網)
Rows 的分布為:
| Fact Table | 3.900.00 |
| Dim | 2.100 |
build flat 表的查詢語句 (簡單版本):
SELECT ,DIM_DATE.X ,DIM_DATE.y ,FACT_POSICIONES.BALANCE FROM FACT_POSICIONES INNER JOIN DIM_DATE ON ID_FECHA = .ID_FECHA WHERE (ID_DATE >= '2016-12-08' AND ID_DATE < '2016-12-23')這里存在的問題是,Hive 只使用 1 個 Map 創建 Flat 表。重要的是我們要改變這種行為。解決方案是在同一列將 DIM 和 FACT 分區
? 選項 1:在 Hive 表中使用 id_date 作為分區列。這有一個大問題:Hive metastore 意味著幾百個分區而不是幾千個 (在 Hive 9452 中有一個解決該問題的方法但現在還未完成)
? 選項 2:生成一個新列如 Monthslot。
為 dim 和 fact 表添加同一個列
現在,用這個新的條件 join 表來更新數據模型
生成 flat 表的新查詢類似于:
用這個數據模型 rebuild 新 cube
結果,性能更糟了 😦。嘗試了幾種方法后,還是沒找到解決方案
問題是分區沒有被用來生成幾個 Mappers
(我和 ShaoFeng Shi 檢查了這個問題。他認為問題是這里只有很少的 rows 而且我們不是使用的真實的 Hadoop 集群。請看這個 tech note)。
結果摘要
調整進度如下:
- Hive 輸入表壓縮了
- HBase 輸出壓縮了
- 應用了 cardinality (Joint,Derived,Hierarchy 和 Mandatory) 減少的技術
- 為每一個 Dim 個性化 Dim 編碼器并選擇了 Dim 在 Row Key 中最好的順序
現在,這里有三種類型的 cubes: - 在 dimensions 中使用低 cardinality 的 Cubes(如 cube 4,大多數時間用在 flat 表這一步)
- 在 dimensions 中使用高 cardinality 的 Cubes(如 cube 6,大多數時間用于 Build cube,flat 表這一步少于 10%)
- 第三種類型,超高 cardinality (UHC) 其超出了本文的范圍
1.35 調優:用高 cardinality Dimensions 的 Cube
在這個用例中 72% 的時間用來 build Cube
這一步是 MapReduce 任務,您可以在 > 看 YARN 中關于這一步的日志
Map – Reduce 的性能怎樣能提升呢? 簡單的方式是增加 Mappers 和 Reduces (等于增加了并行數) 的數量。
注意: YARN / MapReduce 有很多參數配置和適應您的系統。這里的重點只在于小部分。
(在我的系統中我可以分配 12 – 14 GB 和 8 cores 給 YARN 資源):
? yarn.nodemanager.resource.memory-mb = 15 GB
? yarn.scheduler.maximum-allocation-mb = 8 GB
? yarn.nodemanager.resource.cpu-vcores = 8 cores
有了這些配置我們并行列表的最大理論級別為 8。然而這里有一個問題:“3600 秒后超時了”
參數 mapreduce.task.timeout (默認為 1 小時) 定義了 Application Master (AM) 在沒有 ACK of Yarn Container 的情況下發生的最大時間。一旦這次通過了,AM 殺死 container 并重新嘗試 4 次 (都是同一個結果)
問題在哪? 問題是 4 個 mappers 啟動了,但每一個 mapper 需要超過 4 GB 完成
? 解決方案 1:增加 RAM 給 YARN
? 解決方案 2:增加在 Mapper 步驟中使用的 vCores 數量來減少 RAM 使用
? 解決方案 3:您可以通過 node 為 YARN 使用最大的 RAM(yarn.nodemanager.resource.memory-mb) 并為每一個 container 使用最小的 RAM 進行實驗(yarn.scheduler.minimum-allocation-mb)。如果您為每一個 container 增加了最小的 RAM,YARN 將會減少 Mappers 的數量。
在最后兩個用例中結果是相同的:減少并行化的級別 ==>
- 現在我們只啟動 3 個 mappers 且同時啟動,第四個必須等待空閑時間
- 3 個 mappers 將 ram 分散在它們之間,結果它們就會有足夠的 ram 完成 task
一個正常的 “Build Cube” 步驟中您將會在 YARN 日志中看到相似的消息:
如果您沒有周期性的看見這個,也許您在內存中遇到了瓶頸。
1.36 調優:提升 cube 響應時間
我們嘗試使用不同 aggregations groups 來提升一些非常重要 Dim 或有高 cardinality 的 Dim 的查詢性能。
在我們的用例中定義 3 個 Aggregations Groups:
比較未使用 / 使用 AGGs:
使用多于 3% 的時間 build cube 以及 0.6% 的 space,使用 currency 或 Carteras_Desc 的查詢會快很多。
1.37 調優:將多表的查詢業務處理成寬表查詢
在kylin中,將多表的統計分析轉變成寬表的統計分析,經過驗證,發現效率有相當大的提升。也就是說,將之前分布在多個表中的數據,最終經過拉平,從不同的表中取出所需的數據,轉換成寬表。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示例:
2.3 錯誤總結:分頁問題
Kylin中分頁查詢和MySQL中的方式不太一樣,使用下面的語法:
LIMIT ${pageSize} OFFSET ${(page - 1) * pageSize}
這個語法和Phoenix的查詢語法一樣。
但是,需要注意的是,這里的為pageSize,為{pageSize},為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區間的數據源大小,可以在下圖查看
可以通過上面的提示看出:
一般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/bashsource /etc/profile#引用公共文件中定義的參數變量 source $PWD/env.shjobId=#是否執行過初始化程序了的控制邏輯 function isInited() {#如果文件存在,讀取相應的數據類型if [[ `ls $tradeInfoVariableFile | grep tradeInfoVariableFile | grep -v grep` != "" ]];thendataType=`cat $tradeInfoVariableFile | grep kylinTradeAnalyzeCubeInited | sed 's/kylinTradeAnalyzeCubeInited=//g'`#如果沒有,說明這個Spark程序還沒有初始化過 if [[ $dataType == "" ]];thenecho -e "\n" >> $tradeInfoVariableFileecho "kylinTradeAnalyzeCubeInited=inited" >> $tradeInfoVariableFilereturn 0;elsereturn 1;fielsemkdir -p $current/tmpfilecd $current/tmpfile#如果沒有這個文件,則是在這個文件中添加echo "kylinTradeAnalyzeCubeInited=inited" > $tradeInfoVariableFilereturn 0;fi }#Spark處理 function kylinHandler() {isInitedif [[ $? == 0 ]];then#上傳數據文件到HDFS中cd $current#1、Disable Cubecurl -X PUT $kylinUserInfo -H "Content-Type: application/json;charset=utf-8" $kylinCubeUrl$tradeAnalyzeCubeName/disableecho ""echo ""#2、Purge Cubecurl -X PUT $kylinUserInfo -H "Content-Type: application/json;charset=utf-8" $kylinCubeUrl$tradeAnalyzeCubeName/purgeecho ""echo ""#3、Enable Cubecurl -X PUT $kylinUserInfo -H "Content-Type: application/json;charset=utf-8" $kylinCubeUrl$tradeAnalyzeCubeName/enableecho ""echo ""#4、Build cubecubeBuildInfo=`curl -X PUT $kylinUserInfo -H "Content-Type: application/json;charset=utf-8" -d '{ "startTime":'$startTimeTimeStampMs',"endTime":'$endTimeTimeStampMs', "buildType": "BUILD"}' $kylinCubeUrl$tradeAnalyzeCubeName/build`echo ""echo ""elsecubeBuildInfo=`curl -X PUT $kylinUserInfo -H "Content-Type: application/json;charset=utf-8" -d '{"endTime":'$endTimeTimeStampMs', "buildType": "BUILD"}' $kylinCubeUrl$tradeAnalyzeCubeName/rebuild`echo ""echo ""fiecho "cube build的狀態結果:"echo $cubeBuildInfoecho ""echo ""#查看是否build好了,如果build好了,發現last_build_time變成了build的最后時間了。jobId=$(echo $cubeBuildInfo |jq '.uuid')echo $jobId > $jobIdsed -i 's/"//g' $jobIdrealJobId=`cat $jobId`echo $realJobIdrm -rf $jobIdecho ""echo ""while :dosleep 1mcubeJobInfo=`curl -X GET --user ADMIN:KYLIN $kylinJobsUrl$realJobId`echo "獲取cube job運行的狀態"echo $cubeJobInfoecho ""echo ""jobStatus=$(echo $cubeJobInfo | jq ".job_status")echo "jobStatus"echo $jobStatus > $realJobIdsed -i 's/"//g' $realJobIdrealJobStatus=`cat $realJobId`echo "$realJobStatus"echo ""if [[ $realJobStatus == "NEW" ]];thenecho "kylin cube build job status:NEW; sleep 1m;"elif [[ $realJobStatus == "PENDING" ]];thenecho "kylin cube build job status:PENDING; sleep 1m;"elif [[ $realJobStatus == "RUNNING" ]];thenecho "kylin cube build job status:RUNNING; sleep 1m;"elif [[ $realJobStatus == "STOPPED" ]];thenecho "kylin cube build job status:STOPPED"#如果stop了,停掉kylin腳本的運行break;elif [[ $realJobStatus == "FINISHED" ]];thenecho "kylin cube build job status:FINISHED"break;elif [[ $realJobStatus == "ERROR" ]];thenecho "kylin cube build job status:ERROR"break;elif [[ $realJobStatus == "DISCARDED" ]];thenecho "kylin cube build job status:DISCARDED"break;else echo "kylin cube build job status:OTHER UNKNOWN STATUS"break;fidone#刪除文件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/
總結
以上是生活随笔為你收集整理的kylin调优,项目中错误总结,知识点总结,kylin jdbc driver + 数据库连接池druid + Mybatis项目中的整合,shell脚本执行kylin restapi 案例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cloudera Manager 和CD
- 下一篇: 生源地贷款续贷时间