日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

用FlatBuffers提升Android平台上Facebook的性能

發布時間:2024/4/11 Android 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用FlatBuffers提升Android平台上Facebook的性能 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在Facebook上,人們可以通過閱讀狀態更新和查看照片同他們的家人和朋友來往。在我們的后端,我們保存了組成這些連接的社交圖譜的所有數據。在我們的移動客戶端,我們不能下載完整的圖譜,而是以一個本地的樹結構的形式下載一個節點及它的一些連接。

下面的圖片描述了在一個含有照片附件的story中這是如何工作的。在這個例子中,John創建了一個story,他的朋友們很喜歡它并加了評論。圖片的左邊是社交圖譜,用來描述Facebook后端的人際關系。當Android app查詢story時,我們獲得一個以story開始的樹結構,包含了參與者的信息,反饋,和附件(如圖片的右邊所展示的那樣)。


我們要處理的一個重要問題是如何在app中表示并存儲數據。規格化所有這些數據為不同的表并放進SQLite數據庫不太現實,因為我們查詢節點并關聯來自于后端的樹結構的方式非常非常多,因此我們直接存儲樹結構。一個解決方案是將樹結構存儲為JSON,但那將需要我們在它能夠被用于UI展示之前先解析JSON,并轉換為一個Java對象。而且,JSON解析耗費時間。我們過去常常在Android平臺上使用Jackson JSON解析器,但我們發現了它的一些問題:

  • 解析速度。它要耗費35 ms來解析一個20 KB(Facebook中一個典型的響應的大小)的JSON流,這超出了UI幀刷新的16.6 ms的間隔了。使用這種方法,我們無法在滾動時,按照需要及時地從磁盤緩存中加載stories而不出現丟幀(視覺上的抖動)。
  • 解析初始化。一個JSON解析器在它可以開始解析之前,需要構建一個字段映射,這可能要耗費100 ms到200 ms,這大幅地降低了應用的啟動時間。
  • 垃圾回收。在JSON解析的過程中要創建大量的小對象,在我們的探索研究中發現,解析一個20 KB的JSON 流時,大概要分配 100 KB的瞬時內存,這將給Java的垃圾回收器帶來巨大的壓力。

我們想要找到一個更好的存儲格式來提升我們的Android app的性能。

FlatBuffers

在我們對可選的格式的探索中,我們找到了FlatBuffers,來自于Google的一個開源項目。FlatBuffers是protocol buffers(protobuf)的一個進化版,后者已經包含了對象元數據,允許直接地訪問數據的獨立的子部件,而不必須先反序列化整個對象(在這個例子中,是一棵樹)。

想象一下,我們有一個簡單的person類對象,它有四個字段: name,friendship status,spouse,及friends列表。spouse和friends字段還包含了person對象,這些形成了一個樹結構。這是一個說明了這樣一個對象,一個person,John和他的妻子,Mary,在FlatBuffer中是如何布局的簡化的圖解。

class Person {String name;int friendshipStatus;Person spouse;List<Person>friends; }

在上面的布局中,你需要注意:

  • 每個對象都被分為兩個部分:元數據的部分(或vtable)在軸心點的左邊,真實的數據部分在右邊。
  • 每個字段對應于vtable中的一個槽,其中存儲了那個字段的真實數據的偏移量。比如,John的table的第一個槽的值為1,表明了John的名字被存放在了距離Jonh的軸心點向右偏移一個字節的地方。

  • 對于對象字段,vtable中的偏移量指向子對象的軸心點。比如,John的vtable中的第三個槽指向了Mary的軸心點。

  • 要表示字段沒有值,我們可以在一個vtable槽中使用一個0偏移量。

下面的代碼片段展示了我們可以如何在上面展示的結構中找到Jonh的妻子的名字。

// Root object position is normally stored at beginning of flatbuffer. int johnPosition = FlatBufferHelper.getRootObjectPosition(flatBuffer); int maryPosition = FlatBufferHelper.getChildObjectPosition(flatBuffer,johnPosition, // parent object position2 /* field number for spouse field */);String maryName = FlatBufferHelper.getString(flatBuffer,maryPosition, // parent object position0 /* field number for name field */);

注意,不需要創建中間對象,這節省了瞬時內存的分配。我們甚至可以通過直接地把FlatBuffer數據存儲在文件中,然后把它mmap進內存中來做進一步的優化。這意味著我只需要加載文件中我們需要讀取的部分,這將進一步降低總的內存消耗。

而且,在讀取字段之前,無需反序列化對象樹。這減少了存儲層和UI之間的延遲,它將提升總的性能。

FlatBuffers上的變化

