NameNode堆內存估算
在HDFS中,數據和元數據是分開存儲的,數據文件被分割成若干個數據塊,每一個數據塊默認備份3份,然后分布式的存儲在所有的DataNode上,元數據會常駐在NameNode的內存中,而且隨着數據量的增加,在NameNode中內存的元數據的大小也會隨着增加,那么這個時候對NameNode的內存的估算就變的非常的重要了。
這里說的內存就是指NameNode所在JVM的堆內存
NameNode內存數據結構非常豐富,除了我們前面講到的Namespace tree和BlocksMap外,其實還包括如LeaseManager/SnapShotManager/CacheManager/NetworkTopology
等管理的數據,但是這些管理數據占用的內存非常的小,我們在估算NameNode內存的時候一般都忽略這些數據所占內存大小。所以在NameNode內存中,主要的內存分別被Namespace tree和BlocksMap占有,那么我們現在只要估算Namespace tree和BlocksMap所占內存即可。
我們在Namespace tree中估算了假設HDFS目錄和文件數分別為1億,Block總量在1億情況下,整個Namespace在JVM中內存使用情況:
- Total(Directory) = (8 + 72 + 80) ∗ 100M + 8 ∗ num(total children)
- Total(Files) = (8 + 72 + 56) ∗ 100M + 8 ∗ num(total blocks)
- 內存總大小是:Total(Directory) + Total(Files) = (8 + 72 + 80) ∗ 100M + 8 * 200M + (8 + 72 + 56) ∗ 100M + 8 * 100M = 31.25G
我們在BlocksMap中估算了假設集群中共1億Block,NameNode可用內存空間固定大小128GB,則BlocksMap占用內存情況:
- BlocksMap直接內存大小 + (Block直接內存大小 + BlockInfoContiguous直接內存大小) * 100M + LightWeightGSet直接內存大小
- 28字節 + (40字節 + 136字節) * 100M + 60字節 + (2%*128G) = 19.7475GB
那么綜上,假設整個HDFS集群中目錄和文件數分別為1億,Block總量在1億情況下,NameNode可用內存空間固定大小128GB,總共占用的內存為:
- Namespace tree所占內存大小 + BlocksMap所占內存大小 = 31.25G + 19.7475GB = 50.9975GB
我們上面已經提供了估算NameNode內存的方式,接下來我們再站在Files和Blocks的粒度上來估算NameNode需要的內存
Files和Blocks
在NameNode內存其實主要的就是存儲着兩種類型的對象,一個是File對象,一個是Block對象。
從Namespace tree中我們可以得到:
- 一個File對象的大小大概為:8 + 72 + 56 = 136字節
- 一個Directory對象的大小大概為:8 + 72 + 80 = 160字節
從BlocksMap中我們可以得到:
- 一個Block對象的大小大概為:40字節 + 136字節 = 176字節
為了方便計算,我們現在假設不管是File對象還是Block對象,他們每一個占用的內存大約為150字節
。
假設現在有一個192MB的文件,數據塊的大小是默認的128M,那么這個192MB的文件會被切分成兩個數據塊,一個數據塊的大小是128MB,另一個數據塊的大小是64MB。就會有3個對象(1個File對象和2個Block對象)存在於NameNode的內存中,占用的內存的大小大約為 3 * 150字節 = 450字節
。
大文件被切分成的數據塊越少,那么占用NameNode的內存就越少。比如一個128MB大小文件被切分成一個數據塊的時候占用的內存大約是300字節(一個File對象和一個Block對象)
;相反,128個1MB的文件在NameNode的內存中會產生256個對象(128個File對象 + 128個Block對象),這樣的話則會占用256 * 150字節 = 38400字節
的內存
節 = 38400字節
的內存
Replication(備份)
我們知道HDFS的數據塊的默認的備份數是3,我們需要知道的是備份數的設置會影響磁盤容量而不會影響NameNode中內存容量。
如果我們現在設置備份數為1,數據塊的大小是128MB。那么一個192MB的文件需要集群的192MB大小的磁盤容量和450字節的內存容量;假設有192TB的數據,這些數據包括了一百萬文件和兩百萬數據塊,那么需要集群的192TB磁盤容量和(一百萬File對象 + 兩百萬Block對象) * 150字節 = 450MB
的內存容量。
當我們設置備份數為默認備份數(即3)的時候,對於192TB的數據,需要集群的192 TB * 3 = 576 TB
的磁盤容量,但是需要的NameNode中的內存容量還是450MB。所以說NameNode中的內存大小和備份數多少關系並不是太大
例子
接下來我們看下兩個估算NameNode內存的例子,在看這兩個例子之前,我們先記住一個經驗值:每一百萬個Block需要NameNode的1G內存。
上面的是一個經驗值,你可以按照一百萬個Block伴隨着有一百萬個文件和一百萬個目錄來進行估算下,不管怎么樣,這個是一個比較靠譜的經驗者,我們可以使用這個經驗值進行估算我們的集群需要多少NameNode的內存
例子一
假設有1GB(1024MB)的數據,我們將它切分成不同數量文件和數據塊(數據塊大小為128M),然后分別來看下NameNode需要消耗多少內存:
一個 1GB 的文件
- 1個File對象
- 8個Block對象(1024MB / 128M)
Total = 9個對象 * 150字節 = 1350 bytes
8個文件,每個文件128MB
- 8個File對象
- 8個Block對象
Total = 16個對象 * 150字節 = 2400字節
1024個1MB的文件
- 1024個File對象
- 1024個Block對象
Total = 2048個對象 * 150字節 = 307200字節
例子二
在這個例子中,我們假設有兩個HDFS集群,兩個集群的總磁盤容量都是4800 TB
。其中集群A的數據塊的備份數設置為1,集群B的數據塊的備份數設置為3;兩個集群的數據塊大小都是128M。那么兩個集群的NameNode分別需要的最大的堆內存是多少呢?
集群A:200台主機,每台主機的磁盤容量是24 TB,總共的磁盤容量大小是4800 TB
- 數據塊大小是128M,備份數是1
- 集群的磁盤容量:
200 * 24,000,000 MB = 4,800,000,000 MB (4800 TB)
- 每一個數據塊需要的磁盤容量是:
128 MB per block * 1 = 128 MB
- 集群可以容納的數據塊的數量:
4,800,000,000 MB / 128 MB = 36,000,000 blocks
我們上面提到,一般情況下,一百萬的數據塊需要1G的內存,那么36,000,000
的數據塊就需要36GB的內存
集群B:200台主機,每台主機的磁盤容量是24 TB,總共的磁盤容量大小是4800 TB
- 數據塊大小是128M,備份數是3
- 集群的磁盤容量:
200 * 24,000,000 MB = 4,800,000,000 MB (4800 TB)
- 每一個數據塊需要的磁盤容量是:
128 MB per block * 3 = 384 MB
- 集群可以容納的數據塊的數量:
4,800,000,000 MB / 384 MB = 12,000,000 blocks
一般情況下,一百萬的數據塊需要1G的內存,那么12,000,000
的數據塊就需要12GB的內存
集群A和集群B的磁盤存儲容量都是一樣的,但是集群B因為備份數的增加,使得可以存儲的數據塊的數量變少了,所以集群B的NameNode需要的內存相應的也變小了。