块大小与元数据算术:决定内存的是文件个数,不是数据量
默认值是经验值,不是算出来的。 HDFS 块大小默认 128MB,可用 dfs.blocksize 配置。它是权衡各项成本后定的经验默认值,不是从方程里解出来的。历史:GFS 是 64MB,早期 Hadoop 是 64MB,Hadoop 2 起默认 128MB,存超大文件的集群有用 256MB 的。
算术只有一条规则。 每个元数据对象——一个文件节点、一个块——在 NameNode 里大约占 150 字节。这个数是近似的、随版本在 150–200 字节量级浮动。只作量级估算,绝不当精确堆大小。
Cloudera 官方例子。 同样的数据,切法不同,元数据代价天差地别。192MB 文件是 2 块加 1 个文件节点,共 3 个对象:
同样 1GB 写成一个大文件,是 8 块加 1 个文件节点,共 9 个对象:
同样 1GB 切成 1024 个 1MB 文件,是 1024 个文件节点加 1024 个块,共 2048 个对象:
同样 1GB 数据,这是大文件情形的约 228 倍:
放大到 1TB。 写成 8192 个 128MB 文件,是 8192 个文件节点加 8192 个块,共 16384 个对象,元数据约 2.3MiB。写成 1048576 个 1MB 文件,是 2097152 个对象,元数据 300MiB。同样的数据,128 倍元数据:
为什么是 128MB:寻道摊销。 机械盘寻道约 10ms,顺序读约 100MB/s。传 128MB 要 1.28s,寻道占不到 1%;传 1MB 约 10ms,寻道约占 50%。块必须大到寻道相对读数据可以忽略。但块太大也有代价:并行度下降(能同时读的片变少)、恢复粒度变粗(丢一块要补拷的数据更多)。
绝不能把 150×对象数当堆大小报。 副本只是位置,不是新的块对象,但块映射等额外开销使 Cloudera 的实践规则是每 100 万个唯一块约 1GB 堆:3600 万块约需 36GB 堆,远高于 150 字节乘对象数。150 字节算的是账本,堆规则算的是机器。
决定内存的是文件个数,不是数据量。 10PB 存成大文件约 8000 万块、几十 GB 元数据,一台大内存服务器装得下;10PB 全是 10KB 小文件约 10 亿个文件、几百 GB 元数据,一台机器装不下。大堆还有自己的代价:GC 停顿随堆增大而变长。HA 里的 standby 只是把同一本账在内存里再抄一份,并不提高容量。超出单机就得拆账本,见 federation;这个病本身见 small-files。