
點選關注“有贊coder”
擷取更多技術幹貨哦~
作者:王劍标
部門:電商移動
背景 & 痛點 & 價值
穩定性始終會是一家成功公司的重要名額,在移動端亦是如此。跟大部分創業公司一樣,有贊在創業初期選擇以核心業務為主, 在一些基礎設施的搭建上主要以使用三方平台為主(騰訊bugly)。随着業務的發展和bugly的長期不維護,慢慢出現一些三方平台的弊端。例如:
- 某次版本上線之後,沒有及時發現其隐藏的Crash, 導緻故障産生
- Crash發生之後,無法根據特定規則分給某位處理人。
- 某個版本上線灰階時,該版本在特定角色下存在Crash。這個時候沒法中斷灰階版本的下發
crash平台建設的線路規劃
為了解決這些問題,我們就開始着手搭建自有的Crash回報平台。平台建設的規劃大緻的路線是:
- 基礎架構搭建。Crash的收集、上報、分類、檢視、處理
- 增加三方平台沒有的功能。實時監控、告警、日報
- 補齊三方平台的功能,Crash趨勢統計、Crash符号化
crash平台的功能集
總結下來,Crash平台大概需要有以下功能:
- Crash收集:某次Crash從發生,儲存本地到上報的過程
- Crash檢視:檢視Crash的發生堆棧,版本分布,發生頁面,操作頁面路徑,幫助處理人快速定位問題。
- Crash處理人以及狀态:将某個Crash配置設定給指定人,發送通知。處理人修複完成之後,修改Crash的狀态。
- Crash分類:根據上報的Crash将Crash進行分組,不同機型、不同版本可能發生同一個Crash,某個Crash辨別某段代碼錯誤。
- Crash告警檢測:針對新版本引入的Crash以及因為服務端變更引起的老版本Crash,增加告警功能,第一時間發現影響面廣的Crash問題。
- Crash報告:每日報告,本日Crash情況,讓團隊的小夥伴能夠清晰的了解到當天整體的crash情況,及時解決crash次數較多的問題。
Crash平台整體設計
得益于有贊在資料埋點方面的建設,Crash資料收集可以通過埋點通道的進行上報,然後通過Flink實時計算任務将上報上來的Crash實時進行撈取、分組、實時監控,最後落到我們自己的業務資料庫中。Crash平台上可以對Crash進行浏覽,配置設定,标記解決等等。整個Crash上報過程、後續處理流程如下圖:
為了避免crash堆棧的資料量過大,crash堆棧等長字段存儲至HBase. Mysql中隻要存儲前128預覽字元與Hbase中的row_key即可
一、實作方案
1.1 Crash發生時的攔截+上報
Crash的攔截主要依靠各端系統的攔截機制。以Android為例,首先需要實作
Thread.UncaughtExceptionHandler
接口,在初始化的時候将線程預設的Handler替換為我們攔截的Handler(當然别忘了調用下原先預設的handler)。
1.2 Crash收集、資料整理--分組歸類及自動配置設定處理人
1.2.1 Crash收集
Crash收集主要由埋點平台提供的實時計算任務來運作。
為什麼要用埋點平台, 而不是用自己上報?
一個原因是避免重複造輪子,再者埋點平台需要設計之初就是為了超大資料量而設計,支援分布式存儲,實時響應資料分析等等優點。而這些都是我們Crash收集所需要的,是以選擇了通過埋點平台。
埋點平台在收到來自用戶端的資料後為我們做了哪些工作
首先我們先來看下平台工作時的整體流程圖:
日志流轉主要環節:
- 前端監控使用者行為,收集并通過http請求上報
- NIO高并發日志接收服務将日志轉發到rsyslog伺服器中
- rsyslog伺服器再通過logstash轉發到kafka原始日志中
- flink實時ETl任務将原始日志加工成标準中間層格式,并繼續落地到kafka
- 最後消息會到我們的Crash收集flink任務程式crash-clollection-task
crash-clollection-task實時任務隻要訂閱相關的Topic,就能實時接收到訂閱相關的Topic消息:
消息:
// 隐去敏感資料,更改為測試資料
因為我們訂閱的Crash涉及到的有贊全部移動端的Crash,是以訂閱了全量的資料。在代碼中對資料進行過濾,隻過濾Crash相關的資料:
@Override
這樣就隻剩下我們關心的Crash相關的資料了。
1.2.2 分組歸類、自動配置設定處理人
分組歸類
分組歸類是必不可少的一個工作,理想情況下。針對同一處代碼錯誤的Crash上報上來,可以精确的将其分組歸類。 但是因為代碼混淆、同一處代碼錯誤,錯誤堆棧缺不能完全比對等等原因。做到這一點其實不容易。 那目前采取的做法是以App辨別、系統、crash類型、crash錯誤原因、crash發生頁面這五個次元來将crash配置設定到指定組。 其中App辨別、系統是用來區分具體哪個App上報的crash的。 crash類型、crash錯誤原因是來根據crash發生的錯誤堆棧來區分出不同錯誤的類型。 以Android堆棧為例: crashType為“java.lang.OutOfMemoryError”,crashReson為“Failed to allocate a 8306416 byte allocation with 502326 free bytes and 490KB until OOM” crash發生頁面是用來區分不同頁面發生的同一個錯誤類型的。 最後将這些字段通過MD5算法計算出一個
groupId
自動配置設定處理人
自動配置設定處理人主要目的是為了讓對應業務的人快速處理屬于自己業務的Crash。為此做了兩種方式的自動配置設定。
- 配置清單配置設定
- 曆史頁面自動配置設定
配置清單配置設定
我們先來看下配置清單:
{
"modules": [
{
"name": "xxxxSDK",
"key_stacks": [
"com.youzan.mobile.xxxx"
],
"cas_id": 10086
}
}
清單中配置着子產品清單,子產品中主要有兩個字段keystacks(關鍵堆棧)、casid(子產品負責人)。有crash上報時,會根據子產品清單一一比對其crash堆棧,看是否能比對上若比對上,則将該crash配置設定給該子產品負責人。 自動配置設定處理人的初步比對就是讀取配置清單中的key_stacks, 然後從上報crash的堆棧中找是否包含目标堆棧。 如果包含就比對成功,會将該crash發送至配置好的messenger群中去,并且@casid字段指定的處理人。
曆史頁面自動配置設定
如果清單比對比對失敗,還會落入曆史頁面自動比對。與清單比對不同的是曆史頁面自動配置設定給該頁面上次的處理人。 當手動配置設定crash給指定人時,這張表中會記錄着這個crash發生頁面配置設定給某個人。例如 工作台頁面有一個crash發生,是配置設定給張三。那麼當下次工作台頁面有crash發生時,都會以此配置設定給張三。
2.2 Crash實時監控、每日報告
得益于實時計算平台,我們能很容易做到實時監控。我們可以做到隻要有Crash上報,就會向企業微信對應的處理人發送消息通知。這樣做的在某種程度上來說是無意義的,尤其是疑難雜症問題多的時候,最多的時候一天能産生1000條通知,對于這樣的通知無異于沒有通知。 後來發現我們報上來大部分問題都是針對最新版本解決就OK,因為老版本要麼是趨于穩定。要麼如果因為後端某個接口變動,那麼新老版本同樣會受到影響。是以就隻要監控最新版本。是以問題就變成如何版本過濾。
2.2.1 版本過濾
想要過濾版本就需要知道目前某個App的最新版本多少。目前有贊移動端的打包發版控制已經都使用自研的建構釋出平台。
crash上報之後,隻要它的版本号大于等于最新全量的版本号,就實時上報到秒級響應群,以便及時發現最新版本、灰階版本、項目測試包的crash問題。
2.2.2 每日報告
每日報告功能有兩個目的,一是為了讓各個App負責人對每天的Crash大緻狀況有個大緻上的了解。二是為了讓沒時間及時處理的小夥伴,當有屬于自己的子產品,發生次數、影響面比較大的Crash出現時要引起重視。
基于這樣的目的我們在每日報告中加了每日Crash變化趨勢(與前一日相比)、每日Crash Top N兩大塊。這裡主要講下設計思路。
每日Crash變化趨勢
日報中會取昨日的crash與今日的crash對比。如漲幅過大,則說明很可能新版本是存在問題的,需要引起注意。
碰到的坑
起初昨日與今日的Crash次數是按照自然日取的。這樣有個問題,就是昨日的次數是一整天的,今天的次數不是一整天。是以這裡對比,應該以報告時間往前24小時内、48~24小時,這樣來對比。才能正常回報Crash的變化趨勢。
每日Crash Top N
排序規則
排序的背後是Crash的影響面大小,影響面大的排在前。這樣讓處理人與管理者能每天及時知曉影響大的Crash有哪些,是否需要及時處理等等目的。
我們為什麼選擇了Top3?
其實開始不是Top3 ,而是Top10。但是運轉一段時間後發現,crash問題并不多,每天彙報時都報Top10,會有大部分次數少的crash,會讓人失焦。無論是管理者還是處理人,都搞不清楚,某個問題是該及時處理還是可以延後處理。再集合運轉的這一段時間的平均資料,最終選擇了Top3。
技術實作
每日報告背後的技術實作有定時任務。起初使用的是SpringBoot自帶的定時任務。 功能都能實作,有一個麻煩的點就是調試起來不友善。比如配置10點報告的,難道要等到10點麼。或者改成1分鐘一次,那調式完成之後是不是又得改回來?後來使用了TSP,具體可參考 有贊排程系統 TSP 調試起來非常友善,定時任務也像普通接口的形式書寫即可。 日報的業務就是在不斷的聚合查詢當天的最新版本的資料,細節不再贅述,直接上日報最終效果圖:
2.3 Crash回報平台--管理背景
Crash管理背景的作用是提供Crash問題分析定位和Crash處理流程管理。
如何快速定位問題
為了友善快速定位在清單接口添加了最近上報資訊、發生過的系統版本、發生過的應用版本來幫處理人第一時間發現問題。 有這樣一個場景:
4.47.0改了某塊代碼之後,釋出至線上,因為使用者老資料的問題,Crash一直隐藏着帶到了線上。此時根據發生過的應用版本就能很快定位到Crash就是出現在4.47.0這個版本上。
類似的發生過的系統版本能幫助快速識别某個系統版本特定的問題。 Crash清單頁資訊:
更詳細的排查次元
為了降低排查難度,增加了Crash頁面路徑、Crash出錯堆棧、符号化等功能來增加排查的線索。 Crash詳情資訊:
詳情中展示全量的Crash堆棧資訊,以及最新上報的一次裝置相關資訊。目的是為了幫助排查Crash。
Crash離線日志
值得一提的是某些時候需要再結合Crash時App端的日志來綜合排查,這個點已經在着手設計排查,開始将Crash時跟日志綁定。後續在此頁面會直接顯示Crash時手機上的日志
總結
Crash回報平台目前還沒有實作Crash處理流程的閉環,存在大家在使用時不會去修改Crash的狀态等問題,接下來會對這個流程做整體優化,提升整體協作效率。随着接入的業務方越來越多,為了保證業務方能更加容易、快速的排查與定位問題,修複問題,需要做的工作還不少,比如Crash的分組更加準确,Android堆棧符号化,頑固Crash定時提醒等等。 Crash回報平台技術上來說他的綜合性比較高,涉及的技術棧有大資料技術、後端技術、前端技術、移動端技術等4端技術棧。開發一個綜合性的平台,不能單從技術層面去思考怎麼解決技術上的問題,更多的需要從整個平台的目的出發。就crash平台而言,需要以去搭建一套能快速發現Crash、及時修複Crash為目标去思考。而技術更多的是“鋤頭”,它隻是幫助實作“大豐收”的其中一個工具。 擴充閱讀:
- 有贊移動消息卡片動态化方案實踐
-
有贊移動端商品子產品的架構演變之路
-
有贊移動熱修複平台建設
-
有贊移動 App 一鍵切換網關實踐
-
有贊零售發票列印圖檔二值化方案
- 有贊 Android 崩潰保護的探索及實踐
- 有贊移動 iOS 元件化(子產品化)架構設計實踐
-
有贊Flutter插件開發與釋出
-
有贊移動如何做到并行灰階的複雜場景?
-
微商城訂單子產品重構實踐
Vol.330