Facebook iOS App如何優化啓動時間

http://www.cocoachina.com/ios/20160105/14870.htmlphp

 

提升 Facebook 應用的性能已經成爲 Facebook 持續關注的領域。由於咱們相信一個高性能的應用可以傳遞一種吸引人且使人愉悅的體驗。每一個 Facebook 應用的用戶都必須作的一件事是啓動應用(咱們特指這個動做爲 」應用啓動「)。所以,這是一個很好的優化目標。html

 

穩定的指標ios

實現最好的性能度量標準和相應的目標,鼓舞咱們專一於提高應用的品質,而且咱們相信這將會產生很大的影響。度量必須易懂、經得起推敲,而且須要精確地捕捉到將要被優化的體驗。對基於性能的度量,咱們已經發如今使用應用過程當中,最好是使用那些被捕捉到感知的交互。理想狀況下,這些度量應該和一個經過基礎設施的單一執行通道有一對一的聯繫。對於應用程序的啓動,肯定用於衡量的關鍵位置是一個挑戰。這須要採起幾回迭代去簡化咱們的測量和移除邊界問題。緩存

應用啓動是一個特別不固定的概念,由於如今存在不少種應用啓動的方式。應用能夠在後臺或者前臺啓動,甚至能夠在後臺啓動,可是在完成初始化以前轉換爲前臺。你能夠經過點擊一條通知或者經過一個 URL 打開應用。Facebook 應用甚至能夠經過其餘應用來打開,由於他們須要經過 Facebook 來實現第三方登陸。在現實場景中,主要的交互仍是最直接的方式:你點擊桌面的應用圖標,而後跳轉啓動。於是,咱們選擇這個做爲應用啓動的入口。安全

當啓動入口明確以後,咱們必須去計算出什麼時候應用啓動是完成的。一樣地,咱們觀察用戶的使用模式,發現用戶喜歡打開應用(首先跳轉到新聞摘要),而後等待摘要的加載。咱們判定「摘要完成加載」是應用啓動一個很好的終點。咱們採起了一些微調使得這個終點契合用戶的使用狀況。咱們能夠經過重複地觀察應用的啓動,圍繞度量標準來提升應用的性能。服務器

一旦肯定了咱們認爲有表明性的啓動入口和終點,咱們把啓動問題分解成兩種類型:網絡

  • 冷啓動。指的是當應用還沒準備好運行時,咱們必須加載和構建整個應用。這包括設置屏幕底部的分欄菜單,確保用戶是否被合適地登陸,以及處理其餘更多的事情。「引導」程序是在applicationDidFinishLaunching:withOptions:方法中開始的。併發

  • 熱啓動。指的是應用已經運行可是在後臺被掛起(好比用戶點擊了 home 健),咱們只須要知道在什麼時候應用進入後臺。在這種狀況下,咱們的應用經過 applicationWillEnterForeground: 接收到前臺的事件,緊接着應用恢復。app

咱們決定主要優化冷啓動,主要有兩個緣由。
首先,冷啓動實際上是包括熱啓動的(冷啓動初始化應用並得到摘要;熱啓動只得到摘要),因此有更多的地方須要優化和微調。
其次,冷啓動須要作額外的初始化工做,因此相較而言更慢,致使須要更長的啓動等待時間。性能

優化冷啓動體驗

咱們把冷啓動問題分解成三個階段,進而咱們能夠有針對性地解決。每一個階段都有一些列變數和挑戰。

  • 請求時間:從應用啓動到摘要請求離開設備(譯者:應該是向服務器發送URL請求算結束時間)的時間。

  • 網絡時間:從摘要請求離開設備到服務器響應返回的時間。

  • 響應處理時間:從響應返回到新數據展現在屏幕的時間。

咱們直觀上認爲冷啓動性能主要被網絡請求和響應處理影響了。這個結論是因爲咱們假定咱們在客戶端花的時間比較少,而且咱們設法讓請求的獲取更加快速。然而,當咱們用 instrument 去檢測時,咱們發現數據很是出人意料。它展示出了徹底不一樣的結果,咱們發現摘要請求花了大部分時間。另外,響應的處理時間也很是短。所以,咱們從新把優化的焦點放在初始化階段。

Feed請求發送的初始化

