在我的服务器应用程序中,我正在从Java应用程序连接到受Kerberos保护的Hadoop群集。我正在使用HDFS文件系统,Oozie,Hive等各种组件。在应用程序启动时,我确实打电话给
UserGroupInformation.loginUserFromKeytabAndReturnUGI( ... );
这将返回我的UserGroupInformation
实例,并在应用程序生存期内保留它。当执行特权操作时,我使用启动它们ugi.doAs(action)
。
这可以正常工作,但我想知道是否以及何时更新kerberos票UserGroupInformation
?我发现了一种UserGroupInformation.checkTGTAndReloginFromKeytab()
似乎在快要到期时都会进行票证更新的方法。我还发现,WebHdfsFileSystem
例如各种Hadoop工具都在调用此方法。
现在,如果我希望我的服务器应用程序(可能运行数月甚至数年)从未经历过票证到期,那么最好的方法是什么?提供具体问题:
Hadoop提交者在这里!这是一个很好的问题。
不幸的是,如果不深入研究应用程序的特定使用模式,很难给出明确的答案。相反,我可以提供一般准则,并描述Hadoop何时为您自动处理票证更新或从keytab重新登录,以及何时不这样做。
Hadoop生态系统中Kerberos身份验证的主要用例是Hadoop的RPC框架,该框架使用SASL进行身份验证。Hadoop生态系统中的大多数守护进程都通过UserGroupInformation#loginUserFromKeytab
在进程启动时进行一次一次性调用来处理此问题。这样的示例包括HDFS DataNode和YARN NodeManager,它们必须对对NameNode的RPC调用进行身份验证,而YARN NodeManager必须对对ResourceManager的调用进行身份验证。诸如DataNode之类的守护程序如何在流程启动时进行一次登录,然后继续运行数月,比典型的票证到期时间还长呢?
由于这是一个常见用例,因此Hadoop直接在RPC客户端层内部实现自动重新登录机制。此代码在RPCClient#handleSaslConnectionFailure方法中可见:
// try re-login
if (UserGroupInformation.isLoginKeytabBased()) {
UserGroupInformation.getLoginUser().reloginFromKeytab();
} else if (UserGroupInformation.isLoginTicketBased()) {
UserGroupInformation.getLoginUser().reloginFromTicketCache();
}
您可以将其视为重新登录的“惰性评估”。它仅在尝试进行RPC连接时由于身份验证失败而重新执行登录。
知道这一点,我们可以给出部分答案。如果您的应用程序的使用模式是从密钥表登录,然后执行典型的Hadoop RPC调用,那么您可能不需要滚动自己的重新登录代码。RPC客户端层将为您完成此任务。“典型的Hadoop RPC”表示用于与Hadoop交互的绝大多数Java API,包括HDFS FileSystemAPI,YarnClient和MapReduceJob提交。
但是,某些应用程序使用模式根本不涉及Hadoop RPC。这样的一个示例是仅与Hadoop的REST API(例如WebHDFS或YARN REST API)交互的应用程序。在这种情况下,身份验证模型会通过Hadoop HTTP身份验证文档中所述通过SPNEGO使用Kerberos 。
知道这一点,我们可以在答案中添加更多内容。如果您的应用程序的使用模式根本不使用Hadoop RPC,而是仅使用REST API,那么您必须滚动自己的重新登录逻辑。正如您所注意到的,这就是为什么WebHdfsFileSystem打电话的UserGroupInformation#checkTGTAndReloginFromkeytab原因。 WebHdfsFileSystem选择在每次操作前立即拨打电话。这是一个很好的策略,因为UserGroupInformation#checkTGTAndReloginFromkeytab仅在“接近”到期时更新票证。 否则,该呼叫为无人操作。
作为最终用例,让我们考虑一个交互式过程,而不是从keytab登录,而是要求用户kinit在启动应用程序之前在外部运行。在大多数情况下,这些应用程序将是短期运行的应用程序,例如Hadoop CLI命令。但是,在某些情况下,这些过程可能是运行时间更长的过程。为了支持运行时间更长的流程,Hadoop启动了一个后台线程来将Kerberos票证“关闭”更新为过期。该逻辑在UserGroupInformation#spawnAutoRenewalThreadForUserCreds。与RPC层中提供的自动重新登录逻辑相比,这里有一个重要的区别。在这种情况下,Hadoop仅具有续签和延长其寿命的功能。票证具有最大的可更新寿命,这由Kerberos基础结构决定。之后,该票将不再可用。在这种情况下,重新登录实际上是不可能的,因为这将暗示重新提示用户输入密码,并且他们很可能已离开终端。这意味着,如果该进程继续运行到票证到期之后,它将无法再进行身份验证。
同样,我们可以使用此信息来告知我们的总体答案。如果您kinit在启动应用程序之前依靠用户以交互方式登录,并且您确信该应用程序的运行时间不会超过Kerberos票证的最大可再生寿命,那么您可以依靠Hadoop内部构件来为您进行定期更新。
如果您使用的是基于keytab的登录方式,并且只是不确定应用程序的使用模式是否可以依赖Hadoop RPC层的自动重新登录,那么保守的方法是自行滚动。@SamsonScharfrichter在这里给自己一个很好的答案。
HBase Kerberos连接更新策略
最后,我应该添加有关API稳定性的注释。该Apache Hadoop Compatibility准则详细讨论了Hadoop开发社区对向后兼容的承诺。的接口UserGroupInformation带有LimitedPrivate和Evolving。从技术上讲,这意味着的APIUserGroupInformation
不被认为是公共的,并且可能以向后不兼容的方式发展。实际上,已经有很多代码取决于的接口UserGroupInformation,因此对我们来说,进行重大更改根本不可行。当然,在当前的2.x版本中,我不会担心方法签名会从您的身下改变并破坏您的代码。
既然我们已经掌握了所有这些背景信息,那么让我们重新讨论您的具体问题。
是否可以在需要时依赖它们调用checkTGTAndReloginFromKeytab的各种Hadoop客户端?
如果您的应用程序的使用模式是调用Hadoop客户端,则可以依靠它,而Hadoop客户端又利用Hadoop的RPC框架。如果您的应用程序的使用模式仅调用Hadoop REST API,则您不能依靠它。
我应该在自己的代码中自称checkTGTAndReloginFromKeytab
吗?
如果您的应用程序的使用模式仅是调用Hadoop REST API而不是Hadoop RPC调用,则可能需要执行此操作。您将无法从Hadoop的RPC客户端内部实现的自动重新登录中受益。
如果是这样,我应该在每次调用ugi.doAs(…)之前执行此操作,还是设置一个计时器并定期(多长时间一次)调用一次?
可以UserGroupInformation#checkTGTAndReloginFromKeytab
在需要验证的每个操作之前立即进行调用。如果票证即将到期,则该方法将为无操作。如果您怀疑Kerberos基础结构缓慢,并且您不希望客户端操作支付重新登录的延迟成本,那么这就是在单独的后台线程中进行此操作的原因。只要确保在票证的实际到期时间之前提前一点时间即可。您可以借用内部逻辑UserGroupInformation来确定票证是否“接近”到期。在实践中,我从未亲自看到过重新登录的延迟有问题。
我有一个< code>Observable链(RxJava 1),我想在Observable完成它的工作时(就在它发出某个东西之前),但在调用任何订户回调之前(我想更新某个< code>AtomicBoolean值,并让所有订户都看到新值),执行一些一次性操作。 以线程安全的方式执行此操作的最佳选择是什么? 我检查了 ,,,但似乎没有关于顺序的保证:我放了一些日志,有时在任何这些方法之前执行第一个
我正在写一个算法,舍入一个浮点数。输入将是64位IEEE754双类型数,非常接近X.5,其中X是小于32的整数。我想到的第一个解决方案是使用位掩码,掩码掉那些最低有效位,因为它们代表2^-n的非常小的分数。(给定指数不大)。 但是问题是我应该这样做吗?有没有其他方法来完成同样的事情?我觉得在浮点上使用比特操作非常有争议。谢谢! 顺便说一下,我用的语言是C。 编辑:谢谢你们的评论。我很感激!假设我有
问题内容: 我想告诉Node.js无论出于何种原因(+ ,异常或任何其他原因)总是在退出之前总是做一些事情。 我尝试了这个: 我开始了该过程,将其杀死,但没有任何反应。我再次启动它,按+ ,仍然没有任何反应… 问题答案: 更新: 您可以注册一个处理程序,并在任何其他情况下(或未处理的异常)进行调用
问题内容: 我有下面的代码打开一个文件,将其读入缓冲区,然后关闭该文件。 关闭文件系统调用要求文件描述符号在ebx寄存器中。ebx寄存器在进行读取系统调用之前获取文件描述符号。我的问题是,在进行读取系统调用之前,我应该将ebx寄存器保存在堆栈中还是某处(int 80h是否可以丢弃ebx寄存器?)。然后恢复ebx寄存器以关闭系统调用?还是我下面的代码安全无虞? 我已经运行了下面的代码并且可以正常工作
--更新二-- 所以我写了这些方法,但我对不同的对象以及如何在驱动程序/测试程序中调用这些方法有点迷惑。以下是我的问题(请原谅,因为它们对一些人来说可能很琐碎):- (1)为什么我们传递一个节点而不是树给这些方法? (2)当我在驱动程序中创建树并试图调用treeHeight方法时,我得到一条错误消息,它告诉我传递了错误的参数(tree而不是node).....我知道这个错误,并理解为什么会有这个错