美团点评移动端基础日志库——Logan
背景
對(duì)于移動(dòng)應(yīng)用來說,日志庫是必不可少的基礎(chǔ)設(shè)施,美團(tuán)點(diǎn)評(píng)集團(tuán)旗下移動(dòng)應(yīng)用每天產(chǎn)生的眾多種類的日志數(shù)據(jù)已經(jīng)達(dá)到幾十億量級(jí)。為了解決日志模塊普遍存在的效率、安全性、丟失日志等問題,Logan基礎(chǔ)日志庫應(yīng)運(yùn)而生。
現(xiàn)存問題
目前,業(yè)內(nèi)移動(dòng)端日志庫大多都存在以下幾個(gè)問題:
- 卡頓,影響性能
- 日志丟失
- 安全性
- 日志分散
首先,日志模塊作為底層的基礎(chǔ)庫,對(duì)上層的性能影響必須盡量小,但是日志的寫操作是非常高頻的,頻繁在Java堆里操作數(shù)據(jù)容易導(dǎo)致GC的發(fā)生,從而引起應(yīng)用卡頓,而頻繁的I/O操作也很容易導(dǎo)致CPU占用過高,甚至出現(xiàn)CPU峰值,從而影響應(yīng)用性能。
其次,日志丟失的場景也很常見,例如當(dāng)用戶的App發(fā)生了崩潰,崩潰日志還來不及寫入文件,程序就退出了,但本次崩潰產(chǎn)生的日志就會(huì)丟失。對(duì)于開發(fā)者來說,這種情況是非常致命的,因?yàn)檫@類日志丟失,意味著無法復(fù)現(xiàn)用戶的崩潰場景,很多問題依然得不到解決。
第三點(diǎn),日志的安全性也是至關(guān)重要的,絕對(duì)不能隨意被破解成明文,也要防止網(wǎng)絡(luò)被劫持導(dǎo)致的日志泄漏。
最后一點(diǎn),對(duì)于移動(dòng)應(yīng)用來說,日志肯定不止一種,一般會(huì)包含端到端日志1、代碼日志、崩潰日志、埋點(diǎn)日志這幾種,甚至?xí)?。不同種類的日志都具有各自的特點(diǎn),會(huì)導(dǎo)致日志比較分散,查一個(gè)問題需要在各個(gè)不同的日志平臺(tái)查不同的日志,例如端到端日志還存在日志采樣,這無疑增加了開發(fā)者定位問題的成本。
面對(duì)美團(tuán)點(diǎn)評(píng)幾十億量級(jí)的移動(dòng)端日志處理場景,這些問題會(huì)被無限放大,最終可能導(dǎo)致日志模塊不穩(wěn)定、不可用。然而,Logan應(yīng)運(yùn)而生,漂亮地解決了上述問題。
簡介
Logan,名稱是Log和An的組合,代表個(gè)體日志服務(wù)的意思,同時(shí)也是金剛狼大叔的大名。通俗點(diǎn)說,Logan是美團(tuán)點(diǎn)評(píng)移動(dòng)端底層的基礎(chǔ)日志庫,可以在本地存儲(chǔ)各種類型的日志,在需要時(shí)可以對(duì)數(shù)據(jù)進(jìn)行回?fù)坪头治觥?/p>
Logan具備兩個(gè)核心能力:本地存儲(chǔ)和日志撈取。作為基礎(chǔ)日志庫,Logan已經(jīng)接入了集團(tuán)眾多日志系統(tǒng),例如端到端日志、用戶行為日志、代碼級(jí)日志、崩潰日志等。作為移動(dòng)應(yīng)用的幕后英雄,Logan每天都會(huì)處理幾十億量級(jí)的移動(dòng)端日志。
設(shè)計(jì)
作為一款基礎(chǔ)日志庫,在設(shè)計(jì)之初就必須考慮如何解決日志系統(tǒng)現(xiàn)存的一些問題。
卡頓,影響性能
I/O是比較耗性能的操作,寫日志需要大量的I/O操作,為了提升性能,首先要減少I/O操作,最有效的措施就是加緩存。先把日志緩存到內(nèi)存中,達(dá)到一定大小的時(shí)候再寫入文件。為了減少寫入本地的日志大小,需要對(duì)數(shù)據(jù)進(jìn)行壓縮,為了增強(qiáng)日志的安全性,需要對(duì)日志進(jìn)行加密。然而這樣做的弊端是:
- 對(duì)Android來說,對(duì)日志加密壓縮等操作全部在Java堆里面。由于日志寫入是一個(gè)高頻的動(dòng)作,頻繁地堆內(nèi)存操作,容易引發(fā)Java的GC,導(dǎo)致應(yīng)用卡頓;
- 集中壓縮會(huì)導(dǎo)致CPU短時(shí)間飆高,出現(xiàn)峰值;
- 由于日志是內(nèi)存緩存,在殺進(jìn)程、Crash的時(shí)候,容易丟失內(nèi)存數(shù)據(jù),從而導(dǎo)致日志丟失。
Logan的解決方案是通過Native方式來實(shí)現(xiàn)日志底層的核心邏輯,也就是C編寫底層庫。這樣做不光能解決Java GC問題,還做到了一份代碼運(yùn)行在Android和iOS兩個(gè)平臺(tái)上。同時(shí)在C層實(shí)現(xiàn)流式的壓縮和加密數(shù)據(jù),可以減少CPU峰值,使程序運(yùn)行更加順滑。而且先壓縮再加密的方式壓縮率比較高,整體效率較高,所以這個(gè)順序不能變。
日志丟失
加緩存之后,異常退出丟失日志的問題就必須解決,Logan為此引入了MMAP機(jī)制。MMAP是一種內(nèi)存映射文件的方法,即將一個(gè)文件或者其它對(duì)象映射到進(jìn)程的地址空間,實(shí)現(xiàn)文件磁盤地址和進(jìn)程虛擬地址空間中一段虛擬地址的一一對(duì)應(yīng)關(guān)系。MMAP機(jī)制的優(yōu)勢是:
- MMAP使用邏輯內(nèi)存對(duì)磁盤文件進(jìn)行映射,操作內(nèi)存就相當(dāng)于操作文件;
- 經(jīng)過測試發(fā)現(xiàn),操作MMAP的速度和操作內(nèi)存的速度一樣快,可以用MMAP來做數(shù)據(jù)緩存;
- MMAP將日志回寫時(shí)機(jī)交給操作系統(tǒng)控制。如內(nèi)存不足,進(jìn)程退出的時(shí)候操作系統(tǒng)會(huì)自動(dòng)回寫文件;
- MMAP對(duì)文件的讀寫操作不需要頁緩存,只需要從磁盤到用戶主存的一次數(shù)據(jù)拷貝過程,減少了數(shù)據(jù)的拷貝次數(shù),提高了文件讀寫效率。
引入MMAP機(jī)制之后,日志丟失問題得到了有效解決,同時(shí)也提升了性能。不過這種方式也不能百分百解決日志丟失的問題,MMAP存在初始化失敗的情況,這時(shí)候Logan會(huì)初始化堆內(nèi)存來做日志緩存。根據(jù)我們統(tǒng)計(jì)的數(shù)據(jù)來看,MMAP初始化失敗的情況僅占0.002%,已經(jīng)是一個(gè)小概率事件了。
安全性
日志文件的安全性必須得到保障,不能隨意被破解,更不能明文存儲(chǔ)。Logan采用了流式加密的方式,使用對(duì)稱密鑰加密日志數(shù)據(jù),存儲(chǔ)到本地。同時(shí)在日志上傳時(shí),使用非對(duì)稱密鑰對(duì)對(duì)稱密鑰Key做加密上傳,防止密鑰Key被破解,從而在網(wǎng)絡(luò)層保證日志安全。
日志分散
針對(duì)日志分散的情況,為了保證日志全面,需要做本地聚合存儲(chǔ)。Logan采用了自研的日志協(xié)議,對(duì)于不同種類的日志都會(huì)按照Logan日志協(xié)議進(jìn)行格式化處理,存儲(chǔ)到本地。當(dāng)需要上報(bào)的時(shí)候進(jìn)行集中上報(bào),通過Logan日志協(xié)議進(jìn)行反解,還原出不同日志的原本面貌。同時(shí)Logan后臺(tái)提供了聚合展示的能力,全面展示日志內(nèi)容,根據(jù)協(xié)議綜合各種日志進(jìn)行分析,使用時(shí)間軸等方式展示不同種日志的重要信息,使得開發(fā)者只需要通過Logan平臺(tái)就可以查詢到某一段時(shí)間App到底產(chǎn)生了哪些日志,可以快速復(fù)現(xiàn)問題場景,定位問題并處理。
關(guān)于Logan平臺(tái)是如何展示日志的,下文會(huì)再進(jìn)行說明。
架構(gòu)
首先,看一下Logan的整體架構(gòu)圖:
Logan自研的日志協(xié)議解決了日志本地聚合存儲(chǔ)的問題,采用先壓縮再加密的順序,使用流式的加密和壓縮,避免了CPU峰值,同時(shí)減少了CPU使用。跨平臺(tái)C庫提供了日志協(xié)議數(shù)據(jù)的格式化處理,針對(duì)大日志的分片處理,引入了MMAP機(jī)制解決了日志丟失問題,使用AES進(jìn)行日志加密確保日志安全性,并且提供了主動(dòng)上報(bào)接口。Logan核心邏輯都在C層完成,提供了跨平臺(tái)支持的能力,在解決痛點(diǎn)問題的同時(shí),也大大提升了性能。
日志分片
Logan作為日志底層庫,需要考慮上層傳入日志過大的情況。針對(duì)這樣的場景,Logan會(huì)做日志分片處理。以20k大小做分片,每個(gè)切片按照Logan的協(xié)議進(jìn)行存儲(chǔ),上報(bào)到Logan后臺(tái)的時(shí)候再做反解合并,恢復(fù)日志本來的面貌。
那么Logan是如何進(jìn)行日志寫入的呢?下圖為Logan寫日志的流程:
性能
為了檢測Logan的性能優(yōu)化效果,我們專門寫了測試程序進(jìn)行對(duì)比,讀取16000行的日志文本,間隔3ms,依次調(diào)用寫日志函數(shù)。
首先對(duì)比Java實(shí)現(xiàn)和C實(shí)現(xiàn)的內(nèi)存狀況:
Java:
C:
可以看出Java實(shí)現(xiàn)寫日志,GC頻繁,而C實(shí)現(xiàn)并不會(huì)出現(xiàn)這種情況,因?yàn)樗粫?huì)占用Java的堆內(nèi)存。那么再對(duì)比一下Java實(shí)現(xiàn)和C實(shí)現(xiàn)的CPU使用情況:
C實(shí)現(xiàn)沒有頻繁的GC,同時(shí)采用流式的壓縮和加密避免了集中壓縮加密可能產(chǎn)生的CPU峰值,所以CPU平均使用率會(huì)降低,如上圖所示。
特色功能
主動(dòng)上報(bào)
Logan日志回?fù)?#xff0c;依賴于Push透傳??蛻舳吮粏拘呀邮誔ush消息,受到一些條件影響:
- Android想要后臺(tái)喚醒App,需要確保Push進(jìn)程在后臺(tái)存活;
- iOS想要后臺(tái)喚醒APP,需要確保用戶開啟后臺(tái)刷新開關(guān);
- 網(wǎng)絡(luò)環(huán)境太差,Android上Push長連建立不成功。
如果無法喚醒App,只有在用戶再次進(jìn)入App時(shí),Push通道建立后才能收到推送消息,以上是導(dǎo)致Logan日志回?fù)茣?huì)有延遲或收不到的根本原因,從分析可以看出,Logan系統(tǒng)回?fù)频淖畲笃款i在于Push系統(tǒng)。那么能否拋開Push系統(tǒng)得到Logan日志呢?先來看一下使用日志回?fù)品绞降牡湫蛨鼍?#xff1a;
其中最大的障礙在于Push觸達(dá)用戶。那么主動(dòng)上報(bào)的設(shè)計(jì)思路是怎樣的呢?
通過在App中主動(dòng)調(diào)用上報(bào)接口,用戶直接上報(bào)日志的方式,稱之為Logan的主動(dòng)上報(bào)。主動(dòng)上報(bào)的優(yōu)勢非常明顯,跳過了Push系統(tǒng),讓用戶在需要的時(shí)候主動(dòng)上報(bào)Logan日志,開發(fā)者再也不用為不能及時(shí)撈到日志而煩惱,在用戶投訴之前就已經(jīng)拿到日志,便于更高效地分析解決問題。
線上效果
Logan基礎(chǔ)日志庫自2017年9月上線以來,運(yùn)行非常穩(wěn)定,大大提高了集團(tuán)移動(dòng)開發(fā)工程師分析日志、定位線上問題的效率。
Logan平臺(tái)時(shí)間軸日志展示:
Logan日志聚合詳情展示:
作為基礎(chǔ)日志庫,Logan目前已經(jīng)接入了集團(tuán)眾多日志系統(tǒng):
- CAT端到端日志
- 埋點(diǎn)日志
- 用戶行為日志
- 代碼級(jí)日志
- 網(wǎng)絡(luò)內(nèi)部日志
- Push日志
- Crash崩潰日志
現(xiàn)在,Logan已經(jīng)接入美團(tuán)、大眾點(diǎn)評(píng)、美團(tuán)外賣、貓眼等眾多App,日志種類也更加豐富。
展望未來
H5 SDK
目前,Logan只有移動(dòng)端版本,支持Android/iOS系統(tǒng),暫不支持H5的日志上報(bào)。對(duì)于純JS開發(fā)的頁面來說,同樣有日志分散、問題場景復(fù)現(xiàn)困難等痛點(diǎn),也迫切需要類似的日志底層庫。我們計(jì)劃統(tǒng)一H5和Native的日志底層庫,包括日志協(xié)議、聚合等,Logan的H5 SDK也在籌備中。
日志分析
Logan平臺(tái)的日志展示方式,我們還在探索中。未來計(jì)劃對(duì)日志做初步的機(jī)器分析與處理,能針對(duì)某些關(guān)鍵路徑給出一些分析結(jié)果,讓開發(fā)者更專注于業(yè)務(wù)問題的定位與分析,同時(shí)希望分析出用戶的行為是否存在風(fēng)險(xiǎn)、惡意請(qǐng)求等。
思考題
本文給大家講述了美團(tuán)點(diǎn)評(píng)移動(dòng)端底層基礎(chǔ)日志庫Logan的設(shè)計(jì)、架構(gòu)與特色,Logan在解決了許多問題的同時(shí),也會(huì)帶來新的問題。日志文件不能無限大,目前Logan日志文件最大限制為10M,遇到大于10M的情況,應(yīng)該如何處理最佳?是丟掉前面的日志,還是丟掉追加的日志,還是做分片處理呢?這是一個(gè)值得深思的問題。
作者簡介
- 白帆,美團(tuán)點(diǎn)評(píng)基礎(chǔ)框架研發(fā)組Android技術(shù)專家。2015年加入原大眾點(diǎn)評(píng)。先后負(fù)責(zé)客戶端長連網(wǎng)絡(luò)SDK、Logan日志SDK等項(xiàng)目。目前主導(dǎo)Logan日志SDK的開發(fā)和推廣。
- 立成,美團(tuán)點(diǎn)評(píng)基礎(chǔ)框架研發(fā)組Android高級(jí)開發(fā)工程師。2016年加入美團(tuán)點(diǎn)評(píng),在Android開發(fā)、跨平臺(tái)開發(fā)、移動(dòng)端測試等領(lǐng)域有一定的實(shí)踐經(jīng)驗(yàn),熱愛新技術(shù)并愿意付諸實(shí)踐,致力于產(chǎn)出高質(zhì)量代碼。
招聘信息
點(diǎn)評(píng)平臺(tái)移動(dòng)研發(fā)中心,base上海,提供美團(tuán)點(diǎn)評(píng)集團(tuán)大多數(shù)移動(dòng)端底層基礎(chǔ)設(shè)施,包含網(wǎng)絡(luò)通信、移動(dòng)監(jiān)控、推送觸達(dá)、動(dòng)態(tài)化引擎、移動(dòng)研發(fā)工具等。同時(shí)團(tuán)隊(duì)還承載流量分發(fā),UGC,內(nèi)容生態(tài),整合中心等業(yè)務(wù)研發(fā),長年虛位以待有志于專注移動(dòng)端研發(fā)的各路英雄。歡迎投遞簡歷:hui.zhou#dianping.com。
解釋說明
總結(jié)
以上是生活随笔為你收集整理的美团点评移动端基础日志库——Logan的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 阿里最全Java面试100题汇总:涵盖天
- 下一篇: 细说ReactiveCocoa的冷信号与