因此爲何這個階段花費了那麼多時間呢?不少 iOS 應用並無這樣一個問題——他們在那個階段並無不少工做須要作,除了初始化視圖控制器和發送網絡請求。然而,對於 Facebook 來講,大部分時間被用來開始的時候去設置不一樣功能塊。下面是咱們應用中的主要功能塊的流程概覽。 

12057214_1016971454990542_827610883_n.png

這看起來好像是很複雜的應用啓動設置。但須要重視的是,這些功能塊對於 Facebook 應用來講是很是重要的提高,能夠提升應用體驗,而且使得工程師可以在不一樣的應用規模下更快地開發。

正如咱們所關注的這個流程,咱們經過優化獨立的部分得到了一些主要的成果。然而,因爲將來支持新特性的初始化以及額外提供支持的基礎設施,這些成果會慢慢地抵消掉。這使得咱們從新考慮如何去解決問題。但咱們從新開始,咱們認爲這個階段的目標是簡單地發送摘要的網絡請求。可是爲何摘要請求發出去得這麼慢?這是因爲不少依賴被添加到摘要的初始化中了。然而,他們並不都是必要的 — 對於摘要請求來講,最少的須要一個有效的驗證 token 以及摘要光標(新聞摘要的位置)。所以,咱們減小了摘要請求的依賴,讓它逐漸地更加接近應用的啓動。這容許應用的剩餘部分在摘要響應的同時進行初始化。因爲這些重構,咱們得到了顯著的收益。

網絡和服務器時間

根據咱們在第一階段的經驗,咱們繼續把這個階段分解成更小的部分。網絡請求/響應看起來像這樣: 

12056998_991399770918380_262846919_n.png

咱們注意到,一旦請求正在排隊,發送請求出去以後就有一個時間間隔。這很好解釋 — 在冷啓動中,網絡鏈接並非一個開放的、安全的 TCP 鏈接。一個鏈接的創建須要三次握手,平均爲幾百毫秒。當摘要請求第一次發送時,沒法避免要花掉這些時間。長遠來看,這能夠經過緩存 SSL 證書來解決。可是再次強調,咱們退回來的目的並非爲了發送 TCP 請求,而是爲了從服務器經過任何可能的方式得到請求信息。

咱們提出了一個創造性的解決方案 — UDP 啓動。本質上,咱們在經過 TCP 發送摘要請求時,先發送一個編碼過的包含摘要請求的 UDP 包到服務器。這樣作的目的是喚醒服務器更早地去獲取和緩存數據。當真正的摘要請求經過 TCP 到達時,服務器只需見到地從緩存內容中構造出響應,併發回客戶端。這個技術使得咱們能夠減小几百毫秒的耗時。

當咱們持續深刻研究服務器端時,咱們開始嘗試使用 層-取(story-fetching)策略。過去咱們已經作了一批摘要請求的 3+7 層。緣由很簡單:下載次數和被下載的層成正比。所以,把請求分割成兩塊,容許開始的三層先進來,其他的七個隨後進來。經過提高咱們的基礎設施,咱們已經可以升級爲 1+1+X 策略,這已經接近於流了。這樣就減小了服務器必須處理第一層的時間,而且可以減小下載的時間,使得能夠在最快的時間內與用戶交互。經過這樣的努力,這樣咱們又減小了幾百毫秒的耗時。

Feed響應處理

正如在前面提到的那樣,咱們覺得在啓動時會在這裏花費大量的時間。可是這個想法被證實是錯誤的。更加令人好奇的是,咱們注意到時間並無花在處理和加工層上面。時間被花在運行應用服務和競爭資源上面。咱們注意到這是咱們優化網絡和服務器時間的反作用,由於摘要請求返回得太早了。儘管大多數的服務是不重要的。所以,咱們開發出一個簡單的機制去序列化這些工做直到應用完成啓動,而且使用先進先出的方式去執行。這樣能夠用更少的鏈接去處理全部層,大大地減小了得到響應和展現在屏幕之間的時間。

總結

很難理解咱們在過去幾個月走了多遠。總之,在一對一的比較中,咱們發現咱們成功地優化了一秒多的耗時。

優化這個特殊的交互是一個長期的過程,須要創建一個穩定的度量,這個度量必須是易懂的、符合真實世界性能特徵,此外要不斷地從新思考問題,以提出創新的解決方案。咱們但願這能夠幫助使用 Facebook 的人有更好的、使人愉悅的用戶體驗。

你也能夠看看 Greg Moeck在 2015 年的演講

相關文章
相關標籤/搜索