Hyperloop,让发布简洁高效
Hyperloop 是什么?
Hyperloop 是服務于美團點評客戶端的組件發版、持續集成、App 打包構建、資源調度等各個環節的發布調度系統。名稱起源于美國 Elon Musk 構想的 Hyperloop 超級高鐵,象征著現代、簡潔、高效。
Hyperloop 提供了一站式的平臺,管理著美團點評 iOS 業務的超過 300 個組件和包括美團 iOS 客戶端在內的4個App。接入 Hyperloop 系統后,開發同學可以通過 Hyperloop 來管理自己的項目,配置發版和打包所需要的步驟和檢查項。開發完成時,用戶只需要登錄 Hyperloop 進行相關操作,Hyperloop 就會根據項目的配置去調用不同的步驟,上報每個步驟的狀態,給出錯誤日志、狀態通知等。
為什么要有 Hyperloop?
說到發布,我們首先想到的就是持續集成和交付,而說到持續集成和交付,我們又會自然而然地想到 Jenkins。沒錯,我們之前的所有和發布工程相關的流程都是與 Jenkins 密切相關,其任務的調度、自動化的構建等功能深受我們的喜愛。
可是隨著我們的業務爆發式的增長,加之對 Jenkins 的深入使用,一些問題逐漸暴露出來了:
1. 使用和維護成本加大
業務量的增多,導致參與到整個發布流程中的同學也越來越多,而因為 Jenkins 偏向于專業的配置和運維步驟,給我們普通的開發同學帶來很多 Jenkins 的使用和維護上的問題,讓我們發布工程的同學不得不花大量的時間來進行答疑和維護。
2. Jenkins Job 的數量增多
Jenkins 中存在的 Job 數量也隨著業務的擴張而變的十分龐大。
| 一級目錄數量 | 總 Job 數量 | | :—–: | :——: | | 74 | 569 |
為什么會有這么多的任務呢?因為我們發布流程會提供一些必要的功能,而每個業務方在使用這些功能的時候需要配置一些自己的業務參數,出于 Jenkins 的一些局限性,常規的做法就是復制一份示例 Job 然后改成自己的構建任務。
所以說這么多的業務方乘以這么多的業務,就造就了這么多的 Job……
這么多的 Job 帶來了不小的問題,不管是新策略的推廣,還是 Job 的維護都是 N 倍的工作量。
3. 構建數據難以統計
這么多的 Job,結果基本上沒有辦法集中統計。此外,Jenkins 中數據分析和呈現能力偏弱,而數據對于我們現如今的開發是尤為重要的,不僅能夠反應出我們的工作成果,還能及時反饋出我們工作中的問題。
有人會說,我們可以利用 Jenkins 插件來解決上述的問題。
的確,Jenkins 憑借著自己豐富的插件和較為成熟的社區,有著較高的拓展性,但是經過我們的調研和評估,發現由于整個系統的設計并不是一個集中式的管理系統,所以很多功能都局限于 Job 而非系統層面。
另外,由于對于數據的收集和存儲能力偏弱,所以我們經常要考慮如何解決數據保存的問題。
如果能夠完美的解決上述問題,從成本上來說,通過對 Jenkins 的二次開發的性價比相較于打造一個全新的系統就低了很多。
因此,我們認為一個擁有中央調度功能的系統可以為我們整個項目帶來諸多便利,所以打造一個 Hyperloop 這樣的系統的想法應運而生。
如何去搭建 Hyperloop?
1. 系統架構
從技術角度劃分,我們把 Hyperloop 劃分為 Web 前端、后端和工具鏈。前端專注于良好的用戶交互和清晰的數據展示,后端則負責數據收集分析、業務處理和任務調度,而工具鏈是負責具體的發版、集成等任務的執行。
后端接受來自前端用戶觸發的操作,反饋數據或者調用工具鏈執行相關任務,所有的任務數據流都流經后端,從而能夠保證構建數據的完整性。
2. 業務模型
插件化檢查方式
組件的發布和集成階段都需要有準入,但實際上每個組件的準入步驟并不一定完全一致,并且隨著業務的需要,準入步驟也會相應的調整。面對這樣的需求,將準入步驟插件化則是一個比較靈活方式。
能力
工具鏈會先行開發準入步驟,這是一個可以接受參數的 fastlane 的 action。完成開發后,我們會在 Hyperloop 后臺上線對應的能力。
組件在自己的設置界面可以看到 Hyperloop 中所有已上線的能力,有一些是必選的,則默認就已經選上了,其他非必選的能力,則有該組件配置權限的同學可以根據自己業務需要勾選。
有一些檢查,例如 warning 數,是可以設置一個目標值的,在未來的某個時間點達到什么樣的目標,之后每一次準入都會由后臺動態計算本次需要達到的目標。
App 的打包集成準入則是通過打包模板的方式來配置準入步驟,相較于發版的簡單方式,集成打包則需要有多種情況供用戶選擇。除了和組件一樣,可以配置目標值,打包模板還可以靈活設置參數配置方式。
策略
將某個能力勾選之后,組件或者打包模板中就會生成對應的策略,不同于能力的是,策略中保存了組件或打包模板中業務方配置的參數。
步驟
每一次組件發版,每一次集成打包,都會生成一個版本,Hyperloop 后臺會根據能力和策略生成本次執行時具體的步驟,和策略類似,不過步驟中參數則是更為具體的值。
隨著發版和集成任務被觸發,工具鏈被調用后會請求 Hyperloop 后臺,下發本次執行的步驟,工具鏈拿到后就會按照具體的步驟和參數來執行任務了。
這樣插件化的模型設計,大大減少了工具鏈的開發成本,并且增加了整個準入步驟的靈活性,更加符合業務方自己的需求。
3. 功能實現
組件發版
組件是支撐整個美團 iOS 客戶端的基礎,前面也提到了,現在有超過300個組件通過我們的這個系統來發布,而在整個開發周期中,又有超過700次的發布需求。而作為整個客戶端的發布流程的起點,組件發版又有著尤為重要的作用,所以在整個系統搭建之初,組件發版是我們優先考慮的功能。
在第一階段,我們實現了基本的組件發布能力,業務方已經可以通過 Hyperloop 來對自己的業務組件進行發版。
但是對于一個全新的發布調度系統,僅僅用于發版是遠遠不夠的,既然我們可以做到數據的匯總分析,那么就可以通過在準入中添加一些特殊的能力,使項目中一些可以優化的指標得以實現,例如 warning 數的分析和限制。所以在完成了基本的發版準入后,我們又增加了一些可選的優化能力。
提到限制,可不僅僅是設置一個數值這么簡單,Hyperloop 允許用戶設置目標值和目標時間,動態地計算出每一次需要達到的數值,從而通過程序這種強制性的手段,來實現工程上面的優化。
有了準入限制,只能說完成了這個功能的一大部分,數據的的展示有多種多樣,既然我們拿到了組件發布時的全部數據,那就讓它有一個很好的展示。所以第三階段,我們又完善了整個組件發布的信息,以及添加了一些功能性的能力,例如 Changelog 的生成,以豐富整個發布過程,讓用戶能夠更清楚地了解到這一次發布的狀況。
如果發布失敗了,我們會在出錯的步驟中展示錯誤的原因和建議,以及出錯的 log,方便大家調查出錯原因。
打包集成
組件發布后,就去集成到美團 iOS 客戶端的主工程里面,所以完成了發布功能后,我們就開始著手實現打包集成。
作為美團點評最大的 iOS 項目之一,美團 iOS 客戶端不管是從業務量級,還是整個打包集成發布的流程,都是非常復雜的,參與 RD 人數也很多。當我們對全公司 iOS 項目分析后發現,如果實現了美團 iOS 客戶端的打包集成,那么別的獨立 App 也都能夠適用。
在這個功能的第一階段,我們簡單的適配了之前的集成流程,為了讓整個發版集成流程盡早可以完整的連起來。滿足了基本可用的條件后,我們參考組件發布的步調,開始完善整個集成的流程。第一步,就是增加準入限制。
如果說組件發版是整個美團 iOS 客戶端搭建的第一步,那么集成就是第二步,也是至關重要的一步。作為集成來講,準入尤為重要,可以說客戶端的各項性能指標是否符合要求,基本上就看集成準入是否能夠過濾掉不合格的組件。
所以我們會在基本的集成能力中加入例如包大小檢查這樣的增強型準入檢查,而在集成包構建完成之后,會進行自動化測試,保證本次集成除了沒有編譯錯誤,還不會有運行時問題。
當然了,作為二進制集成,我們還需要保證我們的組件間 APIs 調用正確,所以我們還會進行全源碼編譯,來確保沒有調用不一致的問題。
同樣,Hyperloop 在集成時所收集的信息,都會展示出來。不同于組件發布,集成后有諸多產物,各位 RD 可能會有下載需求,我們還會把所有的產物都打包上傳到美團云上,提供下載鏈接。
我們雖說有內部的分發平臺,但是高頻次的集成帶來的集成包數量也是非常多的,在集成詳情界面提供可以掃一掃就能下載的二維碼,方便 RD 和 QA 下載下來驗證自己的需求。
除了集成,我們還有個很重要的功能就是打包。作為一些小一點的業務方,自己并沒有什么集成的需求,而更多的是希望能夠按照自己的需求來打一個包出來。例如用于驗證功能的 feature test,用戶每日構建的 daily build,或者說用于提交 iTC(iTunes Connect) 的 App Store build。
之前的做法是,業務方自己創建 Jenkins job,自己配置構建腳本,雖說業務方之間任務獨立,但是基本上很大程度都是重復的。
Hyperloop 為各業務方提供通用的打包能力,業務方可以根據需求組成自己的打包模板,每一次打包的時候只需要根據自己的需求選擇相應的打包模板即可。
雖說能力都有參數,但是在設置打包模板的時候可以固定配置一些參數,簡化每一次的操作步驟,甚至像 App Store build 就可以做到完全零配置,點一下打包即可完成構建觸發。
同樣的,完成打包后,相應的界面也能看到本次構建的詳細信息。
去 Jenkins 化
從一開始我們就提到 Jenkins 對于我們普通的 iOS 開發者而言,不管是使用成本還是維護成本都是比較高的,而其他方面諸多限制致使我們想要搭建一個這樣的系統。
雖說是因為要去 Jenkins,但是我們在一開始也只是降低了對 Jenkins 的依賴,但還是利用 Jenkins 來分配執行任務。
而仔細審視一下,我們不難發現,我們對 Jenkins 的使用也僅僅是分配任務了,為了這一個簡單的需求我們還要保留 Jenkins,維護兩套系統,并且通過系統間 APIs 來通信,非常惡心。
比較巧合的是,后臺和工具鏈都是 Ruby 棧的,這樣來看,工具鏈完全可以成為后臺模塊中的一部分,通過消息隊列就能達到我們想要的效果,并且直接對數據庫的操作,統一的功能開發,也讓整套邏輯變得十分優雅。
這樣來看,Jenkins 就徹底的從我們的視線中消失了。
通知能力
如何才能讓用戶知道整個流程的結果?如何才能更好地向用戶反饋出現的問題?除了前端界面展示詳細數據外,主動通知能力也是個非常重要的功能,畢竟大家不可能一直守在 Hyperloop 面前。
我們提供有內部 IM 工具(大象)的消息通知,重要的問題我們還有郵件通知。
如果出現問題,用戶會第一時間收到來自 Hyperloop 的消息,當然了,如果順利結束,系統也會恭喜你順利完成了此次構建。
除了常規的構建通知,一些重要事項的提醒我們也是有能力告知的,例如開發者證書是否要過期? Provisioning Profile 是否要更新?Hyperloop 有什么需要通知大家的新聞等等……
能否解決我們的問題?
說了這么多,Hyperloop 是否能夠解決我們之前所遇到的問題呢?
1. 通過新版工具鏈和系統后臺解決 Jenkins 所帶來的問題
我們通過新的系統來取代 Jenkins,人性化的界面和交互流程,清晰的信息展示和問題反饋,基本上讓用戶能很輕松地完成自己的發布流程,大大降低了他們的學習操作成本。
2. 中央集中式系統取代分散式的管理方式
Hyperloop 是一個中央集中式的系統,所有的業務方可以根據自己的業務來使用我們提供的能力,減少了各自為政所帶來的冗余,重復的任務配置,也方便我們流程維護和技術升級。不管是運維成本還是技術推動成本都極大地降低。
3. 著重凸顯數據的重要性
不同于之前的流程,Hyperloop 有著強大的數據匯總和分析能力,由于對于整個流程的參與,所有的信息都存儲在 Hyperloop 中,方便分析和展示。作為日常工作的重要指標,數據扮演著尤為重要的角色。
有了數據,我們就能從數據中發現問題,解決問題,從而優化我們的項目,也能從方向性上提升我們的工作效率。
展望未來
Hyperloop 雖說已經能夠處理解決大多數發布流程相關的任務,但是未來依然任重而道遠。
1. 監控統計
雖說我們能夠匯總和分析數據,但是很多方面的監控和統計力度仍然不夠,例如靜態分析問題,重復代碼檢查等等。只有不斷豐富整個工程中的監控指標,才能逐漸暴露出隱藏在項目中的一些問題,解決并且優化整個項目。
2. 上下游關系
目前整個 Hyperloop 上下游中已經充斥著 Git 托管平臺,美團云,iTC 以及 IM 等諸多系統,可是作為整個開發流程來講,我們可能還需要和更多系統之間的通信,例如在構建完成后可以自動管理相應的任務,可以在一個階段完成后自動產生一個統計報表輸出到 wiki 中等等。通過上下游多系統聯動,從而進一步提升我們的開發效率。
3. 多端支持
Hyperloop 目前僅僅是支持 iOS 業務,但是整個發布工程可是不限于 iOS 的,所以我們未來希望能夠讓所有還在發布工程中掙扎的同學們都能搭乘上 Hyperloop,讓開發專注于開發的本質,發布僅僅是點一個鍵的事情。
4. 流程優化
上面也提到過,我們一些功能是延承自之前的流程,而作為一個全新的系統,我們完全可以用更高效的流程來提升構建效率,運用政治經濟學中生產力和生產關系的理論,我們有了更強大的生產力,那也需要有與之相適應的生產關系才能保證和進一步提高生產力。流程,正是如此。
我們做了這么多,其實本質就是讓 RD 專注于開發,減少無謂的時間消耗,而發布的事情就讓系統化的東西來解決。同時又能通過集中式的系統來保證整個流程的管控力度和數據統計,從另一個方面反推我們的開發。這就是 Hyperloop 名字的意義,不僅僅是個 loop,還是個現代、簡潔、高效的 loop。
作者簡介
恩生(@zesming),美團點評高級工程師,2014年加入原美團,曾負責美團 iOS 客戶端的首頁、訂單等重要業務。目前負責 iOS 發布工程的流程制定、Hyperloop 的功能設計和整個系統后臺開發。
總結
以上是生活随笔為你收集整理的Hyperloop,让发布简洁高效的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据驱动精准化营销在大众点评的实践
- 下一篇: Spring Cloud构建微服务架构: