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中 |
FSDirectory(FSNamesystem ns, Configuration conf) throws IOException {
this.dirLock = new ReentrantReadWriteLock(true); // fair
this.inodeId = new INodeId();
rootDir = createRoot(ns);
inodeMap = INodeMap.newInstance(rootDir);
// 权限: 默认开启 ==> dfs.permissions.enabled : true
this.isPermissionEnabled = conf.getBoolean(
DFSConfigKeys.DFS_PERMISSIONS_ENABLED_KEY,
DFSConfigKeys.DFS_PERMISSIONS_ENABLED_DEFAULT);
// dfs.permissions.ContentSummary.subAccess : false
this.isPermissionContentSummarySubAccess = conf.getBoolean(
DFSConfigKeys.DFS_PERMISSIONS_CONTENT_SUMMARY_SUBACCESS_KEY,
DFSConfigKeys.DFS_PERMISSIONS_CONTENT_SUMMARY_SUBACCESS_DEFAULT);
this.fsOwnerShortUserName =
UserGroupInformation.getCurrentUser().getShortUserName();
/// dfs.permissions.superusergroup : supergroup
this.supergroup = conf.get(
DFSConfigKeys.DFS_PERMISSIONS_SUPERUSERGROUP_KEY,
DFSConfigKeys.DFS_PERMISSIONS_SUPERUSERGROUP_DEFAULT);
// dfs.namenode.acls.enabled : false
this.aclsEnabled = conf.getBoolean(
DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY,
DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_DEFAULT);
LOG.info("ACLs enabled? " + aclsEnabled);
this.posixAclInheritanceEnabled = conf.getBoolean(
DFSConfigKeys.DFS_NAMENODE_POSIX_ACL_INHERITANCE_ENABLED_KEY,
DFSConfigKeys.DFS_NAMENODE_POSIX_ACL_INHERITANCE_ENABLED_DEFAULT);
LOG.info("POSIX ACL inheritance enabled? " + posixAclInheritanceEnabled);
this.xattrsEnabled = conf.getBoolean(
DFSConfigKeys.DFS_NAMENODE_XATTRS_ENABLED_KEY,
DFSConfigKeys.DFS_NAMENODE_XATTRS_ENABLED_DEFAULT);
LOG.info("XAttrs enabled? " + xattrsEnabled);
this.xattrMaxSize = conf.getInt(
DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_KEY,
DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_DEFAULT);
Preconditions.checkArgument(xattrMaxSize > 0,
"The maximum size of an xattr should be > 0: (%s).",
DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_KEY);
Preconditions.checkArgument(xattrMaxSize <=
DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_HARD_LIMIT,
"The maximum size of an xattr should be <= maximum size"
+ " hard limit " + DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_HARD_LIMIT
+ ": (%s).", DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_KEY);
this.accessTimePrecision = conf.getLong(
DFS_NAMENODE_ACCESSTIME_PRECISION_KEY,
DFS_NAMENODE_ACCESSTIME_PRECISION_DEFAULT);
//dfs.storage.policy.enabled : true
this.storagePolicyEnabled =
conf.getBoolean(DFS_STORAGE_POLICY_ENABLED_KEY,
DFS_STORAGE_POLICY_ENABLED_DEFAULT);
this.quotaByStorageTypeEnabled =
conf.getBoolean(DFS_QUOTA_BY_STORAGETYPE_ENABLED_KEY,
DFS_QUOTA_BY_STORAGETYPE_ENABLED_DEFAULT);
// dfs.ls.limit : 1000
int configuredLimit = conf.getInt(
DFSConfigKeys.DFS_LIST_LIMIT, DFSConfigKeys.DFS_LIST_LIMIT_DEFAULT);
this.lsLimit = configuredLimit>0 ?
configuredLimit : DFSConfigKeys.DFS_LIST_LIMIT_DEFAULT;
// dfs.content-summary.limit : 5000
this.contentCountLimit = conf.getInt(
DFSConfigKeys.DFS_CONTENT_SUMMARY_LIMIT_KEY,
DFSConfigKeys.DFS_CONTENT_SUMMARY_LIMIT_DEFAULT);
//dfs.content-summary.sleep-microsec 500
this.contentSleepMicroSec = conf.getLong(
DFSConfigKeys.DFS_CONTENT_SUMMARY_SLEEP_MICROSEC_KEY,
DFSConfigKeys.DFS_CONTENT_SUMMARY_SLEEP_MICROSEC_DEFAULT);
// filesystem limits
// 路径最大长度: dfs.namenode.fs-limits.max-component-length : 255
this.maxComponentLength = conf.getInt(
DFSConfigKeys.DFS_NAMENODE_MAX_COMPONENT_LENGTH_KEY,
DFSConfigKeys.DFS_NAMENODE_MAX_COMPONENT_LENGTH_DEFAULT);
// 目录最大数量 1024 * 1024 = 1048576 ≈ 100 万
// dfs.namenode.fs-limits.max-directory-items : 1024 * 1024
this.maxDirItems = conf.getInt(
DFSConfigKeys.DFS_NAMENODE_MAX_DIRECTORY_ITEMS_KEY,
DFSConfigKeys.DFS_NAMENODE_MAX_DIRECTORY_ITEMS_DEFAULT);
// dfs.namenode.fs-limits.max-xattrs-per-inod: 32
// inode的属性最大限制 32
this.inodeXAttrsLimit = conf.getInt(
DFSConfigKeys.DFS_NAMENODE_MAX_XATTRS_PER_INODE_KEY,
DFSConfigKeys.DFS_NAMENODE_MAX_XATTRS_PER_INODE_DEFAULT);
this.protectedDirectories = parseProtectedDirectories(conf);
Preconditions.checkArgument(this.inodeXAttrsLimit >= 0,
"Cannot set a negative limit on the number of xattrs per inode (%s).",
DFSConfigKeys.DFS_NAMENODE_MAX_XATTRS_PER_INODE_KEY);
// 我们需要一个最大最大值,因为默认情况下,
// PB将message大小限制为64MB。
// 这意味着每个目录只能存储大约670万个条目,
// 但是为了安全起见,请使用640万个条目。
final int MAX_DIR_ITEMS = 64 * 100 * 1000;
Preconditions.checkArgument(
maxDirItems > 0 && maxDirItems <= MAX_DIR_ITEMS, "Cannot set "
+ DFSConfigKeys.DFS_NAMENODE_MAX_DIRECTORY_ITEMS_KEY
+ " to a value less than 1 or greater than " + MAX_DIR_ITEMS);
// dfs.namenode.name.cache.threshold: 10
// 经常访问的文件的访问次数超过此阈值的次数被缓存在FSDirectory nameCache中。
int threshold = conf.getInt(
DFSConfigKeys.DFS_NAMENODE_NAME_CACHE_THRESHOLD_KEY,
DFSConfigKeys.DFS_NAMENODE_NAME_CACHE_THRESHOLD_DEFAULT);
NameNode.LOG.info("Caching file names occurring more than " + threshold
+ " times");
nameCache = new NameCache<ByteArray>(threshold);
namesystem = ns;
this.editLog = ns.getEditLog();
ezManager = new EncryptionZoneManager(this, conf);
this.quotaInitThreads = conf.getInt(
DFSConfigKeys.DFS_NAMENODE_QUOTA_INIT_THREADS_KEY,
DFSConfigKeys.DFS_NAMENODE_QUOTA_INIT_THREADS_DEFAULT);
initUsersToBypassExtProvider(conf);
}
常量
- INodeDirectory rootDir:整个文件系统目录树的根节点,是 INodeDirectory 类型的
- FSNamesystem namesystem:Namenode 的门面类,这个类主要支持对数据块进行操作的一些方法,例如addBlock()
- INodeMap inodeMap:记录根目录下所有的 INode,并维护 INodeId 到 INode 的映射关系
- ReentrantReadWriteLock dirLock:对目录树以及 inodeMap 字段操作的锁
- NameCache
nameCache:将常用的 name 缓存下来,以降低 byte[] 的使用,并降低JVM heap的使用