深入理解Presto
深入理解Presto
簡介
Presto是一個facebook開源的分布式SQL查詢引擎,適用于交互式分析查詢,數據量支持GB到PB字節。presto的架構由關系型數據庫的架構演化而來。presto之所以能在各個內存計算型數據庫中脫穎而出,在于以下幾點:
本文從外到內,依次來介紹presto。
架構
Presto采用典型的master-slave模型:
在worker的配置中,可以選擇配置:
2和3的原理是基于service inventory, worker 會動態監聽這個文件,如果有變化,load出最新的配置,指向最新的discovery節點。
在設計上,discovery和coordinator都是單節點。如果有多個coordinator同時存活,worker 會隨機的向其中一個匯報進程和task狀態,導致腦裂。調度query時有可能會發生死鎖。
discovery和coordinator可用性設計。由于service inventory的使用,監控程序可以在發現discovery掛掉后,修改service inventory中的內容,指向備機的discovery。無縫的完成切換。coordiantor的配置必須要在進程啟動時指定,同一個集群中無法存活多個coordinator。因此最好的辦法是和discovery配置到一臺機器。 secondary機器部署備用的discovery和coordinator。在平時,secondary機器是一個只包含一臺機器的集群,在primary宕機時,worker的心跳瞬間切換到secondary。
數據模型
presto采取三層表結構:
presto的存儲單元包括:
不同類型的block:
- boolean valueIsNull[]表示每一行是否有值。
- T values[] 每一行的具體值。
2. 可變寬度的block,應用于string類數據,由三部分信息組成
-
- Slice : 所有行的數據拼接起來的字符串。
- int offsets[] :每一行數據的起始便宜位置。每一行的長度等于下一行的起始便宜減去當前行的起始便宜。
- boolean valueIsNull[] 表示某一行是否有值。如果有某一行無值,那么這一行的便宜量等于上一行的偏移量。
3. 固定寬度的string類型的block,所有行的數據拼接成一長串Slice,每一行的長度固定。
4. 字典block:對于某些列,distinct值較少,適合使用字典保存。主要有兩部分組成:
-
- 字典,可以是任意一種類型的block(甚至可以嵌套一個字典block),block中的每一行按照順序排序編號。
- int ids[] 表示每一行數據對應的value在字典中的編號。在查找時,首先找到某一行的id,然后到字典中獲取真實的值。
插件
了解了presto的數據模型,就可以給presto編寫插件,來對接自己的存儲系統。presto提供了一套connector接口,從自定義存儲中讀取元數據,以及列存儲數據。先看connector的基本概念:
插件能夠幫助開發者添加這些功能:
Presto提供了一個簡單的connector : local file connector ,可用于參考如何實現自己的connector。不過local file connector中使用的遍歷數據的單元是cursor,即一行數據,而不是一個page。 hive 的connector中實現了三種類型,parquet connector, orc connector, rc file connector。
上文從宏觀上介紹了presto的一些原理,接下來幾篇文章讓我們深入presto 內部,了解一些內部的設計,這對性能調優會有比較大的用處,也有助于添加自定義的operator。
內存管理
Presto是一款內存計算型的引擎,所以對于內存管理必須做到精細,才能保證query有序、順利的執行,部分發生餓死、死鎖等情況。
內存池
Presto采用邏輯的內存池,來管理不同類型的內存需求。
Presto把整個內存劃分成三個內存池,分別是System Pool ,Reserved Pool, General Pool。
為什么要使用內存池
System Pool用于系統使用的內存,例如機器之間傳遞數據,在內存中會維護buffer,這部分內存掛載system名下。
那么,為什么需要保留區內存呢?并且保留區內存正好等于query在機器上使用的最大內存?
如果沒有Reserved Pool, 那么當query非常多,并且把內存空間幾乎快要占完的時候,某一個內存消耗比較大的query開始運行。但是這時候已經沒有內存空間可供這個query運行了,這個query一直處于掛起狀態,等待可用的內存。 但是其他的小內存query跑完后,又有新的小內存query加進來。由于小內存query占用內存小,很容易找到可用內存。 這種情況下,大內存query就一直掛起直到餓死。
所以為了防止出現這種餓死的情況,必須預留出來一塊空間,共大內存query運行。 預留的空間大小等于query允許使用的最大內存。Presto每秒鐘,挑出來一個內存占用最大的query,允許它使用reserved pool,避免一直沒有可用內存供該query運行。
內存管理
Presto內存管理,分兩部分:
- query內存管理
- query劃分成很多task, 每個task會有一個線程循環獲取task的狀態,包括task所用內存。匯總成query所用內存。
- 如果query的匯總內存超過一定大小,則強制終止該query。
- 機器內存管理
- coordinator有一個線程,定時的輪訓每臺機器,查看當前的機器內存狀態。
當query內存和機器內存匯總之后,coordinator會挑選出一個內存使用最大的query,分配給Reserved Pool。
內存管理是由coordinator來管理的, coordinator每秒鐘做一次判斷,指定某個query在所有的機器上都能使用reserved 內存。那么問題來了,如果某臺機器上,,沒有運行該query,那豈不是該機器預留的內存浪費了?為什么不在單臺機器上挑出來一個最大的task執行。原因還是死鎖,假如query,在其他機器上享有reserved內存,很快執行結束。但是在某一臺機器上不是最大的task,一直得不到運行,導致該query無法結束。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的深入理解Presto的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 困扰多年的PCB散热问题终于可以解决了!
- 下一篇: c语言方框透视原理,FPS游戏的方框透视