性能優(yōu)化專場一共有四場分享,包括“Instagram Direct ?性能聊天產(chǎn)品”阴孟, “?淘iOS性能優(yōu)化探索”,“滴滴出? iOS 端瘦身實(shí)踐”和“微信 SQLite 數(shù)據(jù)庫 損壞恢復(fù)實(shí)踐”袍镀,除了微信的這個議題评疗,其他三場都現(xiàn)場聽了。
Instagram Direct ?性能聊天產(chǎn)品
這個演講個人感覺是兩天里面聽到的比較好的一次滞诺,PPT的結(jié)構(gòu)比較清晰形导,不會包含太過細(xì)節(jié)的內(nèi)容,主題明確习霹,演講的時候靠演講本身來闡述細(xì)節(jié)骤宣。
這個議題的主題是“高效可靠的數(shù)據(jù)端到端傳輸”,通過這個議題序愚,讓大家可以了解:移動應(yīng)用如何應(yīng)對不穩(wěn)定的網(wǎng)絡(luò)狀況,實(shí)現(xiàn)信息的穩(wěn)定傳輸等限;如何確保信息的有序傳播爸吮;如何將復(fù)雜的重試機(jī)制和應(yīng)用層開發(fā)隔離開來。
Instagram 是一個以圖片和視頻為核心的社區(qū)望门,用戶以年輕人為主形娇,月活達(dá)7億,而Direct是Instagram旗下的一款聊天產(chǎn)品筹误,月活為3.75億桐早。跟Facebook一樣,IM都被獨(dú)立出來厨剪,再想想國內(nèi)的微信哄酝,IM本身的在移動互聯(lián)網(wǎng)的重要性可見一斑,這也是阿里這么執(zhí)著的往這個方向發(fā)展這么多年的一個原因吧(似乎最近消停了很多)祷膳。
言歸正傳陶衅,Direct作為一款新的產(chǎn)品,在兩年的時間內(nèi)用戶規(guī)模增長達(dá)4億直晨,與之帶來的是新功能的不斷增加搀军,以及團(tuán)隊(duì)規(guī)模的不斷擴(kuò)大。這也導(dǎo)致了一個結(jié)果就是開發(fā)的模式勇皇,由一個小的負(fù)責(zé)多個功能的單平臺團(tuán)隊(duì)的開發(fā)模式罩句,轉(zhuǎn)變成一個團(tuán)隊(duì)專注于多個平臺的單個功能。這一點(diǎn)跟我們現(xiàn)在的開發(fā)模式很像敛摘,比如Viz組就負(fù)責(zé)iOS和Android兩塊所有的Widget的開發(fā)门烂。這也是因?yàn)楫?dāng)系統(tǒng)本身業(yè)務(wù)邏輯越來越復(fù)雜,功能模塊之間的區(qū)分度越來越大的一個必然的結(jié)果兄淫。
第一部分:前端架構(gòu)
Direct產(chǎn)品作為一款短消息應(yīng)用诅福,對“實(shí)時性”的要求非常高匾委,哪怕是滑動時稍微卡一點(diǎn),日活量就會有顯著的下降氓润;產(chǎn)品越來越復(fù)雜赂乐,團(tuán)隊(duì)的規(guī)模越來越大,隨之而來的就是如何確保代碼本身的可維護(hù)性咖气,特別是當(dāng)新人加入團(tuán)隊(duì)的時候挨措,如何使新人更容易的快速掌握代碼;敏捷開發(fā)模式下對功能的快速迭代要求很高崩溪,這就需要我們的產(chǎn)品技術(shù)架構(gòu)能夠適應(yīng)功能的隨時修改和增減浅役。這些都是Direct遇到的比較棘手的問題。
針對前面提到的三個問題伶唯,Direct相應(yīng)的對策分別是:首先是使用純Native開發(fā)來確保產(chǎn)品的性能達(dá)到最優(yōu)觉既,這里對開發(fā)代價(jià)本身的敏感度就降低了,跟我們自己的產(chǎn)品一樣乳幸,對產(chǎn)品本身運(yùn)行的性能要求很高瞪讼,決定了我們要盡可能的使用Native的開發(fā)方式來充分優(yōu)化產(chǎn)品的性能;代碼模塊化粹断,壓縮單個代碼的長度符欠,使代碼簡單清晰,這一點(diǎn)上我們的產(chǎn)品做得還不夠瓶埋,基本各個功能模塊的耦合度過大希柿,也有部分代碼的長度過長,現(xiàn)在導(dǎo)致維護(hù)起來的成本也越來越大养筒;使用信息流模式讓信息在不同模塊之間流動曾撤,使得測試和調(diào)試更加順暢。
AB測試:對于存在多種方案面臨選擇時晕粪,同時面向客戶盾戴,通過手機(jī)用戶體驗(yàn)數(shù)據(jù)和業(yè)務(wù)數(shù)據(jù),最終評估出最好的版本正式采用兵多。AB測試多用在UI和流程方面尖啡,特別是主觀性偏強(qiáng)的功能模塊,難以通過討論做出決策時剩膘,讓終端用戶來做出這個選擇衅斩。
這個信息流圖是相對高級的模塊區(qū)分,其中服務(wù)層是連接界面與基礎(chǔ)功能模塊的關(guān)鍵怠褐。從界面產(chǎn)生的操作畏梆,通過從服務(wù)層相應(yīng)的服務(wù)實(shí)現(xiàn)
作為一款聊天產(chǎn)品,最主要的問題就是列表過長,可以看微信就是一個直接的例子:在消息界面奠涌,存在著你和朋友聊天的列表宪巨,各種公眾號的信息,各種群的信息等等溜畅。Direct也類似捏卓,這會導(dǎo)致處理這個長列表的代碼會過于龐大,因?yàn)橄⒌念愋投鄻哟雀瘢矔勾a過于復(fù)雜怠晴。
Direct采取的應(yīng)對是切分長列表類,將不同的消息單獨(dú)處理浴捆,使用獨(dú)立的Section Controller
經(jīng)典的MVC模式的最主要的問題就是Controller過于臃腫蒜田,針對這個問題罗捎,在前端開發(fā)領(lǐng)域下發(fā)展出了多種不同的進(jìn)階形式肿轨,比如MVP和MVVM:
MVVM:Model(數(shù)據(jù)訪問層)枷颊,View(UI界面)嗓蘑,ViewModel(View的抽象,負(fù)責(zé)VM之間的信息轉(zhuǎn)換财破,將View的Command傳送到Model惫周,iOS中使用KVO或Notification技術(shù)達(dá)到這種效果)
Direct針對長列表問題又引入了MVVS這個模式钥勋,其實(shí)就是講每一個消息類型分別做MVVM餐茵,等于是多加了一層,我們可以參看下面的實(shí)例對照
采用這種架構(gòu)后述吸,我們可以確保:每個模塊的責(zé)任明確忿族,避免臃腫;每一條新消息進(jìn)入蝌矛,只需要增加一個Section Controller道批,更新一個Cell,提高刷新效率和響應(yīng)速度入撒;如果需要添加一個新消息類型隆豹,就直接增加一套MVVS,不用改動其他的代碼茅逮;克制團(tuán)隊(duì)暴兵璃赡,容易實(shí)現(xiàn)功能迭代
第二部分:消息重試機(jī)制
移動App的使用場景經(jīng)常存在網(wǎng)絡(luò)不穩(wěn)定,或者沒有網(wǎng)絡(luò)的情況献雅,這就導(dǎo)致了“如何確保重要信息的穩(wěn)定傳輸”成為了提升用戶體驗(yàn)的關(guān)鍵碉考。總結(jié)而言挺身,聊天產(chǎn)品的設(shè)計(jì)需求侯谁,可以包括:
這里有意思的是“用戶感知到的消息發(fā)送速度”,用戶不僅僅會在意接收到對方消息的速度,對自己發(fā)出消息的速度的感知也很強(qiáng)烈墙贱。所以一個點(diǎn)就是當(dāng)用戶發(fā)出消息時热芹,瞬間展示為正常發(fā)送狀態(tài),只有在發(fā)送失敗的時候再更新惨撇,這樣讓用戶的體驗(yàn)更加順暢伊脓,而不需要讓用戶感知到發(fā)送的過程。
根據(jù)前述的移動環(huán)境下的網(wǎng)絡(luò)不穩(wěn)定串纺,消息的發(fā)送有可能失敗丽旅,比如當(dāng):服務(wù)器宕機(jī)了,信號不穩(wěn)定纺棺,沒有信號等榄笙。這種情況下,為保證用戶體驗(yàn)的順暢祷蝌,我們需要提供“自動重試”的功能茅撞。對于聊天產(chǎn)品,讓用戶感知到消息發(fā)送的失敗是一件特別嚴(yán)重的事巨朦,我們應(yīng)該盡可能的避免這種情況的發(fā)生米丘。
自動重試針對的是隨機(jī)性的不確定消息傳輸失敗,簡單的通過一次重試糊啡,就會顯著的提高消息發(fā)送的成功率拄查。
這是Direct的單個消息重試機(jī)制,設(shè)置了上限五次棚蓄。個人感覺文本信息可以重復(fù)多次堕扶,圖片和視頻其實(shí)兩三次就夠了,因?yàn)閳D片視頻本身的傳輸時間過長梭依,加上重試后稍算,確認(rèn)成功的時間可能拖得太長了。
在消息重試機(jī)制中一個很重要的問題是如何保證消息發(fā)送序列的一致性役拴,Direct這里采用的是單隊(duì)列的形式糊探,只有前面的消息發(fā)送成功后才繼續(xù)發(fā)送后續(xù)的消息。(河闰?這里沒有并行發(fā)送的問題科平,是因?yàn)橐粋€對話信息流相對比較簡單,數(shù)據(jù)量不會過大嗎)
我們知道通常的場景是多個對話同時存在姜性,每個對話對用有一個消息隊(duì)列匠抗,這樣可以避免不同對話間消息的相對獨(dú)立。圖片和視頻與普通的消息不太一樣污抬,它們本身體量較大汞贸,又需要預(yù)處理比如壓縮編碼等绳军,并且對上下文不如消息敏感,所以確保它們能夠迅速的發(fā)送出去比保持隊(duì)列的順序更加重要矢腻。Direct這里采用的是將他們統(tǒng)一發(fā)入了一個多媒體隊(duì)列中门驾。
自動重試直接的會導(dǎo)致更多的CPU和網(wǎng)絡(luò)資源的占用,因此需要考慮重試的時機(jī)多柑。這里總結(jié)了Direct實(shí)現(xiàn)自動重試的一些時機(jī)奶是,其中有一點(diǎn)就是:自動重試只是針對隨機(jī)性的不確定的消息失敗,對于確定性的失敗竣灌,重試也是失敗聂沙,是沒有意義的。
圖片視頻的機(jī)制與消息稍有不同初嘹,因?yàn)楸旧眢w量過大及汉,所以需要限制同時傳送的數(shù)量,避免資源占用過多屯烦。
Direct里還有一個有趣的問題是多賬號系統(tǒng)的存在坷随,出于個人隱私和不同朋友圈的考慮,一個用戶可能擁有多個賬號驻龟,如果將朋友賬號里的消息發(fā)送到了親友賬號里温眉,可能就會有點(diǎn)尷尬了。Direct這里采用的是在賬戶切換過程時翁狐,暫停消息發(fā)送类溢,也就是你的消息只有在你當(dāng)前賬號Active的時候才可以發(fā)送。(為不同賬號提供不同的session來區(qū)分不是更好嗎露懒?)
Q&A
1)圖片的壓縮比例以及重傳的分析
圖片壓縮的比例一般是 50%-80%闯冷,壓縮后對用戶的體驗(yàn)影響不大,除非是那種像素特高的高端手機(jī)隐锭。如果一個版本更新后重傳量暴增窃躲,這個八成是代碼的問題计贰,而不是網(wǎng)絡(luò)的問題钦睡,對于分析重傳的效率,會通過后臺的日志記錄來分析躁倒。
2)當(dāng)團(tuán)隊(duì)由小團(tuán)隊(duì)變成大團(tuán)隊(duì)荞怒,歷史存量代碼過大的時候,如何實(shí)現(xiàn)組件化
Direct就存在這個問題秧秉,存量代碼有非常巨大的類:針對這種問題褐桌,解決過程一般都是非常有挑戰(zhàn)的,比如Direct的消息列象迎,大概3500+行的代碼荧嵌,由一個工程師到三四個工程師同時工作呛踊。在更新的過程中,會保留舊的代碼啦撮,同時運(yùn)行新的代碼谭网,比如從1%的用戶開始,通過檢測分析這1%的用戶的使用情況赃春,即使發(fā)現(xiàn)bug愉择,再慢慢的推廣到所有的用戶。使用這種循序漸進(jìn)的方法來避免初期不穩(wěn)定的影響范圍织中。(跟AB測試有點(diǎn)類似)
對于代碼劃分的粒度锥涕,Direct里開始的時候是從UI無關(guān)的代碼開始,并且限制每個類不超過300行(~這種粒度比我們的細(xì)多了)
3)Direct從十幾個工程師到七十幾個工程師是如何進(jìn)行職能劃分的
按照不同的業(yè)務(wù)模塊劃分狭吼,比如廣告层坠、圖片等,每個業(yè)務(wù)模塊有獨(dú)立的PM搏嗡,一般開發(fā)的過程是代碼逐步整合窿春,但是等功能完善后再逐步放開,這個節(jié)點(diǎn)是等待內(nèi)測完成采盒,雖然代碼可能已經(jīng)存在于正式產(chǎn)品中旧乞。
4)產(chǎn)品的功能越來越多的時候,按照功能劃分磅氨,如何處理跨平臺問題
盡可能的保持大的方向在不同平臺上一致尺栖,小的地方根據(jù)不同平臺的特性保證高效率,比如iOS會選Sqllite
5)一周發(fā)布一次的頻率烦租,如何保證開發(fā)的質(zhì)量
代碼的單元測試(對核心功能測試延赌,UI相對少);灰度的小開關(guān)(雖然一周發(fā)一次叉橱,但是四周后才打開)挫以;內(nèi)部會有測試的反饋意見;QA相對測試窃祝,基于自動化測試掐松,以及內(nèi)測;其實(shí)很多時候粪小,發(fā)現(xiàn)的問題就是產(chǎn)品的設(shè)計(jì)本身的問題
6)Direct產(chǎn)品指標(biāo)
Crash率是關(guān)鍵指標(biāo)大磺,在內(nèi)測階段,大的bug會作為指標(biāo)探膊,然后對于Direct杠愧,日活率,月活率逞壁,接受率流济,發(fā)送率等等
7)新功能如果不及預(yù)期锐锣,是否會砍掉
大部分功能是一個工程師單獨(dú)完成,大的功能绳瘟,一般會區(qū)分iOS和Android獨(dú)立開發(fā)刺下。上線后發(fā)現(xiàn)的bug肯定會及時修改,但如果是產(chǎn)品設(shè)計(jì)的問題稽荧,就會砍掉
手淘iOS性能優(yōu)化探索
這個議題主要介紹了手機(jī)淘寶iOS性能優(yōu)化的一些工作橘茉,針對移動開發(fā)性能優(yōu)化和運(yùn)維相關(guān)提供一些新的思路。
由表象的終端用戶感受到的問題姨丈,到在業(yè)務(wù)流程角度需要考慮排查的性能問題
手淘從技術(shù)上的研發(fā)流程角度畅卓,將問題劃分為這四個階段。
研發(fā)架構(gòu)支撐
其實(shí)我們的產(chǎn)品也很類似蟋恬,我們的啟動過程也非常復(fù)雜翁潘,簡單的看我們的Delegate和Context相關(guān)的代碼量就是一個巨量,并且我們也在啟動過程中綁定了很多的功能模塊歼争,像Authenticaiton就有很多種拜马。這個結(jié)果也是我們在開發(fā)的過程中,不停的“無節(jié)制”的添加功能導(dǎo)致的沐绒,手淘的這些問題我們的產(chǎn)品也基本都存在俩莽。手淘的設(shè)計(jì)目標(biāo),簡單的就是說要實(shí)現(xiàn)啟動任務(wù)的松耦合乔遮,實(shí)現(xiàn)高并發(fā)扮超,提高性能,再通過線上服務(wù)器端解決使用中的問題蹋肮。除了這條線上控制出刷,其他的三點(diǎn)我們的產(chǎn)品也基本都可以利用。
因?yàn)槊總€具體用戶的使用習(xí)慣不同坯辩,并且不像我們2B的產(chǎn)品馁龟,實(shí)現(xiàn)可以知道具體用戶的使用場景,比如不同職務(wù)會看不同的報(bào)表漆魔,像手淘這種2C的產(chǎn)品坷檩,只有用戶使用后才能知道用戶的使用場景和習(xí)慣。所以這里“自學(xué)習(xí)啟動任務(wù)”是要求手淘可以根據(jù)用戶的使用習(xí)慣有送,調(diào)整APP啟動時淌喻,不同任務(wù)的優(yōu)先級僧家。另外雀摘,首頁啟動的優(yōu)先級最高,你不可能讓用戶對著啟動頁看上半天八拱,可以通過Cache先將首頁渲染出來阵赠,再通過其他的線程逐步更新首頁內(nèi)容涯塔。
集成數(shù)據(jù)卡口
主要是介紹了API調(diào)用的時候,如何去統(tǒng)計(jì)和定位具體函數(shù)的耗時清蚀,會細(xì)節(jié)到匯編代碼的層次去分析匕荸。
性能無痕度量
這里介紹的一個主要問題是:如何判定屏幕渲染已經(jīng)完成?
我們不能夠以“viewDidAppear”來判定頁面已經(jīng)展示枷邪,因?yàn)槠聊坏匿秩具M(jìn)程經(jīng)常會用到異步的回調(diào)渲染榛搔,相反的我們應(yīng)該通過用戶的真實(shí)體驗(yàn)來判定頁面加載完成:
不同機(jī)型的數(shù)據(jù)也是不同的,所以除了產(chǎn)品本身东揣,運(yùn)行的設(shè)備對產(chǎn)品性能的影響也是巨大的践惑。
線上排查工具
蘋果的Instrument是給開發(fā)人員使用的性能排查的工具,我們也都應(yīng)該使用過它排查過memory leak以及memory的使用瓶頸嘶卧。這里手淘主要介紹了他們自己的一個線上的Instrument:tbinstrument
設(shè)計(jì)的思路主要是服務(wù)器通過指令來收集線上app的線程信息尔觉,在后臺進(jìn)行分析。(什么時候開源芥吟?)
Q&A
1)PPI的要求
最低60幀侦铜,即使是低端設(shè)備
2)Web界面如何監(jiān)控
像素點(diǎn)采集,因?yàn)閣eb不夠穩(wěn)定钟鸵,所以對于web的采樣周期會相應(yīng)變長
3)手淘Crash后钉稍,重啟會有彈框進(jìn)行修復(fù),這里面做了什么
因?yàn)檫@些Crash大多數(shù)都是個別人存在的偶然性問題棺耍,而在測試過程中并沒有發(fā)現(xiàn)嫁盲,這個原因很大可能是某些數(shù)據(jù)被破壞,導(dǎo)致數(shù)據(jù)不完整烈掠,這時候刪除緩存的數(shù)據(jù)羞秤,重新下載和生成新的數(shù)據(jù),基本上會解決Crash的問題左敌。
4)自學(xué)習(xí)啟動的優(yōu)化參數(shù)標(biāo)準(zhǔn)
同樣的機(jī)器瘾蛋,即使運(yùn)行同樣的任務(wù),可能結(jié)果都不一樣矫限,這是因?yàn)闄C(jī)器本身隨著使用時間和方式的不同哺哼,會導(dǎo)致機(jī)器本身性能的差別
滴滴出? iOS 端瘦身實(shí)踐
在聽這個議題的時候,我們正好遇到有客戶抱怨我們的APP過大叼风,我們現(xiàn)在的DMG編完的app大概為300M+取董,這里面的最主要的問題是我們的framework同時支持了Simulator和Device,以及32位和64位的機(jī)器无宿,通過腳本我們刪除了多余的支持內(nèi)容后茵汰,如果只確保生成具體Device的編譯文件,我們生成的APP大概為100M+的水平孽鸡。當(dāng)然蹂午,還是很大~~ 后面想要繼續(xù)瘦身的話栏豺,只能從代碼層面以及圖片資源方面下手了。
對于滴滴來說豆胸,存在同樣的問題奥洼,APP經(jīng)過長期的產(chǎn)品迭代,項(xiàng)目越來越大晚胡,可執(zhí)行文件占用的體積也是灵奖。這個議題就是介紹了滴滴是如何指定及實(shí)施一套工程優(yōu)化的方案使得滴滴在不斷迭代開發(fā)后還能保持苗條~
資源瘦身
刪除無用圖片
滴滴自建了一個工具用來查找,并通過XCode匹配刪除無用的圖片估盘,F(xiàn)engNiao:Link
大比例壓縮
使用Google提供的Webp圖片文件格式桑寨,優(yōu)點(diǎn)包括:壓縮率高,同時支持有損壓縮和無損壓縮忿檩;體積大幅減少尉尾,肉眼看不出差異;支持Alpha透明和24bit顏色數(shù)燥透,相比而言PNG8色彩不夠出現(xiàn)毛邊沙咏;Gif轉(zhuǎn)Animated Webp有損可減少64%,無損19%班套。相應(yīng)的缺點(diǎn)就是:比PNG消耗2倍左右CPU和解碼時間肢藐,全平臺支持度不夠。
一般而言吱韭,小于256色適合無損壓縮吆豹,大于256的使用75%有損壓縮
壓縮工具iSparta:Link
WebP 項(xiàng)?目主?頁:Link
iOS WebP 解析庫:Link
大資源文件
下載后使用,比如表情包等
其它一些效果較小的方法
重復(fù)資源檢測:Link
音頻壓縮瘦身:Link
簡單圖片用代碼替換
將代碼里的靜態(tài)字符串抽取出來放到靜態(tài)文件里
基于編譯后的瘦身
LinkMap展現(xiàn)的是可執(zhí)行文件的全貌理盆,列出了編譯后的每一個.o目標(biāo)文件的信息痘煤。通過分析LinkMap的文件,我們可以了解各個獨(dú)立模塊的大小猿规,進(jìn)而分析那些模塊可能是無用的衷快,哪些模塊體積過大等等。
基于編譯過程的Clang Plugin瘦身
主要是分析調(diào)用關(guān)系姨俩,找出沒被調(diào)用的代碼:需要編寫分析全部源碼的插件蘸拔,在編譯過程中將插件作為Clang參數(shù)載入生成中間文件,然后編寫工具分析所有的方法有哪些是會被調(diào)用的环葵。
iOS APP分析無用代碼(A source-code level/Clang Approach):Link
CLANG技術(shù)分享系列四:IOS APP無用代碼/重復(fù)代碼分析: Link
代碼級瘦身
AppCode:類似于XCode的一款iOS/Mac開發(fā)工具调窍,可以找出沒有被使用的類、方法张遭、值等等
結(jié)構(gòu)瘦身
基于字符查找相似代碼
SameCoderFinder?Link?可以在源代碼文件中檢測到相同的function并顯示兩者之間的Hamming距離邓萨,這樣就可以找到需要提取重復(fù)使用的相同代碼,支持OC和Java
對于大量代碼比較如何提高效率:就是如何高效計(jì)算二進(jìn)制序列中1的個數(shù)
空間換時間:比如8位的話列出1~256每個數(shù)中1的個數(shù)
基于代碼結(jié)構(gòu)查找相似代碼
基于代碼行的;基于標(biāo)識符的先誉;基于度量的;基于抽象語法樹的的烁;基于程序依賴圖的等等
Q&A
1)第三方庫
使用第三方庫的源代碼褐耳,再使用以上的方法進(jìn)行瘦身,缺點(diǎn)就是需要自己維護(hù)渴庆,而我們就盡量維護(hù)一個穩(wěn)定的版本
2)工作量和后續(xù)監(jiān)控
基本每個事業(yè)部需要一到兩個人做這項(xiàng)工作铃芦,后期的監(jiān)控主要是實(shí)時監(jiān)控文件的體積,一旦出現(xiàn)增量襟雷,就會提醒響應(yīng)的人員
3)查找詳細(xì)的方法
相似的功能通過組件化的實(shí)現(xiàn)刃滓,然后共享