Kylin 2.0升级总结
文章轉載,原文地址:https://blog.bcmeng.com/post/kylin-upgrade.html #6-給kylin社區的建議
引用于個人自查、學習
Kylin 2.0的升級節奏
升級的大原則
升級的目標
1 Kylin 2.0 升級流程
1.1 Kylin 2.0 代碼合入
1.2 配置更新和梳理
1.3 兼容性測試
1.4 Cube構建測試
1.5 Cube查詢測試
1.6 web測試
2 升級中暴露的問題
2.1 查詢機灰度中暴露的問題
2.2 上線Staging和Prod后Cube構建暴露的性能問題
2.3 我自己代碼的問題
3 可供下次升級復用的經驗
4 我們如何保證復雜系統的可靠性
4.1 為什么復雜系統很難保證可靠性
4.2 航天系統是如何保證系統可靠性的
4.3 如何打造高可靠的軟件系統
5 感謝Kylin社區
6 給Kylin社區的建議
7 Kylin 2.0升級總結。
我從5月中旬開始進行Kylin 2.0的升級,現在的版本是Kylin 1.5.4.1。本次升級的所有工作均由我一人完成,升級耗時和我之前估計的差不多,1個月左右,其中每天平均半天左右的時間在當“客服”(幫用戶答疑,錯誤處理,調優,追查問題)。 本次Kylin 2.0升級已經基本完成,所以寫下此文對本次Kylin 2.0升級進行總結。主要包含以下內容:
Kylin 2.0升級的流程
Kylin 2.0升級過程中遇到的一些問題
可以供下次升級復用的經驗
如何保證系統可靠性的一點思考
感謝Kylin社區
對Kylin 社區的一些建議
整個升級過程的總結
首先我們簡要回顧下 Kylin 2.0的 升級節奏:
Kylin 2.0的升級節奏
(備注:我們的Kylin服務共有Dev, Test, Staging, Prod4個環境,這也應該是Kylin生產級別的標準配置,其中Dev和 Test環境共用一個HBase集群,Staging和Prod環境共用一個HBase集群)
5月15日 開始Kylin 2.0 代碼合入。
5月17日 代碼合入完成,Dev環境測試Kylin 2.0。
5月19日 Test環境升級到Kylin 2.0。
5月25日 灰度1臺Prod的QueryServer到Kylin 2.0。
6月5日 16臺Prod的QueryServer全部升級到Kylin 2.0。
6月6日 Staging環境2臺JobServer升級到Kylin 2.0。
6月8日 Prod環境3臺JobServer升級到Kylin 2.0。
6月19日 t-digest算法原理分享(非計劃內,純粹興趣使然,在業余時間內完成)
ToDo 線上的調度腳本支持多Segment并發構建。
Doing Kylin 2.0 新特性調研和分享。
升級的大原則
穩定壓倒一切。對穩定性有影響的功能直接禁用。穩定性達不到生產環境要求的新特性就不啟用。
升級的目標
希望此次升級是一次對用戶幾乎透明,幾乎無影響,平穩上線,無case的升級。
1 Kylin 2.0 升級流程
1.1 Kylin 2.0 代碼合入
需要代碼合入的原因是我們內部的代碼和社區的diff已經越來越多,所以必須將我們內部的代碼合入到社區的2.0 版本中。代碼合入是一個十分耗神的苦力工作。因為我們早期的commit message不是很規范,所以幾乎每條commit我都要仔細認真的check下,確認每條commit是否已經合入社區,除非是我自己印象很深的commit。代碼合入要求我們對Kylin的代碼本身必須是比較熟悉的,這樣當cherry-pick出現diff時我們才能快速,合理的處理。為了減輕代碼合入的成本并減少失誤,dayue和我在今年2月份引入了以下規范:
1.2 配置更新和梳理
KYLIN-2195 引入了配置的命名規范,更新了Kylin所有配置的命名。 雖然新舊配置是兼容的,但是為了和新版保持一致,我梳理了之前所有的舊配置,移除所有不必要的配置,更新了配置名。將之前的配置從100多個刪減到40多個。這次升級配置相關的問題暴露出好幾個,后面會提到。
1.3 兼容性測試
代碼合入完成后,我首先進行了兼容性測試。Kylin的兼容性主要分3個部分: 元數據兼容性,Coprocessor兼容性, API兼容性。
元數據不兼容 意味著升級幾乎無法進行
Coprocessor不兼容 意味著升級無法灰度,升級成本極高,升級難度極大
API不兼容 其實只要能提前測試發現并提前通知用戶即可
1.2.1 元數據兼容性
首先Kylin 2.0的元數據整體上是兼容Kylin 1.5.4.1的, 不過存在以下問題:
定長編碼的兼容性。KYLIN-2642
Model元數據的兼容性。2.0版本之前由于Kylin前端有bug以及后端檢查較松,當用戶修改事實表后,會造成Model中dimensions字段中某一列只有table字段,但是columns列表是空;或者Model中dimensions字段有的table已經不存在。 對于前一種情況,我直接改了代碼,對于后一種情況,就必須得修復元數據了。我開始是直接修改元數據的,這種做法效率低下,而且危險系數也比較高。所以就用1個多小時開發測試了 web頁面直接修改model json的功能(KYLIN-2665)。
Project元數據的兼容性。這個問題應該說是我自己給我挖的坑。現象是我在staging升級到2.0后,發現每個Project的配置信息都沒了。原因是我當初開發這個功能的時候,project配置屬性用的是overrideKylinProps,liyang Review的時候改成了override_kylin_properties,關鍵是我當初發現了這一點,而且我還重構了ProjectRequest,但是我當時完全忘了考慮兼容性的問題。
1.2.2 Coprocessor兼容性
Coprocessor兼容性主要是指Kylin QueryServer和HBase RegionServer的Coprocessor通信時 序列化和反序列化的兼容性。 主要是KYLIN-2603和KYLIN-2212打破了兼容性。我處理方式比較簡單直接,就是Revert掉相關Commit。當然,我們也可以選擇讓這些功能變成可配置的,或者直接讓這些功能變成兼容的。顯然,后兩種的成本會高一些。
1.2.3 API兼容性
實際上本次升級我幾乎沒有測試API兼容性,這次升級只暴露出一個API兼容性的問題,是我們的用戶反饋出來的。就是cube_desc的Dimension信息中的table字段內容格式被修改。2.0前table字段的格式是DBname.Tablename,2.0后table字段的格式是table的別名。其實這個合理的做法應該是新加個alias的字段來表示別名。
1.4 Cube構建測試
構建測試就是抽取了30多個Cube進行build測試,為了節省資源,快速出結果,我沒有選取一些復雜的大cube,這也導致了在測試的時候沒有發現Cube構建的性能問題。
1.5 Cube查詢測試
查詢測試主要是利用我在上次升級時開發的線上查詢回放測試工具。原理是一個線程用Presto從Hive表獲取某個cube某天的所有SQL,然后再用一個線程池去查Kylin。其中查Kylin的時候每100條會對新舊兩個版本的查詢結果進行校驗。最后會統計輸出每個cube查詢的成功率,查詢時延,失敗的具體SQL和異常。但是對于PreparedStatement的查詢,由于獲取不到具體的SQL,我只能向用戶要了10條左右的SQL進行手動驗證。
1.6 web測試
測試的過程主要是把project,cube,model,job的操作過了一遍,我測試的時候沒有發現什么問題。 其實web前端的問題我主要是靠Staging 環境的用戶發現并反饋,因為web的具體操作很多,我不可能把所有細節都測試一遍。 而且web出問題影響也不大,因為web的問題不會影響生產,而且只要web發現問題,一般我都可以較快修復。
2 升級中暴露的問題
2.1 查詢機灰度中暴露的問題
KYLIN-2652 現象是1臺QuerServer灰度后,隔了大半天的時間,導致所有線上QuerServer查詢都會隨機失敗。 主要原因是KYLIN-2195忽略了 kylin.query.endpoint.compression.result這條配置的特殊性以及CubeVisitService中的KylinConfig不是線程安全的,這會導致HBase返回的查詢結果是壓縮的,但是QuerServer按照不壓縮的去反序列化。
KYLIN-2647
case A when 0 then 0 else 1.0 * B/A end Kylin 2.0中如果A是null查詢則會失敗,列出這個問題是因為這個問題影響比較大,我們的多個用戶都有這種寫法。原因是新版Calcite 生成的代碼有問題,沒有處理A是null的情況。解決辦法是SQL改寫為 case A when 0 then 0 else cast (B as double) /A end,Calcite對這個SQL生成的代碼對A等于null時有特殊處理,直接返回null。
PreparedStatement的 Date類型的bug。起初我調試代碼,以為是Calcite的bug,后來看了下Calcite的代碼,才發現是Kylin的bug。Calcite對Date類型有特殊處理,會將Date類型的值轉成epoch time,比如2015-01-01 轉為 16436,所以Kylin對Date類型也有特殊處理。
對于Statement,Kylin中Date的轉換格式如下:
1 Date類型的2015-01-01 在OLAPFilterRel.cast中 轉為 1420070400000
2 1420070400000 在請求HBase前后會有編碼和解碼
3 1420070400000 在Tuple的convertOptiqCellValue轉為16436(epoch time)
對于PreparedStatement: Kylin的處理過程如下:
1 KylinClient的AvaticaPreparedStatement 將2015-01-01 轉為 16436
2 KylinClient的KylinPreparedStatement 將16436 轉為 2015-01-01。
3 KylinServer在setParam時 AvaticaPreparedStatement 再次將2015-01-01 轉為 16436
4 在OLAPEnumerator.bindVariable() 中對PreparedStatement的Date類型 還有特殊轉換,不過此處有問題, 因為此處Kylin認為2015-01-01的格式應該是2015-01-01,但實際上是16436。
所以我認為該問題的解決方法可以是:
在OLAPEnumerator.bindVariable() 將16436 轉為1420070400000,應該只需改一行代碼。
2.2 上線Staging和Prod后Cube構建暴露的性能問題
字典的MR構建對基數超高的列性能很低下。全部禁用了字典的MR構建。
構建Base cuboid時全局字典頻繁換入換出。 這個也是我自己埋的坑,因為我解決這個問題時在我們內部用的配置和我最終合入社區的配置不一致。社區的配置在Review時按照建議修改了。
計算列基數這一步變的異常慢。原因是kylin.engine.mr.uhc-reducer-count 默認值變成了1。我清晰的記得我當初專門把這個值改成了3,為了讓IT可以cover這個feature。
HFile Reducer個數偏少。 我看log發現cuboid總大小估計的比較小,我開始以為是我設置的kylin.cube.size-estimate-ratio 和 kylin.cube.size-estimate-countdistinct-ratio 參數有問題,或者是新版估計cuboid大小算法有變化。 我新確認了cuboid大小估計算法的diff,發現雖然有略微區別,但本質上是一樣的。后來我嘗試掉了幾次這兩個參數的大小,發現并沒有明顯效果。后來當我注意到cuboid總大小,Region大小,HFile的大小關系時,才發現好幾個Cube HFile的大小是egion大小的一半。這時我才注意到計算HFile時的這個分支:
if (hfileSizeMB > 0.0 && kylinConfig.isDevEnv()) {
hfileSizeMB = mbPerRegion / 2;
}
我開始一直以為kylinConfig.isDevEnv()是false,就忽略這段代碼,結果點進去后發現kylinConfig.isDevEnv()的默認值是true,而我這次梳理配置時把kylin.env的這個配置刪除了,我覺得這個參數沒啥用。而實際上,估算hfileSizeMB依賴kylin.env的配置肯定是不合理的,想cover IT,直接把sandbox的Hfile的大小調小就可以。
2.3 我自己代碼的問題
精確去重的Segment粒度的AppendTrieDict之前不支持segment并發,現在已經支持。
KYLIN-2606 對精準聚合的精確去重查詢的優化。我之前在判斷一個SQL是否是精準聚合時,遺漏了下面的情況:
SELECT MIN(A) A FROM table WHERE A = ‘2017-06-05’ //其中 A 是維度
解決辦法就是將 維度作為指標的情況 判為 非精準聚合
3 可供下次升級復用的經驗
兼容性測試時元數據兼容性,Coprocessor兼容性, API兼容性這3點都需要考慮。
Cube構建測試時需要選取一些復雜的大Cube進行測試,需要重點關注構建性能。
增大線上查詢回放的Cube個數,對更多的查詢進行測試,重點不在于能測試多少條查詢,在于能測試多少種不同類型的查詢。
升級順序可以和本次一樣,可以先灰度線上QueryServer,確定查詢沒有問題后,再升級Staging和Prod的JobServer。
升級Staging和Prod的JobServer前,需要先確認舊版的代碼是否可以構建新版的cube。如果可以,Staging和Prod的升級間隔就可以拉的很長,甚至可以在staging把Prod上全部cube構建一遍后再升級Prod。 否則,升級完Staging后就需要較快的升級Prod,因為沒法切Cube,會對用戶造成影響。 本次升級就屬于后者,所以升級壓力就會很大,必須快速解決暴露的所有問題。
應該考慮上線回滾方案,可以參考 來自 Google 的高可用架構理念與實踐
我們向社區貢獻代碼時,應該保證合入社區的配置名稱,配置默認值,元數據的屬性和我們內部一致。
4 我們如何保證復雜系統的可靠性
這個問題可以近似等價于以下問題:
我們如何確保我們的每次升級或者上線是一定沒問題的?
我們有沒有可能寫出沒有bug的復雜系統?
我們的測試到底需要測到什么程度?
首先,這個世界上沒有完全沒有bug的系統,也不存在100%可用的系統。我們的目標只能是提供可用性盡可能高的系統,比如3個9的可用性,4個9的可用性。關于系統可用性的概念可以參考來自 Google 的高可用架構理念與實踐或者關于高可用的系統。
4.1 為什么復雜系統很難保證可靠性
我認為可能有以下幾點:
1 復雜系統必然有很多模塊,那么這些模塊這件的相互影響就會比較復雜。 如果只寫一個二分搜索或者快排函數,那么我們可以很容易確定我們的函數是沒有問題的。 因為輸入和輸出是簡單的,各種邊界情況和異常情況也是有限的。 但是在復雜系統中,你有時候一個看似很簡單的獨立改動,也會對其他模塊造成影響。 比如KYLIN-2619,我只是換個線程池,結果UT掛了,本質原因是Kylin使用的HTTPclient是不支持并發的。 比如KYLIN-2672,我只是優化了Cube遷移的緩存更新,結果沒想到切完Cube后導致整個線上的查詢掛了,本質原因是TblColRef在檢查TableDesc一致性的時候用了 == 而不是 equals。其實我們應該使用equals。
2 復雜系統實際應用時的具體環境和參數都是不同的,而不同的context可能會導致不一致的表現。很多時候系統會出現只是某一部分模塊cover了所有已知的環境,但是某些模塊只cover了部分。
3 復雜系統的依賴一般比較多,越多的依賴必然引入越多的穩定性風險。比如Kylin很好的融入了Hadoop社區,這是其優點,也是其顯著的缺點,比如HBase,Mapreduce,Yarn,HDFS,Hive隨便一個系統出點問題或者有bug,都會給Kylin帶來顯著影響。新版還加入了Spark和Kafka的依賴。 此外,越多的系統依賴,也使得Kylin的日常運維成本極高,此處的運維不僅指你需要確保Kylin所依賴系統的穩定性,了解Kylin所依賴系統的原理,這都是應該的,最主要的是你還需要教給你的用戶這些系統的簡單原理,它們在Kylin中的作用,出了問題怎么排查。
4 現在的復雜系統一般都是分布式系統,而我們知道分布式系統天生就有許多難題:不可靠的網絡,不可靠的時鐘,進程無響應,單機掛掉等。
說了這么多,我其實一直挺好奇像神舟飛船這種完全不能出錯的系統到底是怎么保障可靠性的?
4.2 航天系統是如何保證系統可靠性的
我谷歌了下,發現盡然有專門的大學專業:可靠性系統工程。 還買了兩篇相關的論文讀了下:《可靠性系統工程的理論與技術框架》,《航天器環境試驗和航天產品的質量與可靠性保證》。結果發現這教授寫的論文和我的本科論文一樣水,沒啥干貨。最后在《握手太空的航天科技》書中谷歌到一點答案,其實發現和我們保證一個高可用的軟件系統原理是一樣的:
首先是大量,嚴密的測試確保飛船的一些組件,功能是正常的。 和軟件系統一樣。
其次是關鍵部件的備份,冗余,takeover,關鍵設備都是3份同時工作。 和軟件系統一樣。
最后是分析飛船可能出現的所有故障情況,并給出應急方案。 也和軟件系統一樣,我們既然不能保證不出case,那么我就盡可能保證出了case立即發現,立即處理,立即恢復。
可以發現,保證系統可靠性的原理和思路在任何領域都是一致的 除了以上幾點,可靠性的系統當然需要可靠優秀的總體設計或者架構設計,也需要可靠的細節實現或者代碼實現。
當然,還有個顯然的問題就是,神舟飛船在地面怎么測試太空的場景?答案是模擬。 所以我們現在可以回答 我們的測試到底需要測到什么程度 這個問題。答案是,如果你能在線下造出和線上完全相同的環境,那么你就可以用線上真實的數據或者case進行測試,Kylin在升級時其實是完全可以做到的,只不過這種做法成本太高,所以我們就需要模擬。有人會問,網絡隔離,磁盤掛掉,機器down掉,CPU持續飆高等情況可以模擬嗎,答案是可以模擬的,請參考以下篇文章:
分布式系統測試那些事兒——理念
分布式系統測試那些事兒——錯誤注入
分布式系統測試那些事兒——信心的毀滅與重建
這3片文章對測試的講解十分深入,值得大家一讀,大家也可以反思自己系統的測試。
4.3 如何打造高可靠的軟件系統
可靠的系統設計
可靠的理論基礎
可靠的代碼實現
可靠,充分,全面的測試
充分的冗余,備份,多活,takeover等
可靠的監控和運維系統
可靠的故障恢復機制
高效,自動化的工具
具體大家可以參考下面的參考資料,引用陳皓的話總結:高可靠的系統是一個系統化的工程,這不是一個人或者幾個人可以做到的,取決于全公司的技術實力和工程素養。 比如可用性4個9以上的系統,小公司基本不太可能做的出來。
來自 Google 的高可用架構理念與實踐
如何建設高可用系統
關于高可用的系統
TiDB 架構的演進和開發哲學
《designing-data-intensive-applications》 5星力薦,很贊的一本書。
5 感謝Kylin社區
Kylin 2.0為我們帶來多Segment并發重導,TrieDictionaryForest字典,雪花模型,百分位函數,Steaming cubing,Spark cubing等實用功能和新特性,以及若干bug Fix 和性能提升。十分感謝Kylin社區,身為Kylin commiter,能夠理解每位Kylin contributor的付出,因為很多時候,我們都是在自己的業余時間和假期向Kylin社區貢獻。
6 給Kylin社區的建議
我們每個Kylin的contributor和commiter都應該考慮兼容性問題,具體包括元數據的兼容性,Coprocessor兼容性, API兼容性。比如像1.2.3 API兼容性中舉的例子,只要我們有考慮到這一點,這個兼容性問題完全可以避免掉。
我們每個JIRA的Assignee都應該在JIRA中描述必要的信息。 Bug類型的issue應該描述bug產生的原因,Fix bug的思路。Improve類型的issue應該描述是如何改進的,如果有性能對比則更好。New Feature類型的issue應該描述清楚背景或動機,并簡要描述實現思路。 Issue Fix后應該在JIRA中給出github commit的鏈接。現在Kylin的大多數JIRA描述信息太過簡單,要想知道基本的實現思路,必須自己去讀代碼,而且具體的commit信息還得根據JIRA號去找。
建議用Github的PR代替patch。 好處是首先代碼閱讀更方便,代碼Review更方便,這樣commit中就不會有那么多code review的commit。其次是Github可以和很多自動化工具集成,目前kylin中commit中經常有Fix UT和FIX IT,如果可以讓每個PR自動跑UT和IT,只有通過后才允許合入Master,就不會有這個問題。
7 Kylin 2.0升級總結。
本次升級基本符合目標。
一個意外是在所有環境升級2.0的4天之后,發生了一次查詢事故。事故的原因是升級2.0后,由于新版的Coprocessor會加載更多的類,所以HBase RegionServer的PermGen增加了10M左右,超過了MaxPermSize,所以PermGen就OOM了。事故的本質原因是RegionServer的PermGen配置較小和Kylin Coprocessor 中catch了OOM異常。而事實上OOM異常幾乎沒有理由去catch,Kylin Coprocessor中更不應該去catch OOM。
總結
以上是生活随笔為你收集整理的Kylin 2.0升级总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在有原来的数据的情况下,恢复数据库的数据
- 下一篇: Win10强制更新怎么关闭 彻底禁止Wi