簡(jiǎn)介
為了解決HDFS的水平擴展性問(wèn)題,社區從Apache Hadoop 0.23.0版本開(kāi)始引入了HDFS federation。HDFS Federation是指 HDFS集群可同時(shí)存在多個(gè)NameNode/Namespace,每個(gè)Namespace之間是互相獨立的;
單獨的一個(gè)Namespace里面包含多個(gè) NameNode,其中一個(gè)是主,剩余的是備,這個(gè)和上面我們介紹的單Namespace里面的架構是一樣的。這些Namespace共同管理整個(gè)集群的數據,每個(gè)Namespace只管理一部分數據,之間互不影響。
集群中的DataNode向所有的NameNode注冊,并定期向這些NameNode發(fā)送心跳和塊信息,同時(shí)DataNode也會(huì )執行NameNode發(fā)送過(guò)來(lái)的命令。集群中的NameNodes共享所有DataNode的存儲資源。HDFS Federation的架構如下圖所示:

子模塊
State Store模塊
初始化
初始化是從類(lèi)Router的serviceInit函數觸發(fā)的。
提供開(kāi)關(guān):dfs.federation.router.store.enable,默認開(kāi)啟。核心實(shí)現類(lèi)是StateStoreService。
在serviceInit的時(shí)候初始化。
初始化store driver,通過(guò)配置dfs.federation.router.store.driver.class,默認為StateStoreZooKeeperImpl.class,通過(guò)反射機制初始化。目前默認支持的有:
- StateStoreFileImpl
- StateStoreFileSystemImpl
- StateStoreMySQLImpl
- StateStoreZooKeeperImpl
注冊record stores,目前支持的有:
- MembershipStoreImpl
- MountTableStoreImpl
- RouterStoreImpl
- DisabledNameserviceStoreImpl
所有的record stores都保存在recordStores當中。
// Add supported record stores
addRecordStore(MembershipStoreImpl.class);
addRecordStore(MountTableStoreImpl.class);
addRecordStore(RouterStoreImpl.class);
addRecordStore(DisabledNameserviceStoreImpl.class);
初始化定期檢查任務(wù)
// Check the connection to the State Store periodicallythis
this.monitorService = new StateStoreConnectionMonitorService(this);
this.addService(monitorService);
初始化緩存跟新服務(wù)
// Cache update service
this.cacheUpdater = new StateStoreCacheUpdateService(this);
addService(this.cacheUpdater);
最后是初始化監控信息,核心的監控實(shí)現bean是StateStoreMBean。
啟動(dòng)
啟動(dòng)主要是Router的serviceStart函數觸發(fā),最終調用StateStoreDriver的init函數,用于初始化driver。核心函數為initDriver和initRecordStorage。
其中initRecordStorage針對每個(gè)record stores都需要調用,如下:
for (Class<? extends BaseRecord> cls : records) {
String recordString = StateStoreUtils.getRecordName(cls);
if (!initRecordStorage(recordString, cls)) {
LOG.error("Cannot initialize record store for {}", cls.getSimpleName());
return false;
}
}
StateStoreFileImpl or StateStoreFileSystemImpl
initDriver
對于當前的StateStore初始化比較簡(jiǎn)單,主要是檢查本地文件夾是否存在,不存在就創(chuàng )建。大致代碼如下:
public boolean initDriver() {
String rootDir = getRootDir();
if (rootDir == null) {
LOG.error("Invalid root directory, unable to initialize driver.");
return false;
}
// Check root path
if (!exists(rootDir)) {
if (!mkdir(rootDir)) {
LOG.error("Cannot create State Store root directory {}", rootDir);
return false;
}
}
// ... 省略 ...
int threads = getConcurrentFilesAccessNumThreads();
this.concurrentStoreAccessPool =
new ThreadPoolExecutor(threads, threads, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(),
new ThreadFactoryBuilder()
.setNameFormat("state-store-file-based-concurrent-%d")
.setDaemon(true).build());
return true;
}
initRecordStorage
和initDriver類(lèi)似,支持針對每個(gè)State Store創(chuàng )建對應的目錄,目錄名稱(chēng)使用state store的className。
public <T extends BaseRecord> boolean initRecordStorage(
String className, Class<T> recordClass) {
String dataDirPath = getRootDir() + "/" + className;
// Create data directories for files
if (!exists(dataDirPath)) {
LOG.info("{} data directory doesn't exist, creating it", dataDirPath);
if (!mkdir(dataDirPath)) {
LOG.error("Cannot create data directory {}", dataDirPath);
return false;
}
}
return true;
}
StateStoreMySQLImpl
initDriver
核心邏輯就是創(chuàng )建Mysql連接。Mysql連接封裝為類(lèi)MySQLStateStoreHikariDataSourceConnectionFactory。
MySQLStateStoreHikariDataSourceConnectionFactory(Configuration conf) {
Properties properties = new Properties();
properties.setProperty("jdbcUrl", conf.get(StateStoreMySQLImpl.CONNECTION_URL));
properties.setProperty("username", conf.get(StateStoreMySQLImpl.CONNECTION_USERNAME));
properties.setProperty("password", conf.get(StateStoreMySQLImpl.CONNECTION_PASSWORD));
properties.setProperty("driverClassName", conf.get(StateStoreMySQLImpl.CONNECTION_DRIVER));
// Include hikari connection properties
properties.putAll(conf.getPropsWithPrefix(HIKARI_PROPS));
HikariConfig hikariConfig = new HikariConfig(properties);
this.dataSource = new HikariDataSource(hikariConfig);
}
initRecordStorage
zai StateStoreMySQLImpl當中,每個(gè)state store 對應一張表。建表語(yǔ)句如下:
CREATE TABLE <className> (
recordKey VARCHAR (255) NOT NULL,
recordValue VARCHAR (2047) NOT NULL,
PRIMARY KEY(recordKey))
)
StateStoreZooKeeperImpl
initDriver
initRecordStorage