您好,登錄后才能下訂單哦!
Apache Kylin是怎樣在百度地圖實踐的,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
百度地圖開放平臺業務部數據智能組主要負責百度地圖內部相關業務的大數據計算分析,處理日常百億級規模數據,為不同業務提供單條SQL毫秒級響應的OLAP多維分析查詢服務。
對于Apache Kylin在實際生產環境中的應用,在國內,百度地圖數據智能組是最早的一批實踐者之一。Apache Kylin在2014年11月開源,當時,我們團隊正需要搭建一套完整的大數據OLAP分析計算平臺,用來提供百億行級數據單條SQL毫秒到秒級的多維分析查詢服務,在技術選型過程中,我們參考了Apache Drill、Presto、Impala、Spark SQL、Apache Kylin等。對于Apache Drill和Presto因生產環境案例較少,考慮到后期遇到問題難以交互討論,且Apache Drill整體發展不夠成熟。對于Impala和Spark SQL,主要基于內存計算,對機器資源要求較高,單條SQL能夠滿足秒級動態查詢響應,但交互頁面通常含有多條SQL查詢請求,在超大規模數據規模下,動態計算亦難以滿足要求。后來,我們關注到了基于MapReduce預計算生成Cube并提供低延遲查詢的Apache Kylin解決方案,并于2015年2月左右在生產環境完成了Apache Kylin的首次完整部署。
Apache Kylin是一個開源的分布式分析引擎,提供Hadoop之上的SQL查詢接口及多維分析(OLAP)能力以支持超大規模數據,最初由eBay Inc. 開發并貢獻至開源社區,并于2015年11月正式畢業成為Apache頂級項目。
我們在Apache Kylin集群上跑了多個Cube測試,結果表明它能夠有效解決大數據計算分析的3大痛點問題。
痛點一:百億級海量數據多維指標動態計算耗時問題,Apache Kylin通過預計算生成Cube結果數據集并存儲到HBase的方式解決。
痛點二:復雜條件篩選問題,用戶查詢時,Apache Kylin利用router查找算法及優化的HBase Coprocessor解決;
痛點三:跨月、季度、年等大時間區間查詢問題,對于預計算結果的存儲,Apache Kylin利用Cube的Data Segment分區存儲管理解決。
這3個痛點的解決,使我們能夠在百億級大數據規模下,且數據模型確定的具體多維分析產品中,達到單條SQL毫秒級響應。因此,我們對Apache Kylin產生了較高的興趣,大數據計算查詢分析的應用中,一個頁面通常需要多條SQL查詢,假設單條SQL查詢需要2秒響應,頁面共有5個SQL請求,總共就需要10秒左右,這是不可接受的。而此時,Apache Kylin對于一個頁面多條SQL查詢響應的優勢就尤為突出。
在實踐過程中,根據公司不同業務的需求,我們數據智能團隊的大數據OLAP平臺后臺存儲與查詢引擎采用了由Apache Kylin、Impala及Spark SQL組成,在中小數據規模且分析維度指標較為隨機的情況下,平臺可提供Impala或Spark SQL服務;在超大規模百億級行數據的具體產品案例上,因查詢性能需求較高,同時具體產品對其需要分析的維度和指標較為明確,我們使用Apache Kylin解決方案。下文將主要介紹Apache Kylin在百度地圖內部的實踐使用。
(點擊放大圖像)
數據接入:主要負責從數據倉庫端獲取業務所需的最細粒度的事實表數據。
任務管理:主要負責Cube的相關任務的執行、管理等。
任務監控:主要負責Cube任務在執行過程中的狀態及相應的操作管理。
集群監控:主要包括Hadoop生態進程的監控及Kylin進程的監控。
因業務特殊性,我們并未采用公司內部的Hadoop集群進行計算、存儲和查詢,而是獨立部署一臺完整的集群,并獨立維護。
集群機器:共4臺,1臺master(100G內存) + 3臺slaves(30G內存)。
軟件環境:CDH + Hive + HBase + Kylin 0.71
對于任何一個數據計算處理平臺,數據的接入十分關鍵,就像熟知的Spark,對數據接入也是十分重視。目前,我們的大數據OLAP平臺可以支持2種數據源的引入: MySQL數據源及HDFS數據源。在實踐中,我們遇到一個問題,假設MySQL及HDFS數據源沒有標識表示T-1天的數據已經計算完成的情況下,如何確定T-1天的數據已經準備就緒。對于Hive數據源,查詢數據所在Hive Meta的partition是否就緒;對于MySQL,我們目前想到的辦法是間隔一定時間循環探測當天數據行數是否變化,如果沒有變化,我們基本能夠簡單認為第T-1天的數據已經由數據倉庫計算完畢,接下來就可以觸發數據拉取模塊邏輯將數據拉取到Master節點的本地文件系統中,根據業務判斷是否需要對這些數據細加工,然后,導入到Master的Hive中,觸發事實表對應任務涉及到的所有cube,啟動MapReduce計算,計算結束后,前端可以刷新訪問最新數據。另外,如果到了指定時間,發現數據倉庫端的數據仍舊沒有準備好,數據接入模塊會短信報警給倉庫端,并繼續循環檢測直至指定時刻退出。
(點擊放大圖像)
數據引入模塊
任務管理對于計算型平臺服務十分重要,也是我們大數據OLAP多維分析平臺的核心擴展工作之一。對于用戶而言,Apache Kylin對于Cube的最小存儲單位為data segment,類似于Hive的partition,data segment采用左閉右開區間表示,如[2015-11-01,2015-11-02)表示含有2015-11-01這一天的數據。對于Cube數據的管理主要基于data segment粒度,大致分為3種操作: 計算(build)、更新(refresh)、合并(merge)。對于一個具體產品來說,它的數據是需要每天例行計算到cube中,正常例行下,每天會生成1個data segment,但可能會因為數據倉庫的任務延遲,2天或多天生成1個segment。隨著時間推移,一方面,大量的data segment嚴重影響了性能,另一方面,這也給管理帶來了困難和麻煩。因此,對于1個cube,我們按照1個自然月為1個data segment,清晰且易管理。
假設我們有1個月30天的數據,共23個data segment數據片段,如:[2015-11-01,2015-11-02), [2015-11-02,2015-11-04), [2015-11-04,2015-11-11), [2015-11-11,2015-11-12), [2015-11-12,2015-11-13), 。。。[2015-11-30,2015-12-01)
問題1: 假設因為數據有問題,需要回溯2015-11-01的數據,因為我們能夠在cube中找到[2015-11-01,2015-11-02)這樣一個data segment,滿足這個時間區間,于是,我們可以直接界面操作或者Rest API啟動這個data segment的refresh更新操作。
問題2: 假設我們需要回溯2015-11-02到2015-11-03的數據,同理,可以找到一個符合條件的data segment [2015-11-02,2015-11-04),然后refresh更新這個data segment。
問題3: 假設我們需要回溯2015-11-01到2015-11-02的數據,我們找不到直接滿足時間區間的data segment。于是我們有2種解決方案,第1種方案是分別依次refresh更新 [2015-11-01,2015-11-02), [2015-11-02,2015-11-04)這2個data segment實現;第2種方案是先合并(merge)[2015-11-01,2015-11-02), (2015-11-02,2015-11-04)這兩個data segment,合并后得到[2015-11-01,2015-11-04)這樣1個data segment,然后我們再拉取新數據后執行更新操作,即可滿足需求。
問題4: 假設我們需要刷新2015-11-01~2015-11-30這1個月的數據,我們在另1套集群上基于Kylin 1.1.1對同一個cube進行測試,如果采用問題3中的第1種方案,我們需要逐步刷新cube的23個data segment,大約耗時17.93min X 30=537分鐘; 如果我們采用問題3中的第2種方案, 那么我們只需要將23個data segment合并成[2015-11-01,2015-12-01)這1個data segment,計1次操作。然后再執行1次更新操作,共2次操作即可完成需求,總體上,耗時約83.78分鐘,較第1種方法性能上提高很多。
基于上面的問題,目前我們平臺對Apache Kylin進行了二次開發,擴展出了任務管理模塊。
對于cube的計算(build)操作,假設數據倉庫2015-11-29~2015-12-02的數據因故延遲,在2015年12-03天產出了(T-1天的數據),如果不判斷處理,就會例行計算生成一個時間區間為[2015-11-29,2015-12-03)的data segment。所以,在每個cube計算前,我們的邏輯會自動檢測跨自然月問題,并生成[2015-11-29,2015-12-01)和[2015-12-01,2015-12-03)兩個data segment.
對于cube的更新(refresh)操作,我們會采用問題3、問題4中提到的第2種方案,自動合并(merge)data segment后再執行更新refresh操作。因為上面已經保證了不會有跨月data segment的生成,這里的自動合并也不會遇到生成跨自然月的情況。
對于cube的合并(merge)操作,如果每天都自動合并該自然月內前面日期已有的所有data segment,假設我們想回溯更新2015-11-11這一天的數據,那么就需要回溯(2015-11-01,2015-11-12)(因為這個時間區間的data segment每天都被自動合并了),其實,我們沒有必要回溯2015-11-01~2015-11-10這10天的數據。所以,對于1個自然月內的cube的數據,在當月,我們先保留了1天1個data segment的碎片狀態,因為在當月發現前面某幾天數據有問題的概率大,回溯某個data segment小碎片就更加合理及性能更優。對于上個月整個月的數據,在下個月的中上旬時數據已經比較穩定,回溯的概率較小,通常要回溯也是上個月整月的數據。因此,在中上旬整體合并上1個月的數據而不是每天合并更合理。
(點擊放大圖像)
任務管理模塊
通常,1個產品對應多個頁面,1頁面對應1個事實表,1個事實表對應多個cube,那么一個產品通常會包含多個cube,上面提到的cube基于data segment的3種任務狀態,很難人為去核查,所以對于任務執行的監控是非常必要的,當任務提交后,每隔一段時間檢測一次任務的狀態,任務狀態中間失敗或者最后成功后,則會發送郵件或者短信報警通知用戶。
由于我們的服務器是團隊內部獨自部署維護,為了高效監控整套Hadoop集群、Hive,HBase、Kylin的進程狀態,以及處理海量臨時文件的問題,我們單獨開發了監控邏輯模塊。一旦集群出現問題,能夠第一時間收到報警短信或者郵件。
平臺監控模塊
由于我們以平臺方式提供給各個業務線使用,當某個業務線的業務數據計算規模較大,會造成平臺現有資源緊張時,我們會根據實際情況,要求業務方提供機器資源,隨之而來的就是如何根據業務方提供的機器資源分配對應的計算隊列的資源隔離問題。目前,官方的Apache Kylin版本對于整個集群只能使用1個kylin_job_conf.xml, 平臺上所有項目的所有Cube的3種操作只能使用同一個隊列。于是,我們基于kylin-1.1.1-incubating這個tag的源碼做了相關修改,支持了以項目為粒度的資源隔離功能,并提交issue到https://issues.apache.org/jira/browse/KYLIN-1241,方案對于我們平臺管理員自身也參與項目開發的應用場景下非常適用。對于某個項目,如果不需要指定特定計算隊列,無需在$KYLIN_HOME下指定該項目的kylin_job_conf.xml文件,系統會自動調用官方原有的邏輯,使用默認的Hadoop隊列計算。
資源隔離
因獨立部署的Hadoop集群硬件配置不高,內存十分有限,所以,在項目實踐過程中也遇到不少問題。
調整MapReduce分配資源參數:在cube計算過程中,會出現mr任務失敗,根據日志排查,主要因mr的內存分配不足導致,于是,我們根據任務實際情況整體調整了yarn.nodemanager.resource.memory-mb,mapreduce.map.memory.mb, mapreduce.map.java.opts, mapreduce.reduce.memory.mb及mapreduce.reduce.java.opts等參數。
由于機器整體資源限制,我們給HBase配置的HBASE_HEAPSIZE值較小,隨著時間推移,平臺承載的項目越來越多,對內存及計算資源要求也逐步提高。后來平臺在運行過程中,HBase的RegionServer在不同節點上出現隨機down掉的現象,導致HBase不可用,影響了Kylin的查詢服務,這個問題困擾了團隊較長時間,通過網上資料及自身的一些經驗,我們對HBase和Hadoop相關參數做了較多優化。
A. HBase的JVM GC相關參數調優,開啟了HBase的mslab參數:可以通過GC調優獲得更好的GC性能,減少單次GC的時間和FULL GC頻率;
B. HBase的ZK連接超時相關參數調優:默認的ZK超時設置太短,一旦發生FULL GC,極其容易導致ZK連接超時;
C. ZK Server調優,提高maxSessionTimeout:ZK客戶端(比如Hbase的客戶端)的ZK超時參數必須在服務端超時參數的范圍內,否則ZK客戶端設置的超時參數起不到效果;
D. HBASE_OPTS參數調優:開啟CMS垃圾回收期,增大了PermSize和MaxPermSize的值;
Hadoop及HBase優化
Hadoop及HBase優化
對于Cube的設計,官方有專門的相關文檔說明,里面有較多的指導經驗,比如: cube的維度最好不要超過15個, 對于cardinality較大的維度放在前面,維度的值不要過大,維度Hierarchy的設置等等。
實踐中,我們會將某個產品需求分為多個頁面進行開發,每個頁面查詢主要基于事實表建的cube,每個頁面對應多張維度表和1張事實表,維度表放在MySQL端,由數據倉庫端統一管理,事實表計算后存放在HDFS中,事實表中不存儲維度的名稱,僅存儲維度的id,主要基于3方面考慮,第一:減少事實表體積;第二:由于我們的Hadoop集群是自己單獨部署的小集群,MapReduce計算能力有限,join操作希望在倉庫端完成,避免給Kylin集群帶來的Hive join等計算壓力;第三:減少回溯代價。 假設我們把維度名稱也存在Cube中,如果維度名稱變化必然導致整個cube的回溯,代價很大。這里可能有人會問,事實表中只有維度id沒有維度name,假設我們需要join得到查詢結果中含有維度name的記錄,怎么辦呢?對于某個產品的1個頁面,我們查詢時傳到后臺的是維度id,維度id對應的維度name來自MySQL中的維度表,可以將維度name查詢出來并和維度id保存為1個維度map待后續使用。同時,一個頁面的可視范圍有限,查詢結果雖然總量很多,但是每一頁返回的滿足條件的事實表記錄結果有限,那么,我們可以通過之前保存的維度map來映射每列id對應的名稱,相當于在前端邏輯中完成了傳統的id和name的join操作。
比如我們的事實表有個detail分區數據,detail分區包含最細粒度os和appversion兩個維度的數據(注意: cuid維度的計算在倉庫端處理),我們的cube設計也選擇os和appversion,hierarchy層次結構上,os是appversion的父親節點,從os+appversion(group by os, appversion)組合維度來看,統計的用戶量沒有問題,但是按照os(group by os)單維度統計用戶量時,會從基于這個detail分區建立的cube向上匯總計算,設上午用戶使用的是android 8.0版本,下午大量用戶升級到android 8.1版本,android 8.0組合維度 + android 8.1組合維度向上計算匯總得到os=android(group by os, where os=android)單維度用戶,數據會膨脹且數據不準確。因此我們為事實表增加一個agg分區,agg分區包含已經從cuid粒度group by去重后計算好的os單維度結果。這樣,當用戶請求os維度匯總的情況下,Apache Kylin會根據router算法,計算出符合條件的候選cube集合,并按照權重進行優選級排序(熟悉MicroStrategy等BI產品的同學應該知道這類案例),選擇器會選中基于agg分區建立的os單維度agg cube,而不從detail這個分區建立的cube來自底向上從最細粒度往高匯總,從而保證了數據的正確性。
對應小規模集群,計算資源是非常寶貴的,假設我們對于某個項目的留存分析到了日對1日到日對30日,日對1周到日對4周,日對1月到日對4月,周對1周到周對4周,月對1月到月對4月。那么對于傳統的存儲方案,我們將遇到問題。
假如今天是2015-12-02,我們計算實際得到的是2015-12-01的數據
(點擊放大圖像)
上面數據存儲方案的思路是,當今天是2015-12-02,那么2015-12-01可以計算活躍用戶了,于是,我們會將2015-11-30的日對第1日留存, 2015-11-29的日對第2日, 2015-11-28的日對第3日等的這些列指標數據進行更新(如上紅色對角線部分),這是因為每天數據的每1列都是以當天為基準,等今后第n天到了,再回填這1天的這些第x日留存,如此,對于1個任務會級聯更新之前的多天歷史數據,如上紅色對角線的數據。
此方案的優勢:
a, 如果要查看某個時間范圍內的某一個或者多個指標,可以直接根據時間區間,選擇需要的列指標即可。
b, 如果要查看某1天的多個指標,也可以直接選擇那1天的多個指標即可
此方案的缺點:
a, 每天都需要更新歷史數據,如上紅色對角線的數據,造成大量MapReduce任務預計算cube,需要較多的機器計算資源支持。
b, 如果今后增加新的留存,比如半年留存,年留存,那么對角線長度就更長,每天就需要回溯更新更多天數的歷史數據,需要更多時間跑任務。
c, 對于級聯更新的大量的歷史數據任務,其實依賴性很強,如何保證留存項目多個cube每一天的多個data segment級聯更新正確,非常復雜,難以維護和監控,對于數據倉庫端也易遇到如此問題。
d, 對于需要批量回溯一個較大時間區間的歷史數據時,問題3中涉及的任務計算難點和困難尤為突出。
假如今天是2015-12-02,我們計算實際得到的是2015-12-01的數據(可和上面的結構對比)
(點擊放大圖像)
此方案的思路是,當今天是2015-12-02,實際是2015-12-01的數據,如上示例存儲,但日對第n日的留存表示的是n日前對應的那個日期的留存量,相當于旋轉了紅色對角線。
此方案的優勢:
a, 如果要查看某個時間范圍內的某1個指標,直接選擇該范圍的該列指標即可
b, 如果今后增加新的留存,比如半年留存,年留存等指標,不需要級聯更新歷史天數的數據,只需要更新2015-12-01這1天的數據,時間復雜度O(1)不變,對物理機器資源要求不高。
此方案的缺點:
a, 如果涉及到某1天或者某個時間范圍的多列指標查詢,需要前端開發留存分析特殊處理邏輯,根據相應的時間窗口滑動,從不同的行,選擇不同的列,然后渲染到前端頁面。
目前,我們在項目中采用變通的存儲方案。
看完上述內容,你們掌握Apache Kylin是怎樣在百度地圖實踐的的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。