赴海獨漂櫓,白首度餘生。 -- 木心
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。
image.png -
TokenStoreDelegationTokenSecretManager 返回 Token,并且使用自己的 createPassword 方法為這個Token生成密碼。除了照搬hadoop-common里面的記錄Token的生命周期外,還額外的調用了tokenStore.addToken將我們的token信息保存進了DelegationTokenStore中。
image.png
-
-
Token認證
-
服務端認證調用 SaslDigestCallbackHandler回調方法,從nc中拿到客戶端傳遞過來的DelegationTokenIdentifier,在getPassword一步,服務端將做兩部驗證,第一,這個Token是否存在;第二,這個Token是否過期。如果驗證合格,則處理業務。
image.pngimage.png
-
-
Token清理
-
因為引入了額外的存儲方式 DelegationTokenStore, 為了防止存儲數據無限膨脹,我們需要定時對服務端過期的Token進行remove。
image.png
image.png
-
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共享問題。