大規模數據OLAP分析爆內存問題分析與解決

大規模數據OLAP分析爆內存問題分析與解決

PR地址:Fix RocksDB OOM #823

問題背景

問題表現

在執行如下Gremlin語句時,如果一次查詢分析的結果數據在千萬條以上,進程內存在幾分鐘內暴漲,JVM老年代佔據將近20G內存、RocksDB佔用本地內存超過100G,最終導致OOM,甚至進程被系統kill掉。

g.V().hasLabel('vbsku').count() 
g.V().hasLabel('vbsku').groupCount().by(properties('p_trade').value())
問題分析:

經過分析,發現大量迭代器RocksIterator沒有釋放,達到幾百萬個。這些java層RocksIterator對象佔用的內存其實並不算大,但是在JNI層之下,其持有的本地對象佔用了大量資源。這些資源依賴JVM的GC垃圾回收機制來釋放,當JVM GC壓力大時,導致本地資源無法及時釋放,最終惡性循環越積越多,內存撐爆。

那麼,RocksIterator爲何沒有釋放?

在HugeGraph中,一個用戶查詢Query會被拆分爲多個子查詢SubQuery,並且將SubQuery的結果通過迭代器Iterator列表串起來。每個SubQuery的的結果也是一個迭代器,比如頂點迭代器Iterator<Vertex>,邊迭代器Iterator<Edge>;並且,最上層的接口到最底層的數據之間也是通過迭代器串聯起來的,這中間可能涉及到針對迭代器的幾類轉換操作:

  • map
  • flatmap
  • batchmap
  • filter
  • concat

比如:

把二進制數據迭代器轉換爲頂點迭代器的操作:

  • map(Iterator<Entry>) => Iterator<Vertex>

或者把索引結果迭代器轉換爲頂點迭代器的操作:

  • map(Iterator<Entry>) => Iterator<Index>
  • batchmap(Iterator<Index>) => Iterator<IdList>
  • flatmap(Iterator<IdList>) => Iterator<Entry>)
  • map(Iterator<Entry>) => Iterator<Vertex>

這種獲取數據的模式在數據庫領域稱之爲火山模型,使用火山模型的目的是通過流式讀取數據,而不是把所有數據都從磁盤讀到內存(數據量比較大時內存裝不下),再進行下一步操作。

由於迭代器的組合靈活,導致各類迭代器的生命週期難以管理,此前迭代器的釋放基本是採取如下原則:

  1. 儘量在迭代器不需要使用的時候釋放,比如對底層的數據迭代器,當取下一條數據next()發現已經無數據時,及時關閉。
  2. 對於無法及時關閉的的迭代器,則依賴JVM GC來自動釋放,比如上層迭代到一半就因爲其它條件不滿足而提前結束時(類似limit()或one()等),底層迭代器無法感知,只能在無人引用該對象的時候,觸發GC finalize()對底層迭代器進行釋放。

正是因爲有部分依賴GC機制釋放的迭代器存在,引入了爆內存的風險,當GC壓力大時,JVM本地冰山對象嚴重消耗內存,並且來不及回收,出現了上述問題。

問題解決

解決方案:
  1. 將所有的迭代器的生命週期進行鏈式管理,最上層的迭代器關閉時,傳導到中間層的所有迭代器,最終傳導到最底層的迭代器,觸發資源釋放。
  2. 所有迭代器,包括中間層和上層的,在無需繼續使用時均採取手動關閉該迭代器,進而觸發底層的迭代器釋放。參考代碼:Manually close the iterators
  3. 禁止使用一次性加載數據到內存集合的操作,把迭代器轉換爲集合,包括遺留的部分場景比如邊的頂點列表獲取、緩存列表獲取、任務列表獲取等等。參考代碼:iter gloabal by batchlimit iterator to listforce limit BatchIdHolder.all()adapt ListIterator.list() return Collection
  4. 同時,解決了一些極端情況下爆內存的場景,比如超級點的邊被大量加載到內存,限制了一次最多讀取的條數。參考代碼:fix cassandra oomfix check subRows().size() <= INLINE_BATCH_SIZE
  5. 順便解決了offset在多個子查詢結果之間無法定位的問題,思想是在最頂層的Query中維護一個偏移計數,從而讓最底層的SubQuery也能夠通過OriginQuery鏈共享該計數。參考代碼:fix offset bug
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章