赴海獨漂櫓,白首度餘生。 -- 木心
Just For M
前言
为了梳理 apache sentry_1.5.0 开启 hdfs sync 功能后 不再支持hs2的Metastore HA 的原因,最近把�HiveServer2 的部署架构梳理了一遍,网上针对该类信息的文章也非常少,特地在这里整理出来,以供大家讨论。
先描述一下我们的 HiveServer2 的部署背景,我们的大数据平台是CDH, 整个平台使用 KERBEROS 来进行身份验证,权限控制使用的是 Sentry + Acls, 我们的 HiveServer2 服务使用 LDAP 或者 KERBEROS 来对用户进行身份验证,实际上开启 LDAP 验证的 HiveServer2 也是可以进行 KERBEROS 验证的,但是 hive on spark 这个功能的开启,导致了 HiveServer2 必须是 KERBEROS 验证的(他们使用了一个相同的config来进行判断提交任务是否需要 KERBEROS)。
一般情况下部署 HiveServer2 ,大家应该很熟悉。Metastore 可以选择是 内嵌 还是 单独部署,为了保证服务的高可用性(HA),我们可能会部署多台 HiveServer2 以及 多台 Metastore,他们也起到了负载均衡的效果。而在安全的情况下,配置的时候需要些许注意,而 HiveServer2 内部也会多执行一些东西来保证认证安全,下面我们所要讲的就是这些流程。
HiveServer2
图例展示了一个通用的部署模式: HiveServer2 多台,Metastore 多台,使用 mysql 等关系型数据库来保存元数据信息。 HiveServer2 如果需要修改元数据信息,会将请求发送到 Metastore 。
HiveServer2 使用 Thrift 来进行通信, 用户使用 jdbc 或者 Thrift 连接到 HiveServer2; HiveServer2 每个执行线程如果需要与后面的 Metastore 通信也是使用 Thrift 连接。
ThrfitSasl
看过 kerberos体系下的应用(yarn,spark on yarn) 的用户可能已经对 ThrfitSasl 连接方式了解了,我们这里将描述一下通信过程:
- 我们的 ThrfitSasl 接受两种验证, KERBEROS 认证以及由自己下发给客户端的 Token;
- Token 认证是有时效性的,有最大刷新时间和失效时间。
- 关于Token认证,如果大家对 HDFS 里面NameNode、DataNode 里面的 Token 的逻辑有所耳闻,阅读 HiveServer2 Token逻辑,会感觉似曾相识,是的,hive里面的相关逻辑是借鉴 hadoop-common。
让我们对其中的细节再深入思考一下。
KERBEROS认证
- 如果 conf 没有
hive.metastore.token.signature
,选择kerberos认证方式,创建SaslClient的实现类GssKrb5Client用于与 SaslServer 通信。 -
hive.server2.enable.doAs
为 false 的服务,均使用kerberos认证,因为我们的平台使用 sentry 来做权限管理,所以是不允许 doAs 操作的,提交任务的用户均为hive 用户。 - 这意味着运行SaslClient端的服务上 UGI 要不断更新,保持自己的
tgt。 - 关于
javax.security.sasl
实现的逻辑,这里不扩展了,有兴趣的可以查阅资料,后面有机会会专门分析。
Token认证
想一想,如果我们要效仿HDFS的Delegation Token逻辑,在实现上我们需要什么?
- 首先服务端要能够生成有时效性的Token,并且有能判断Token是否过期的能力。
- 因为需要沿用hadoop-common中的token的数据结构,我们返回的 Token 的格式应该是继承自 AbstractDelegationTokenIdentifier。 在Hive中,这个类型为DelegationTokenIdentifier,其中KindName标示为
HIVE_DELEGATION_KIND
。 - 返回的Token 将由UGI统一管理:
ugi.addToken(delegationToken)
- 我们知道UGI可能同时管理访问不同组件的多个Token,所以我们还应该有个选择
HIVE_DELEGATION_KIND
的选择器:DelegationTokenSelector, 有了它,我们在创建 SaslClient的时候可以获得对应的Token:
上述应该是使用 Token 认证的各个部分的注意事项。
Token认证-服务端
服务端(e.g: Metastore)使用 HiveDelegationTokenManager 来进行Token管理。类中主要包含了一个继承自hadoop-common AbstractDelegationTokenSecretManager的 TokenStoreDelegationTokenSecretManager,也是我们这节探讨的重点。
-
Token生成
-
客户端申请一个Token使用,服务端收到get_delegation_token请求时候(这次通信是kerberos认证的),调用TokenStoreDelegationTokenSecretManager方法 getDelegationToken。
-
TokenStoreDelegationTokenSecretManager 返回 Token,并且使用自己的 createPassword 方法为这个Token生成密码。除了照搬hadoop-common里面的记录Token的生命周期外,还额外的调用了tokenStore.addToken将我们的token信息保存进了DelegationTokenStore中。
-
-
Token认证
-
服务端认证调用 SaslDigestCallbackHandler回调方法,从nc中拿到客户端传递过来的DelegationTokenIdentifier,在getPassword一步,服务端将做两部验证,第一,这个Token是否存在;第二,这个Token是否过期。如果验证合格,则处理业务。
-
-
Token清理
-
因为引入了额外的存储方式 DelegationTokenStore, 为了防止存储数据无限膨胀,我们需要定时对服务端过期的Token进行remove。
-
Token认证-DelegationTokenStore
Metastore提供三种存储方式:
- MemoryTokenStore
- DBTokenStore
- ZooKeeperTokenStore
第一种是内存,这里不做解读,对于后两者,为什么 Metastore 要把这部分数据统一持久化呢?我们持久化的是什么信息?我们持久化的大部分是可以使用的Token,当验证Token认证的客户端的时候将时候到这部分信息。
如果我们部署了多台Metastore, HiveServer2 随机选择一台进行连接操作,如果我们打开了doAs,那么我们业务线程连接Metastore将使用Token认证。这个时候我们已经连接的Metastore突然挂掉,客户端重连到了另外一台Metastore上去,因为我们知道Metastore是无状态的,所以重连到新的机器上不影响业务数据。但是新的Metastore如果认证这个Token? 是的!! 因为它们的所有Metastore 所有的Token信息都是共享的,新的Metastore 轻而易举的就通过了重连的客户端认证。
总结
读完全文之后,希望读者重新查看本文的�HiveServer2-HA-架构图,其实想表达的逻辑都在图中。这里需要重点注意的是,我们在部署 Metastore HA后,如果开启了Token认证,请务必使用DBTokenStore或者ZooKeeperTokenStore,否则HiveServer2与Metastore 的断开重连对用户不透明。但是如果只会使用KERBEROS认证,则不会存在Token共享问题。