QJM的基本原理是用2N+1个JournalNode存储Editlog,每次写数据操作都有大部分(>=N+1)当返回成功时,我认为写作成功,数据不会丢失。当然,该算法最多可以容忍N台机器。如果超过N台机器,该算法将无效。
第二部分
2.1.写日志机制编写操作由主节点完成。当主节点调用flush操作时,RPC将被调用到N个JN服务中,并异步编写日志。如果有N/2+1个节点返回成功,则此编写操作将成功。
主节点将标记返回失败的JN节点。在下次调用滚动日志之前,将不再编写该节点。如果JN节点恢复正常,主节点将在主节点后编写日志。虽然节点丢失了一些日志,但由于主节点写了多个日志,相应的日志并没有丢失。
为了保证每个日志文件txid的连续性,主节点确保分配的txid是连续的。同时,当JN节点接受编写日志时,将首先检查txid是否与上次连续编写。如果不连续,将向主节点报告错误,并连续编写日志文件。
2.2阅读日志机制1、选择日志文件,建立输入流
所有未消化的日志文件从节点遍历,未处理的文件将被删除。对于每个JN节点上的日志文件,根据txid从小到大排序放入集合。这样的集合对应于从节点端的每个JN节点。然后将每个JN节点之间相同的日志文件分为一组(组内日志将检查fisrttxid是否相等,lasttxid是否相等);每组之间按txid从小到大进行排序,方便从节点按txid顺序消化日志;同时判断每组之间的txid是否连续。
2、消化日志
输入流准备好后,开始消化日志,按照txid的顺序从每个日志组从节点消化日志。在每个日志组中,首先检查txid是否正确。如果是正确的,首先从节点消化第一个日志文件,如果第一个日志文件消化失败,则消化第二个日志文件,以此类推。如果日志组中的文件在经历后没有找到所需的日志,则日志消化失败,如果消化每个日志的最后一个txid等于日志文件的lasttxid,日志文件消化结束。
处理如下图所示:
2.3.日志恢复最近的日志段状态将在从节点切换到主节点的过程中进行检查。如果不转换为finalized状态,则将其转换为该状态,日志恢复正在进行中。
2.3.1.触发条件
QJM将检查最新日志文件的数据一致性,然后决定是否触发数据修复过程。
HDFS之前的日志文件将确保它已经从inprocess状态转变为finalized状态,因此只有最新的日志文件是新的,可能需要恢复此处理。
2.3.2.恢复流程
2.3.2.1.准备恢复preparecover
操作将RPC请求发送到JN端,查询需要恢复的日志段文件是否存在。如果存在,则判断日志段文件的状态(inprocess或finalized),还将返回epoch号,namenode根据返回的查询信息通过修复算法选择修复的源节点,准备数据修复。
修复策略:
1、首先,判断JN节点是否有指定的txid。如果没有节点,节点将不作为源节点;
2、如果JN节点中有指定的txid,则判断该文件是否处于finalized状态。如果不同的JN节点,txid所在的文件包括finalized状态文件和inprocess状态文件,则以finalized状态文件为候选源节点,当然,在finalized状态的文件之间,需要判断txid是否相等,然后返回任何节点作为源节点
如果节点间文件是inprocess状态的文件,则首先判断其epoch编号。如果epoch编号不一致,则以epoch编号较大的epoch作为候选源节点;如果epoch编号一致,则选择结束txid作为源节点。)
2.3.2.2.acceptrecovery接受恢复
计算源节点后,Namenode将恢复操作发送到JN端。JN节点根据收到的RPC恢复请求,判断当前节点是否需要日志修复。如果需要修复,则通过doget将需要恢复的目标日志文件下载到源节点。在下载过程中,首先将下载的文件放入临时目录(tmp)在目录下,下载完成后进行md5验证,检查是否有数据丢失,然后将下载的文件放入工作目录(current)这样,数据恢复就完成了。
在JN节点的实施中,有两个问题需要考虑:
您可以考虑返回URL数组,而不是单个URL,这样一个URL不能连接,也可以尝试连接其他JN节点下载文件;
2、在JN节点下载日志文件时,有可能挂掉自己的过程,在QJM中,有办法处理这个问题;
当我第一次接触时,我担心是否可能有文件从节点读取,恢复日志文件。经过分析,我发现不会发生任何情况,因为从节点消化的日志是finalized状态的文件,而不是inprocess状态的文件。