实现从SBN上进行一致性读取
背景
在HA模式下的HDFS通常有两个namenode,一个处于活动状态,另一个处于待机状态。备用节点(SBN)是热的,这意味着一旦发生故障,从活动的NameNode (ANN)到SBN的故障转移可以在相当短的时间内发生,因此对客户端是透明的。SBN通过日志保持热度。ANN将称为事务的所有名称空间更新发布到Quorum Journal Manager (QJM),而SBN从QJM使用它们。因此日志记录是协调ANN和SBN之间状态的一种手段。这也意味着SBN上的名称空间状态与ANN上的相同,除了最近修改的对象的有限集合。后者为从SBN而不是活动的NameNode读取元数据创造了机会。理想情况下,我们希望在ANN和SBN之间平衡读取请求的负载,这将使集群上读取元数据的吞吐量翻倍。写请求仍将由ANN处理,但由于实际上读操作占所有元数据操作的90%左右,负载平衡应该会得到显著改善NameNode的总体吞吐量。所以实现从SBN上进行读取元数据操作的目的是:充分利用SBN的处理能力,尽量将读请求转向SBN处理,而让ANN处理写请求,以此大大增强集群的处理能力(吞吐量和性能)。
延迟读问题(读一致性问题)
ANN和SBN经历了相同的转换序列,每个转换都改变了名称空间的状态。我们假设状态是由状态id标识的,状态id随着每次变换单调递增。NameNode的事务id是状态id的当前实现。实现从SBN读取的主要挑战是一致性。当到达相同的状态id时,ANN和SBN的状态是一样的,但是SBN是它的leader ANN的追随者,所以它总是在后面,因为它消耗了ANN已经执行的事务,并且有延迟。因此从客户端角度来看,它可以向任意一个节点发送读请求,并从每个节点获得对HDFS中大多数“旧”文件的正确响应。但它需要能够识别一些最近修改过的“新”文件,并为这些文件找到真相的来源。举个简单的例子,用户在HDFS内新创建一个文件,然后立即去查询此文件的信息,在ANN上很显然我们能查到结果,但是从SBN上,可能就查不到。所以与任何复制的分布式系统一样,应该解决陈旧读取(延迟读)的问题,也就是一致性问题。我们的主要目标是以一致的方式提供备用数据读取,以使大量现有应用程序可以在HDFS之上运行。
一致性模型
参考hadoop jira上设计文档翻译如下:假设obj.modId是对象obj最后一次修改的状态id。其中object是文件或目录的索引节点。我们的一致性方法可以表述为以下原则:如果客户c1在t1时刻的modId1看到或修改对象状态,那么在未来的任意时刻,c1将看到该对象的状态在modId2 >= modId1. 当客户端总是通过相同的活动NameNode访问名称空间时,此原则对应于当前语义。当SBN读取开始发挥作用时,同样的原则自动应用到ANN,因为在未来的任何时候,客户端都不能看到ANN上过去的状态。但是对于SBN,它可能是违反的,因为SBN反映了ANN最近的一些过去的状态。因此,我们的目标是在通过SBN访问名称空间时提供相同的一致性。
Our consistency approach can be formulated as the following principle:
If a client c1 sees or modifies an object state at modId1 at time t1,
then in any future time t2 > t1, c1 will see the state of that object at modId2 >= modId1
一致性读的实现
保证一致性的读取称为协调读取。协调读取确保它使用大于或等于已知id的状态id访问名称空间的状态。并不是所有的阅读都需要协调。实际上,大多数名称空间对象不需要这样做,因为在namenode上的大多数名称空间对象是相同的。只有一小部分与最近的事务都有所不同。
有两种方式来执行协调读取:
1. 从待机状态读取,但仅在它赶上客户机所知道的状态之后。
2. 从活动状态读取,ANN读取总是很协调。
可以总结为实现一致性读核心思想是首先从SBN节点去读数据,需要保证事务信息一致,如果客户端发现事务差距过大,则直接从ann节点上读取。
namenode将其最新的状态id作为LastWrittenId进行跟踪,它对应于名称空间的最后一次更新,或者是写入NN日志的最后一次事务。我们为每个HDFS客户端引入LastSeenId,它在每次调用ANN或SBN时更新,并设置为各自的LastWrittenId。假设客户端c向ANN发送了一个写请求。调用一旦执行也将设置c.LastSeenId =ANN返回的LastWrittenId。现在c向SBN发送一个读请求。SBN延迟客户机请求的执行,直到c.LastSeenId < = SBN.LastWrittenId,然后执行请求。这也将重置c.LastSeenId = SBN.LastWrittenId。因此c的后续呼叫SBN将不会延迟。客户总是可以从SBN切换到ANN而不会因为ANN而延迟。LastWrittenId > = SBN.LastWrittenId > = c.LastSeenId。如果将日志事务从ANN传播到SBN的延迟很小,也就是说,与客户端从一个节点切换到另一个节点所需的时间相当,这应该可以很好地工作。但是如果SBN太落后,客户应该切换回ANN而不是SBN。
其他:
1. HDFS中的客户机-服务器通信是通过可插拔的FailoverProxyProvider类来执行的。它的当前实现假设故障发生时从活动节点转移到备用节点。当允许从SBN读取数据时,从一个节点切换到另一个节点就成了常规。交换逻辑以及协调读取应该嵌入到一个名为StandbyReadProxyProvider的新代理提供程序中,此provider代理会将读请求转发到SBN。
2. 引入新节点ObserverNode,和SBN功能类似,也需要实时同步editlog并加载,但是不会做周期checkpoint操作,启动方式:hdfs namenode -observer。
3. 原有逻辑中,SBN只读已经关闭了的editlog文件,然后一个整的segement文件去读。而一个关闭的editlog文件依赖于定期触发ANN的log roll操作,这期间就会有时间延时,无法立即消费到最新数据。倘若SBN能够支持读in-progress的数据,无疑将会大大减少其中的数据延时。所以为了使得SBN能够尽可能快地追上新的数据,需要实现SBN支持tailing in-progress的editlog。
ANN,SBN,ONN可以相互转换,如下图。
参考资料:Consistent Reads from Standby Node
本文地址:https://blog.csdn.net/breakout_alex/article/details/107554972