1、JournalSet
JournalSet是维护Journals的集合,FSEditLog通过initJournals(List dirs)填充该集合。
private synchronized void initJournals(List<URI> dirs) {
int minimumRedundantJournals = conf.getInt(
DFSConfigKeys.DFS_NAMENODE_EDITS_DIR_MINIMUM_KEY,
DFSConfigKeys.DFS_NAMENODE_EDITS_DIR_MINIMUM_DEFAULT);
synchronized(journalSetLock) {
journalSet = new JournalSet(minimumRedundantJournals);
for (URI u : dirs) {
boolean required = FSNamesystem.getRequiredNamespaceEditsDirs(conf)
.contains(u);
//本地文件
if (u.getScheme().equals(NNStorage.LOCAL_URI_SCHEME)) {
StorageDirectory sd = storage.getStorageDirectory(u);
if (sd != null) {
journalSet.add(new FileJournalManager(conf, sd, storage),
required, sharedEditsDirs.contains(u));
}
} else {
//jnode
journalSet.add(createJournal(u), required,
sharedEditsDirs.contains(u));
}
}
}
if (journalSet.isEmpty()) {
LOG.error("No edits directories configured!");
}
}
入参dirs包含了dfs.namenode.shared.edits.dir 和 dfs.namenode.edits.dir 对应jnode集群地址和本地edits保存地址(如果没有配置dfs.namenode.edits.dir,则使用dfs.namenode.name.dir)。对dirs中的每个地址,根据其schema创建不同的JournalManager,然后存入JournalSet。
- dfs.namenode.shared.edits.dir的value通常为qjournal://jn1:8485;jn2:8485;jn3:8485/nsInfo, 根据前缀DFS_NAMENODE_EDITS_PLUGIN_PREFIX和schema qjournal 确定对应JournalManager为QuorumJournalManager;
- dfs.namenode.edits.dir的value为file:///local_path,对应FileJournalManager。
public static final String DFS_NAMENODE_EDITS_PLUGIN_PREFIX = "dfs.namenode.edits.journal-plugin";
<property>
<name>dfs.namenode.edits.journal-plugin.qjournal</name>
<value>org.apache.hadoop.hdfs.qjournal.client.QuorumJournalManager</value>
</property>
JournalSet在添加JournalManager时会用两类JournalManager构建出两个JournalAndStream对象保存在集合中。
private final List<JournalAndStream> journals = new CopyOnWriteArrayList<JournalSet.JournalAndStream>();
void add(JournalManager j, boolean required, boolean shared) {
JournalAndStream jas = new JournalAndStream(j, required, shared);
journals.add(jas);
}
2、JournalAndStream 每个JournalAndStream维护一个JournalManager,其startLogSegment()方法用于产生一个新的editlog segment,并创建一个新的EditLogOutputStream 用于向新的segment中写入操作记录。
public void startLogSegment(long txId, int layoutVersion) throws IOException {
Preconditions.checkState(stream == null);
disabled = false;
stream = journal.startLogSegment(txId, layoutVersion);
}
3、QuorumJournalManager
QuorumJournalManager负责将edit写入JournalNodes,后续会专门分析。
4、FileJournalManager
ActiveNamenode上的FileJournalManager 负责将edit写入本地文件(edits__${beg_txid}_${end_txid})。当每次滚动一个新的edit log segment时,其startLogSegment( )方法会被触发,该方法创建一个新的EditLogFileOutputStream对象用于edit的写入。