Namenode 最重要的两个功能之一就是维护整个文件系统的目录树(即命名空间namesystem)。HDFS 文件系统的命名空间(namespace),也就是以“/”为根的整个目录树,是通过 FSDirectory 类来管理的。

FSNamesystem 也提供了管理目录树结构的方法,但 FSNamesystem 中的方法多是调用 FSDirectory 类的实现,FSNamesystem 在 FSDirectory 类方法的基础上添加了 editlog 日志记录的功能。而 FSDirectory 的操作则全部是在内存中进行的,并不进行editlog的日志记录

FSDirectory 的设计使用了门面(Facade)模式,门面模式是指提供一个统一的接口去访问多个子系统的多个不同的接口,它为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用

构造方法

序号 参数 默认值 含义
1 dfs.permissions.enabled true 权限,默认开启
2 dfs.permissions.superusergroup supergroup 超级用户组
3 dfs.namenode.acls.enabled false 设置为true以启用对HDFS ACL(访问控制列表)的支持。 默认情况下,禁用ACL。 禁用ACL时,NameNode拒绝与设置或获取ACL相关的所有RPC
4 dfs.ls.limit 1000 限制ls打印的文件数量。如果小于或等于零,将最多打印DFS_LIST_LIMIT_DEFAULT(= 1000)
5 dfs.content-summary.limit 5000 一个锁定期内允许的最大内容摘要计数。 0或负数表示没有限制
6 dfs.content-summary.sleep-microsec 500 在内容摘要计算中重新获得锁定之间的使线程进入睡眠状态的时间长度(以微秒为单位)
7 dfs.namenode.fs-limits.max-component-length 255 定义路径的每个组件中以UTF-8编码的最大字节数。 值为0将禁用检查
8 dfs.namenode.fs-limits.max-directory-items 1024 * 1024 ≈100 万 定义目录可以包含的最大项数。无法将属性设置为小于1或大于6400000的值
9 dfs.namenode.fs-limits.max-xattrs-per-inode 32
10 final int MAX_DIR_ITEMS 64 100 1000= 640万 我们需要一个最大最大值,因为默认情况下,
PB将message大小限制为64MB。
这意味着每个目录只能存储大约670万个条目,
但是为了安全起见,请使用640万个条目
11 dfs.namenode.name.cache.threshold 10 经常访问的文件的访问次数超过此阈值的次数被缓存在FSDirectory nameCache中
  1. FSDirectory(FSNamesystem ns, Configuration conf) throws IOException {
  2. this.dirLock = new ReentrantReadWriteLock(true); // fair
  3. this.inodeId = new INodeId();
  4. rootDir = createRoot(ns);
  5. inodeMap = INodeMap.newInstance(rootDir);
  6. // 权限: 默认开启 ==> dfs.permissions.enabled : true
  7. this.isPermissionEnabled = conf.getBoolean(
  8. DFSConfigKeys.DFS_PERMISSIONS_ENABLED_KEY,
  9. DFSConfigKeys.DFS_PERMISSIONS_ENABLED_DEFAULT);
  10. // dfs.permissions.ContentSummary.subAccess : false
  11. this.isPermissionContentSummarySubAccess = conf.getBoolean(
  12. DFSConfigKeys.DFS_PERMISSIONS_CONTENT_SUMMARY_SUBACCESS_KEY,
  13. DFSConfigKeys.DFS_PERMISSIONS_CONTENT_SUMMARY_SUBACCESS_DEFAULT);
  14. this.fsOwnerShortUserName =
  15. UserGroupInformation.getCurrentUser().getShortUserName();
  16. /// dfs.permissions.superusergroup : supergroup
  17. this.supergroup = conf.get(
  18. DFSConfigKeys.DFS_PERMISSIONS_SUPERUSERGROUP_KEY,
  19. DFSConfigKeys.DFS_PERMISSIONS_SUPERUSERGROUP_DEFAULT);
  20. // dfs.namenode.acls.enabled : false
  21. this.aclsEnabled = conf.getBoolean(
  22. DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY,
  23. DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_DEFAULT);
  24. LOG.info("ACLs enabled? " + aclsEnabled);
  25. this.posixAclInheritanceEnabled = conf.getBoolean(
  26. DFSConfigKeys.DFS_NAMENODE_POSIX_ACL_INHERITANCE_ENABLED_KEY,
  27. DFSConfigKeys.DFS_NAMENODE_POSIX_ACL_INHERITANCE_ENABLED_DEFAULT);
  28. LOG.info("POSIX ACL inheritance enabled? " + posixAclInheritanceEnabled);
  29. this.xattrsEnabled = conf.getBoolean(
  30. DFSConfigKeys.DFS_NAMENODE_XATTRS_ENABLED_KEY,
  31. DFSConfigKeys.DFS_NAMENODE_XATTRS_ENABLED_DEFAULT);
  32. LOG.info("XAttrs enabled? " + xattrsEnabled);
  33. this.xattrMaxSize = conf.getInt(
  34. DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_KEY,
  35. DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_DEFAULT);
  36. Preconditions.checkArgument(xattrMaxSize > 0,
  37. "The maximum size of an xattr should be > 0: (%s).",
  38. DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_KEY);
  39. Preconditions.checkArgument(xattrMaxSize <=
  40. DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_HARD_LIMIT,
  41. "The maximum size of an xattr should be <= maximum size"
  42. + " hard limit " + DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_HARD_LIMIT
  43. + ": (%s).", DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_KEY);
  44. this.accessTimePrecision = conf.getLong(
  45. DFS_NAMENODE_ACCESSTIME_PRECISION_KEY,
  46. DFS_NAMENODE_ACCESSTIME_PRECISION_DEFAULT);
  47. //dfs.storage.policy.enabled : true
  48. this.storagePolicyEnabled =
  49. conf.getBoolean(DFS_STORAGE_POLICY_ENABLED_KEY,
  50. DFS_STORAGE_POLICY_ENABLED_DEFAULT);
  51. this.quotaByStorageTypeEnabled =
  52. conf.getBoolean(DFS_QUOTA_BY_STORAGETYPE_ENABLED_KEY,
  53. DFS_QUOTA_BY_STORAGETYPE_ENABLED_DEFAULT);
  54. // dfs.ls.limit : 1000
  55. int configuredLimit = conf.getInt(
  56. DFSConfigKeys.DFS_LIST_LIMIT, DFSConfigKeys.DFS_LIST_LIMIT_DEFAULT);
  57. this.lsLimit = configuredLimit>0 ?
  58. configuredLimit : DFSConfigKeys.DFS_LIST_LIMIT_DEFAULT;
  59. // dfs.content-summary.limit : 5000
  60. this.contentCountLimit = conf.getInt(
  61. DFSConfigKeys.DFS_CONTENT_SUMMARY_LIMIT_KEY,
  62. DFSConfigKeys.DFS_CONTENT_SUMMARY_LIMIT_DEFAULT);
  63. //dfs.content-summary.sleep-microsec 500
  64. this.contentSleepMicroSec = conf.getLong(
  65. DFSConfigKeys.DFS_CONTENT_SUMMARY_SLEEP_MICROSEC_KEY,
  66. DFSConfigKeys.DFS_CONTENT_SUMMARY_SLEEP_MICROSEC_DEFAULT);
  67. // filesystem limits
  68. // 路径最大长度: dfs.namenode.fs-limits.max-component-length : 255
  69. this.maxComponentLength = conf.getInt(
  70. DFSConfigKeys.DFS_NAMENODE_MAX_COMPONENT_LENGTH_KEY,
  71. DFSConfigKeys.DFS_NAMENODE_MAX_COMPONENT_LENGTH_DEFAULT);
  72. // 目录最大数量 1024 * 1024 = 1048576 ≈ 100 万
  73. // dfs.namenode.fs-limits.max-directory-items : 1024 * 1024
  74. this.maxDirItems = conf.getInt(
  75. DFSConfigKeys.DFS_NAMENODE_MAX_DIRECTORY_ITEMS_KEY,
  76. DFSConfigKeys.DFS_NAMENODE_MAX_DIRECTORY_ITEMS_DEFAULT);
  77. // dfs.namenode.fs-limits.max-xattrs-per-inod: 32
  78. // inode的属性最大限制 32
  79. this.inodeXAttrsLimit = conf.getInt(
  80. DFSConfigKeys.DFS_NAMENODE_MAX_XATTRS_PER_INODE_KEY,
  81. DFSConfigKeys.DFS_NAMENODE_MAX_XATTRS_PER_INODE_DEFAULT);
  82. this.protectedDirectories = parseProtectedDirectories(conf);
  83. Preconditions.checkArgument(this.inodeXAttrsLimit >= 0,
  84. "Cannot set a negative limit on the number of xattrs per inode (%s).",
  85. DFSConfigKeys.DFS_NAMENODE_MAX_XATTRS_PER_INODE_KEY);
  86. // 我们需要一个最大最大值,因为默认情况下,
  87. // PB将message大小限制为64MB。
  88. // 这意味着每个目录只能存储大约670万个条目,
  89. // 但是为了安全起见,请使用640万个条目。
  90. final int MAX_DIR_ITEMS = 64 * 100 * 1000;
  91. Preconditions.checkArgument(
  92. maxDirItems > 0 && maxDirItems <= MAX_DIR_ITEMS, "Cannot set "
  93. + DFSConfigKeys.DFS_NAMENODE_MAX_DIRECTORY_ITEMS_KEY
  94. + " to a value less than 1 or greater than " + MAX_DIR_ITEMS);
  95. // dfs.namenode.name.cache.threshold: 10
  96. // 经常访问的文件的访问次数超过此阈值的次数被缓存在FSDirectory nameCache中。
  97. int threshold = conf.getInt(
  98. DFSConfigKeys.DFS_NAMENODE_NAME_CACHE_THRESHOLD_KEY,
  99. DFSConfigKeys.DFS_NAMENODE_NAME_CACHE_THRESHOLD_DEFAULT);
  100. NameNode.LOG.info("Caching file names occurring more than " + threshold
  101. + " times");
  102. nameCache = new NameCache<ByteArray>(threshold);
  103. namesystem = ns;
  104. this.editLog = ns.getEditLog();
  105. ezManager = new EncryptionZoneManager(this, conf);
  106. this.quotaInitThreads = conf.getInt(
  107. DFSConfigKeys.DFS_NAMENODE_QUOTA_INIT_THREADS_KEY,
  108. DFSConfigKeys.DFS_NAMENODE_QUOTA_INIT_THREADS_DEFAULT);
  109. initUsersToBypassExtProvider(conf);
  110. }

常量

  • INodeDirectory rootDir:整个文件系统目录树的根节点,是 INodeDirectory 类型的
  • FSNamesystem namesystem:Namenode 的门面类,这个类主要支持对数据块进行操作的一些方法,例如addBlock()
  • INodeMap inodeMap:记录根目录下所有的 INode,并维护 INodeId 到 INode 的映射关系
  • ReentrantReadWriteLock dirLock:对目录树以及 inodeMap 字段操作的锁
  • NameCache nameCache:将常用的 name 缓存下来,以降低 byte[] 的使用,并降低JVM heap的使用