有時我們需要修改FlatBuffers里的值。由于FlatBuffers有意地設計為不可變的,而沒有一個直接的方法來做到這一點。我們想到的一個方案是與最初的FlatBuffer一并追蹤變化。

FlatBuffer中的每個數據片段可以通過它在FlatBuffer中的絕對位置來唯一的標識。我們支持變化,因而我們不一定要為很小的更新重新下載整個story——比如friendship status的改變。由于只是例子,這是一個概念的可視化,關于如何使用它來追蹤兩個變化:

  • Jonh的friendship status由FlatBuffer的絕對索引2處的vtable槽指向。要改變John的status,我們只需要記錄絕對索引2所對應的那個數據現在為1(意味著一個friend)而不是2(意味著不是一個friend,但需要發送friendship請求)。

  • Mary的名字(“Mary”)由位于絕對索引13處的一個vtable槽指向。類似地,要修改Mary的名字,我們只需要記錄對應于絕對索引13的新的String值。

最后,我們可以把所有的變化打包進變化緩沖區。變化緩沖區由兩部分組成:變化索引和變化數據。變化索引記錄了從base buffer中絕對索引到新數據的位置的映射。變化數據以FlatBuffer的格式存儲了新的數據。


當查詢FlatBuffers中的一個數據片段時,我們可以計算出數據的絕對位置,然后查詢變化緩沖區來查看是否發生了變化并返回它,否則返回base buffer中的數據。

平坦模型

FlatBuffers不僅可以被用于存儲,也可以被用于網絡,以app中的in-memory的格式。這消除了服務器響應的數據到UI顯示之間的轉換。這已經允許我們走向一個更干凈平坦模型架構,這將消除UI和存儲層之間額外的復雜性。

當使用JSON作為存儲格式時,我們需要添加一個內存緩存來迂回地處理反序列化的性能問題。我們最終也在UI和存儲層之間添加應用和網絡邏輯。


盡管這個三層架構在iOS和桌面上已經相當的流行了,它在Android上依然有一些重要問題:

  • 一個內存緩存通常意味著,相對于UI顯示的需要,我們將在內存中放多得多的東西。市場上的許多Android設備依然有著每個app 48 MB或更少內存的限制。當你加入了Java的垃圾收集器的開銷,這可能對性能有影響。

  • 應用邏輯需要處理內存緩存,UI和存儲,但是典型地與UI和存儲相關的代碼是發生在不同的線程中的。但在一個巨大的應用程序中保持線程模型簡單可能是很困難的。

  • UI典型地從多個源接收數據,比如存儲中緩存的數據,來自于網絡的新數據,來自于應用邏輯的本地數據變化,還有更多其它的。這需要UI不得不處理不同類型的數據改變場景,而可能導致UI透支。

通過 平坦模型 方法,UI和存儲層可以被更簡單地集成,如下面的圖片所展示的那樣。


  • 使用標準的Android cursors直接在存儲之上構建UI,而且由于storage-to-UI是大多數Android apps中最熱的執行路徑,這可以幫助保持UI響應性。
  • 應用邏輯和網絡組件已經被移到了存儲層的下方,允許那里的所有邏輯發生在一個后臺線程中,并確保結果首先反映在存儲中。然后,通過使用標準Android content provider通知,UI可以被通知去重繪。
  • 這個架構可以將UI和應用邏輯進行干凈的分離——我們可以簡化每個的邏輯。UI組件只需要反映存儲的狀態 ,而應用邏輯只需要向存儲層寫入最終的(正確的)信息。UI和應用邏輯層運行于不同的線程,它們從不需要彼此直接的通信。

結論

FlatBuffers是一個數據格式,它使得存儲和UI之間的數據轉換變得不必要了。采用這種技術,我們也已經驅動了我們的app的額外的架構提升,如平坦模型。我們在FlatBuffers之上構建的mutation擴展使我們可以在一個單獨的結構中,追蹤服務器數據,變化,和本地狀態,這可以簡化我們的數據模型,并暴露一個一致的API給我們的UI組件。

在過去的六個月,我們已經將Android平臺上的Facebook的大部分過度到使用FlatBuffers作為存儲格式了。一些性能提升數字包括:

  • 從磁盤緩存中加載每個Story的時間從35 ms減小到了4 ms。
  • 瞬時內存分配減少了75%。
  • 冷啟動時間提升了10-15個百分點。
  • 我們已經減少了15%的存儲大小。

看到數據格式的選擇使得人們可以只花費一點點的時間就讀到他們的朋友的更新及查看他們的家人的照片令人感到興奮。感謝你,FlatBuffers!

原文鏈接

總結

以上是生活随笔為你收集整理的用FlatBuffers提升Android平台上Facebook的性能的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。