YARN 服務註冊

簡介和概念

這份文件描述了一個 Hadoop 服務註冊,用來解決兩個問題

  1. 用戶端如何與 YARN 部署的服務和組成這些服務的元件通訊?
  2. 允許 Hadoop 核心服務註冊和發現,藉此減少組態參數並讓核心服務更容易被移動。

服務註冊和發現是分散式運算中一個長久存在的問題,可追溯到 Xerox 的 Grapevine 服務。此提案是一個註冊,用於定位由 YARN 部署的分散式應用程式,並決定與這些應用程式通訊所需的繫結資訊。

定義

服務:可能分布在 Hadoop YARN 集群中部署的應用程式,或可從 Hadoop YARN 集群存取的應用程式。範例:Apache HBase、Apache hcatalog、Apache Storm。服務可能是短暫的或長期的。

服務類別:服務類型的名稱,用於註冊表中的路徑,並符合相容 DNS 的路徑命名原則。範例:org-apache-hbaseorg-apache-hcatalog

元件:服務的分布式元素。範例:HBase 主節點、HBase 區域伺服器和 HBase REST 伺服器。

服務執行個體:應用程式的單一執行個體。範例:HBase 集群 demo1。如果構成服務的元件執行個體正在執行,則服務執行個體正在執行。這並不表示在分布式運算的意義上是「運作中」,僅表示處理程序正在執行。

元件執行個體:服務執行個體中元件的單一執行個體。範例:主機 rack1server6 上的 HBase 主節點或主機 rack3server40 上的區域伺服器。

端點:與服務執行個體或元件執行個體建立繫結的一種方式。範例:HBase 的 Apache Zookeeper 繫結、區域伺服器上的 Java JMX 連接埠、HBase 主控站上的 Web UI,以及 HBase REST 元件執行個體的 REST API。端點可能是內部的,供服務執行個體內部使用,或外部的,供服務執行個體的用戶端使用。

服務記錄:註冊表中描述服務執行個體或元件執行個體的記錄,包括列出其端點。

YARN 資源管理員,「RM」:允許用戶端應用程式將工作(包括部署服務執行個體的要求)提交至 YARN 集群的 YARN 元件。RM 保留所有正在執行的應用程式的狀態。

YARN 應用程式:透過 YARN 部署的應用程式。每個應用程式執行個體都有唯一的應用程式 ID。

YARN 應用程式主控站,「AM」:由 RM 排程和部署的特定應用程式元件。它有責任維護應用程式的內部狀態,包括要求和管理此應用程式執行個體的所有其他元件執行個體。YARN RM 會偵測 AM 的故障,並重新排程作為回應。

YARN 容器:元件執行個體的資源配置,包括 CPU 和 RAM。AM 有責任要求其元件需要的容器,並建立命令將其元件執行個體實例化到配置的容器上。每個配置的容器都有唯一的容器 ID。

繫結問題

Hadoop YARN 允許應用程式在 Hadoop 群集上執行。其中有些是批次作業或查詢,可以使用 YARN 現有的 API,使用其應用程式 ID 來管理。此外,YARN 可以部署長駐服務實例,例如 Apache Tomcat 網路伺服器或 Apache HBase 群集。YARN 會根據每個元件需求和伺服器可用性,在群集上部署這些服務實例。客戶端需要發現這些服務實例;傳統上,其 IP 會註冊在 DNS 或某些組態檔中,但這在 YARN 部署的應用程式中不可行,因為主機名稱和網路埠無法事先得知。

因此,客戶端沒有簡單的方法可以與動態部署的應用程式互動。

YARN 支援一個基礎登錄,允許 YARN 應用程式主控端註冊一個網路 URL 和一個 IPC 位址。但這對於我們的目的來說還不夠,因為它不允許註冊任何其他「端點」,例如 REST URL、zookeeper 路徑或應用程式主控端執行的作業端點。此外,可以註冊的資訊會對應到 YARN 應用程式實例,也就是一個唯一的實例 ID,每當 YARN 應用程式啟動時就會變更。這使得無法透過對命名服務的靜態參照來解析繫結資訊,甚至無法探查目前未運作的服務實例是否存在。

使用案例

服務名稱範例

核心 Hadoop 服務。

這些服務可以透過具有寫入 /services 路徑權限的帳戶進行靜態或動態部署,甚至可以註冊從 Hadoop 群集內部存取的遠端服務。

    /services/hdfs
    /services/yarn
    /services/oozie

屬於個別使用者的 YARN 部署服務。

    /users/joe/org-apache-hbase/demo1
    /users/joe/org-apache-hbase/demo1/components/regionserver1

註冊使用案例

  1. 未在 YARN 下執行的 Hadoop 核心服務(例如:HDFS)可以註冊以供發現。這可以由服務或管理工具來執行。

  2. 由 YARN 部署的長駐應用程式會自行註冊以供客戶端發現。註冊資料預計會比應用程式主控端更長久,甚至比服務實例的單一部署壽命更長。

  3. 服務的元件實例會自行註冊,並發布內部繫結資訊,例如 JMX 埠。

  4. YARN 部署的應用程式可以繫結到靜態和動態的依賴服務實例。範例:Tomcat 網路池繫結到動態 HBase 服務實例「/users/joe/services/hbase/demo1」。

  5. 元件實例使用登錄檔繫結到其應用程式主控項的內部端點,並定期對其進行心跳偵測。

不支援的註冊用例

  1. 短暫的 YARN 應用程式會自動註冊到登錄檔中,包括其所有容器。當作業終止時,會註銷。有許多容器的短暫應用程式會對登錄檔造成過大的負載。所有 YARN 應用程式都會獲得註冊的選項,但不會自動進行,而且必須建議應用程式作者不要註冊短暫的容器。

查詢用例

  1. 用戶端應用程式查詢動態部署的服務實例,其使用者、服務類別和實例名稱已知,例如 /users/joe/services/hbase/demo1,並擷取連線到服務所需的資訊

  2. 用戶端應用程式查詢靜態部署的 Hadoop 服務範例:/services/hdfs

  3. 應用程式主控項列舉所有註冊的元件實例,找出其列出的 JMX 連接埠,並初始化自己的網路使用者介面,提供連結到這些端點。

  4. 使用者連線到 /users/joe/services/hbase/demo1 的私人 HBase 服務實例。

  5. 使用者連線到 /services/hbase 的叢集 HBase 服務。

  6. 使用者查詢遠端 Hadoop 叢集的檔案系統繫結資訊,網址為 /net/cluster4/services/hdfs。註冊資訊包括遠端檔案系統的 webhdfs:// URL。

  7. 使用者列出其 HBase 服務實例

    ls /users/joe/services/hbase
    
  8. 使用者在叢集中找出所有 Hbase 服務

    find -endpointField.api=org.apache.hbase
    
  9. 未來可能:透過 DNS 查詢服務。

此登錄檔提案旨在透過提供一種方式讓應用程式註冊其服務端點,以及讓用戶端找到這些端點,來支援這些用例。

服務登錄檔的主要需求

允許動態註冊服務實例

  • YARN 部署的服務實例必須能夠註冊其繫結,並讓用戶端發現。

  • 核心 Hadoop 服務實例必須能夠註冊其服務端點。

  • 如果服務移動或 HA 發生故障,繫結必須能夠升級。

  • 服務執行個體必須能夠發布服務的各種端點:Web UI、RPC、REST、Zookeeper 等。此外,還必須能夠註冊憑證,而其他公開安全資訊可能會作為繫結的一部分發布。

登錄服務屬性

  • 登錄必須具備高度可用性。

  • 規模:大型叢集中的許多服務和許多用戶端。這將限制服務可以發布的資料量。

  • 普遍性:我們需要在每個 YARN 叢集中使用它,無論是實體、虛擬還是雲端。

  • 必須支援階層式名稱空間和名稱。命名慣例必須與 DNS 相符,以便我們在專案的後續階段有選項透過 DNS 協定存取名稱空間。

  • 登錄 API 語言/協定

  • 跨語言:獨立於任何語言;用戶端語言 != 服務

  • 用於讀取登錄資料的 REST API

存取控制

  • 所有人均可讀取存取權

  • 寫入受到限制,以避免佔用和偽冒。

遠端存取性:支援遠端存取,即使是在只能透過 Apache Knox 存取或在雲端環境中託管的叢集上。

非需求

  • 登錄不適用於即時偵測、領導者選舉或為應用程式本身執行其他「共識狀態共享」動作,除了可能在組件執行個體之間共享繫結資訊。

  • 登錄不適用於儲存任意應用程式狀態或發布組態資料,除了繫結資訊至服務及其組件提供的端點。此類使用會使登錄超載,並迅速達到 Zookeeper 允許的限制。

架構

我們建議使用基礎登錄服務,將字串名稱繫結到描述服務和組件執行個體的記錄。我們計畫使用 ZK 作為基礎名稱服務,因為它支援許多屬性,我們選擇 ZK 名稱空間的一部分作為服務登錄的根目錄(預設值:yarnRegistry)。

在這個基礎實作之上,我們建置我們的登錄服務 API 和 YARN 將用於其服務的命名慣例。登錄將由登錄 API 存取,而非直接透過 ZK 存取 - ZK 僅為實作選項(儘管未來不太可能變更)。

  1. 服務透過將路徑繫結到稱為服務記錄的值來註冊。路徑具有階層結構,並使用 / 作為根目錄和分隔符。

  2. 服務記錄會註冊為持續性 znode。這可確保在服務計畫或非計畫的中斷期間,記錄會持續存在,假設用戶端程式碼能承受暫時的中斷。

  3. 每個服務實例的服務記錄會列出該服務實例所匯出的各種通訊協定的端點。

  4. 對於每個通訊協定端點,它必須包含

    1. 通訊協定名稱,包括:Web、REST、IPC、zookeeper。(類型:字串)

    2. 位址:用於尋找此端點的特定詳細資料

    3. 位址類型。這是繫結字串的格式。(URL、ZK 路徑、主機名稱:埠對)。對於預先定義的通訊協定,我們將定義繫結字串的格式必須為何。範例:protocol==REST 表示繫結類型為 URLprotocol==IPC 繫結使用 host/port 位址類型。

    4. API。這是端點提供的 API,且與應用程式有關。範例:org.apache.hadoop.namenodeorg.apache.hadoop.webhdfs

  5. 端點可能是外部的(供服務本身以外的程式使用)和內部的(供服務實例內的元件連接)。它們會列在服務記錄的不同區段中,以區別它們。

  6. 核心服務將使用下列慣例註冊:/services/{servicename},例如 /services/hdfs

  7. YARN 服務應使用下列慣例註冊

    /users/{username}/{serviceclass}/{instancename}
    
  8. 元件實例應註冊在

    /users/{username}/{serviceclass}/{instancename}/components/{componentname}
    
  9. 每個遵循此慣例的使用者服務都必須有唯一的服務類別名稱,

  10. 每個元件實例都必須有對該服務實例而言唯一的名稱。對於 YARN 部署的應用程式,這可以從容器 ID 輕鬆衍生。

對唯一名稱的要求可確保服務實例或元件實例的路徑保證唯一,且特定服務類別的所有實例都可以透過列出服務類別路徑的所有子項來列舉。

登錄模型

服務條目必須是持續性的,由 YARN 和其他工具負責決定何時刪除服務條目。

路徑元素

所有路徑元素都必須符合 RFC1123 定義的主機名稱路徑中的小寫條目;正規表示式為

([a-z0-9]|([a-z0-9][a-z0-9\-]*[a-z0-9]))

此政策將確保如果登錄階層曾經由 DNS 服務匯出,所有服務類別和名稱都將有效。

使用者名稱會產生複雜性,因為平台可能允許使用者名稱包含空格、高 Unicode 和其他字元。此類路徑必須使用國際化 DNS 所使用的 punycode 慣例轉換為有效的 DNS 主機名稱條目。

服務記錄

服務記錄有一些基本資訊,以及可能為空的內部和外部端點清單。

服務記錄

服務記錄包含一些基本資訊和兩個端點清單:一個清單供服務使用者使用,一個清單供應用程式內部使用。

名稱 說明
類型:字串 永遠是:「JSONServiceRecord」
說明:字串 可供人閱讀的說明。
外部:端點清單 外部呼叫者的服務端點清單。
內部:端點清單 服務執行個體內部使用的服務端點清單。

類型欄位必須是 「JSONServiceRecord」。強制使用這個字串允許未來記錄類型在嘗試使用 JSON 剖析器剖析資料之前,快速拒絕沒有這個字串的位元組陣列。

YARN 持久政策

屬性 yarn:idyarn:persistence 指定哪些記錄和任何子項可以在關聯的 YARN 組件完成時刪除。

yarn:id 欄位定義要比對的應用程式、嘗試或容器 ID;yarn:persistence 屬性定義記錄清理的觸發器,並隱含地定義 yarn:id 欄位內容的類型。

這些屬性使用前綴「yarn:」來表示它們依賴 Hadoop 群集的 YARN 層來實作政策。如果註冊表要獨立執行(這完全有可能),所有記錄都會隱含地持續存在。

名稱 說明 `yarn:id` 欄位的內容
永久 記錄會持續存在,直到手動移除。 (未使用)
應用程式 在 id 欄位中定義的 YARN 應用程式終止時移除。 應用程式 ID
應用程式嘗試 當前的 YARN 應用程式嘗試完成時移除。 應用程式嘗試 ID
容器 ID 欄位中的 YARN 容器完成時移除 容器 ID

在應用程式、應用程式嘗試或容器終止時清理的政策需要 yarn:id 欄位與應用程式、嘗試或容器相符。如果設定錯誤的 ID,清理不會進行,而且如果設定為不同的應用程式或容器,將會根據該應用程式的生命週期進行清理。

端點

名稱 說明
api:URI 作為字串 在繫結結束時實作的 API
通訊協定:字串 通訊協定。範例:`http`、`https`、`hadoop-rpc`、`zookeeper`、`web`、`REST`、`SOAP`,...。
addressType:字串 繫結的格式
addresses:清單[字串對應的字串] 地址對應的清單

所有字串欄位都有大小限制,以勸阻服務在文字描述中隱藏複雜的 JSON 結構。

欄位 addressType:地址類型

addressType 欄位定義條目的字串格式。

擁有不同的類型是為了讓工具(例如網路瀏覽器)可以處理繫結字串,而不需要辨識通訊協定。

格式 繫結格式
uri uri:端點的 URI
hostname hostname:服務主機
inetaddress hostname:服務主機,port:服務埠
path path:一般的 unix 檔案系統路徑
zookeeper hostname:服務主機,port:服務埠,path:ZK 路徑

在 zookeeper 繫結中,每個項目都代表叢集中的單一節點,hostnameport 欄位定義 ZK 執行個體的主機名稱和它正在監聽的埠。path 欄位會列出 zookeeper 路徑供應用程式使用。例如,對於 HBase,這會參照包含 HBase 叢集相關資訊的 znode。

addresses 清單中所有地址元素的 path 都必須相同。這可確保任何單一地址都包含足夠的資訊以連線到叢集並連線到相關的 znode。

可以定義新的地址類型;如果是非標準的,請加上字元序列 "x-" 作為前綴。

欄位 api:API 識別碼

API 欄位必須包含 URI,用以識別端點的特定 API。這些 URI 必須對 API 而言是唯一的,以避免混淆。

建議使用下列策略來提供 API 的唯一 URI

  1. SOAP/WS-* 約定,使用定義服務的 WSDL 的 URL
  2. 定義 REST API 的 SVN/Git 主控文件的 URL
  3. classpath 架構,後面接著應用程式中類別或套件的路徑。
  4. 具有已產生 UUID 的 uuid 架構。

希望為常見 API 定義標準 API URI。本文檔中使用兩個此類非規範 API

  • http://:人類的網站
  • classpath:javax.management.jmx:支援 JMX 管理通訊協定(基於 RMI)的端點

服務條目範例

以下是部署 YARN 的 tomcat 應用程式的服務條目範例。

建立並註冊應用程式後,登錄檔如下所示

/users
  /devteam
   /org-apache-tomcat
     /test1
       /components
         /container-1408631738011-0001-01-000002
         /container-1408631738011-0001-01-000001

/users/devteam/org-apache-tomcat/tomcat-test 服務記錄描述整體應用程式。它會匯出 URL 到負載平衡器。

{
  "description" : "tomcat-based web application",
  "external" : [ {
    "api" : "http://internal.example.org/restapis/scheduler/20141026v1",
    "addressType" : "uri",
    "protocol" : "REST",
    "addresses" : [
     { "uri" : "http://loadbalancer/" },
     { "uri" : "http://loadbalancer2/" }
      ]
  } ],
  "internal" : [ ]
}

服務執行個體是由兩個元件執行個體組成,每個執行個體都以其轉換為 DNS 相容主機名的容器 ID 描述。這些條目標記為臨時。如果條目設定在容器內,則當該容器釋出或元件發生故障時,這些條目將自動移除。因此,其持續性政策宣告為「3」,容器。yarn:id 欄位識別容器,其完成將觸發刪除此條目

/users/devteam/org-apache-tomcat/test1/components/container-1408631738011-0001-01-000001

{
  "yarn:id" : "container_1408631738011_0001_01_000001",
  "yarn:persistence" : "container",
  "description" : "",
  "external" : [ {
    "api" : "http://internal.example.org/restapis/scheduler/20141026v1",
    "addressType" : "uri",
    "protocol" : "REST",
    "addresses" : [{ "uri" : "rack4server3:43572" }  ]
  } ],
  "internal" : [ {
    "api" : "classpath:javax.management.jmx",
    "addressType" : "host/port",
    "protocol" : "rmi",
    "addresses" : [ {
      "host" : "rack4server3",
      "port" : "48551"
    } ]
  } ]
}

元件執行個體會列出其端點:公用 REST API 作為外部端點,JMX 位址作為內部端點。

/users/devteam/org-apache-tomcat/test1/components/container-1408631738011-0001-01-000002

{
  "registrationTime" : 1408638082445,
  "yarn:id" : "container_1408631738011_0001_01_000002",
  "yarn:persistence" : "container",
  "description" : null,
  "external" : [ {
    "api" : "http://internal.example.org/restapis/scheduler/20141026v1",
    "addressType" : "uri",
    "protocol" : "REST",
    "addresses" : [ [ "http://rack1server28:35881" ] ]
  } ],
  "internal" : [ {
    "api" : "classpath:javax.management.jmx",
    "addressType" : "host/port",
    "protocol" : "rmi",
    "addresses" : [ {
      "host" : "rack1server28",
      "port" : "48551"
    } ]
  } ]
}

(假設的)負載平衡器可以使用這些資訊來列舉元件並建立元件執行個體清單,以將要求傳送給這些執行個體。類似地,管理應用程式可以列舉所有可用的元件執行個體及其 JMX 連接埠,然後連線到每個執行個體以收集效能指標。

登錄檔 API

以下是從 Java 應用程式看到的登錄檔 API。API 是 ZK 作業之上的薄層,基本上會建立路徑、讀取、寫入和更新條目,以及列舉子項。REST API 是在伺服器內部實作,並使用此相同 API 來實作其 REST API。

所列出的例外僅為可能例外的一小部分—介面僅列出具有特殊意義的例外。

所有寫入作業都必須假設它們與具有 Zookeeper 用戶端一致性檢視的登錄檔服務進行通訊;唯讀用戶端必須假設其檢視可能有些過時。

所有用戶端必須承認註冊表是一個共享資源,並且它可能會在動作序列中變更。

註冊表操作

public interface RegistryOperations extends Service {

  /**
   * Create a path.
   *
   * It is not an error if the path exists already, be it empty or not.
   *
   * The createParents flag also requests creating the parents.
   * As entries in the registry can hold data while still having
   * child entries, it is not an error if any of the parent path
   * elements have service records.
   *
   * @param path path to create
   * @param createParents also create the parents.
   * @throws PathNotFoundException parent path is not in the registry.
   * @throws InvalidPathnameException path name is invalid.
   * @throws IOException Any other IO Exception.
   * @return true if the path was created, false if it existed.
   */
  boolean mknode(String path, boolean createParents)
      throws PathNotFoundException,
      InvalidPathnameException,
      IOException;

  /**
   * Set a service record to an entry
   * @param path path to service record
   * @param record service record service record to create/update
   * @param createFlags creation flags
   * @throws PathNotFoundException the parent path does not exist
   * @throws FileAlreadyExistsException path exists but create flags
   * do not include "overwrite"
   * @throws InvalidPathnameException path name is invalid.
   * @throws IOException Any other IO Exception.
   */
  void bind(String path, ServiceRecord record, int createFlags)
      throws PathNotFoundException,
      FileAlreadyExistsException,
      InvalidPathnameException,
      IOException;

  /**
   * Resolve the record at a path
   * @param path path to service record
   * @return the record
   * @throws PathNotFoundException path is not in the registry.
   * @throws InvalidPathnameException the path is invalid.
   * @throws IOException Any other IO Exception
   */

  ServiceRecord resolve(String path) throws PathNotFoundException,
      InvalidPathnameException,
      IOException;

  /**
   * Get the status of a path
   * @param path path to query
   * @return the status of the path
   * @throws PathNotFoundException path is not in the registry.
   * @throws InvalidPathnameException the path is invalid.
   * @throws IOException Any other IO Exception
   */
  RegistryPathStatus stat(String path)
      throws PathNotFoundException,
      InvalidPathnameException,
      IOException;

  /**
   * Probe for a path existing.
   * This is equivalent to {@link #stat(String)} with
   * any failure downgraded to a
   * @param path path to query
   * @return true if the path was found
   * @throws IOException
   */
  boolean exists(String path) throws IOException;

 /**
   * List all entries under a registry path
   * @param path path to query
   * @return a possibly empty list of the full path names of
   * child entries
   * @throws PathNotFoundException
   * @throws InvalidPathnameException
   * @throws IOException
   */
   List<String> list(String path) throws
      PathNotFoundException,
      InvalidPathnameException,
      IOException;

  /**
   * Delete a path.
   *
   * If the operation returns without an error then the entry has been
   * deleted.
   * @param path path delete recursively
   * @param recursive recursive flag
   * @throws PathNotFoundException path is not in the registry.
   * @throws InvalidPathnameException the path is invalid.
   * @throws PathIsNotEmptyDirectoryException path has child entries, but
   * recursive is false.
   * @throws IOException Any other IO Exception
   *
   */
  void delete(String path, boolean recursive)
      throws PathNotFoundException,
      PathIsNotEmptyDirectoryException,
      InvalidPathnameException,
      IOException;

  /**
   * Add a new write access entry to be added to node permissions in all
   * future write operations of a session connected to a secure registry.
   *
   * This does not grant the session any more rights: if it lacked any write
   * access, it will still be unable to manipulate the registry.
   *
   * In an insecure cluster, this operation has no effect.
   * @param id ID to use
   * @param pass password
   * @return true if the accessor was added: that is, the registry connection
   * uses permissions to manage access
   * @throws IOException on any failure to build the digest
   */
  boolean addWriteAccessor(String id, String pass) throws IOException;

  /**
   * Clear all write accessors.
   *
   * At this point all standard permissions/ACLs are retained,
   * including any set on behalf of the user
   * Only  accessors added via {@link #addWriteAccessor(String, String)}
   * are removed.
   */
  public void clearWriteAccessors();
}

RegistryPathStatus

RegistryPathStatus 類別會摘要註冊表中節點的內容。

public class RegistryPathStatus {

  /**
   * Short path in the registry to this entry
   */
  public String path;

  /**
   * Timestamp
   */
  public long time;

  /**
   * Entry size in bytes, as returned by the storage infrastructure.
   * In zookeeper, even "empty" nodes have a non-zero size.
   */
  public long size;

  /**
   * Number of child nodes
   */
  public int children;
}

安全性

註冊表將允許服務實例只能註冊在它具有權限的路徑下。YARN 會為使用者建立具有適當權限的目錄,讓 YARN 部署的服務可以由使用者註冊。服務實例使用者帳戶。管理員也會建立具有適當權限的目錄(例如 /services)(核心 Hadoop 服務可以在其中註冊自己。

不會嘗試限制對註冊表資訊的讀取存取。服務會透過要求驗證和授權來保護不適當的用戶端存取。服務記錄中有一個 範圍 欄位,但這只是一個標記,表示「僅限內部 API」,而不是直接的安全限制。(這就是為什麼建議使用「內部」和「外部」,而不是「公開」和「私人」)。

理由:無論如何,都可以透過連接埠掃描來發現正在註冊的端點。讓所有內容都可供全世界讀取,讓 REST API 具有更簡單的存取模型,而且與 DNS 相符。

在安全的叢集中,ZK 令牌更新可能會成為長期服務的問題,如果他們的令牌過期,他們的會話可能會過期。此類令牌的更新不屬於 API 實作的一部分,我們可能需要新增一種方法來更新註冊表操作類別實例的令牌。

安全性政策摘要

在非 Kerberos Zookeeper 叢集中,不會實作任何安全性政策。

註冊表設計為在 由 Kerberos 管理的叢集中 安全。

  • 註冊表根授予「系統帳戶」完全權限:mapredhdfsyarn"rwcda";所有其他帳戶和匿名存取為唯讀。

  • /users/services/ 的權限也受到類似的限制

  • 安裝可能會延伸或變更這些系統帳戶。

  • 當屬於使用者的應用程式排程時,YARN 應為該使用者建立一個項目 /users/${username}

  • 這個節點將具有對系統的完全存取權;使用者具有存取權限:"crd"。也就是說,他們可以建立或刪除子節點,但不能寫入他們的家目錄,或變更其權限。

  • 想要寫入註冊表的應用程式必須使用 SASL 連線,透過 Zookeeper 進行驗證。

  • 在使用者路徑中建立節點的應用程式,必須在 ACL 清單中包含由網站指定的系統帳戶,並具有完全存取權。

  • 在使用者路徑中建立節點的應用程式,必須包含 ACL

  • 在使用者路徑中建立節點的應用程式,必須將自己的使用者身分宣告為 sasl:user@REALM 項目。

  • 在使用者路徑中建立節點的應用程式,可以新增額外的 digest: ACL 權杖,以便讓其服務能夠處理註冊表的區段,而不需要 Kerberos 憑證

摘要驅動的驗證避免了長駐應用程式中憑證更新的問題。當啟動時,可以將權杖傳遞給 YARN 應用程式,以連線至 ZK 服務。然後,它可以建立或更新項目,包括在它建立的節點權限中包含一個機密摘要 ACL。因此,即使憑證過期,它仍保留一些存取權。

請注意,為了成功執行此操作,用戶端將需要回溯至使用 SASL 的階段,而是使用驗證 ID:傳遞憑證。

叢集外和叢集間存取

  1. 用戶端應該能夠存取其他叢集的註冊表,以便存取該叢集的服務。此需求的詳細資訊需要進一步說明。

  2. Apache Knox 等防火牆服務可以檢查已發布服務的內部集合,並發布其端點的子集合。它們可能會實作未來的 REST API。

限制

項目大小

Zookeeper 的預設限制為 1MB/節點。如果服務或元件的所有端點都儲存在附加至該節點的 JSON 中,則所有端點註冊資料的總限制為 1MB。

為了防止這成為問題,用戶端 API 應該對欄位的最大長度實作嚴格限制,對 addressType、protocol 和 api 欄位實作較低的限制,對 description 和 addresses 元素實作較長的限制,並對 addresses 欄位中的元素數量實作限制。

名稱大小

為了在未來支援 DNS,所有路徑元素必須限制在 63 個位元組內。對於非 ASCII 使用者名稱,此限制表示較短的路徑可能會是一個限制。

更新速率

在 ZK 叢集中,快速的項目變更速率被視為反社會行為。實作可能會限制更新作業。

輪詢速率

輪詢註冊表的用戶端可能會受到限制。

完整的服務記錄範例

以下是從 YARN 應用程式擷取的服務記錄範例(非規範性)。

{
  "type" : "JSONServiceRecord",
  "description" : "Slider Application Master",
  "yarn:persistence" : "application",
  "yarn:id" : "application_1414052463672_0028",
  "external" : [ {
    "api" : "classpath:org.apache.slider.appmaster",
    "addressType" : "host/port",
    "protocol" : "hadoop/IPC",
    "addresses" : [ {
      "port" : "48551",
      "host" : "nn.example.com"
    } ]
  }, {
    "api" : "http://",
    "addressType" : "uri",
    "protocol" : "web",
    "addresses" : [ {
      "uri" : "http://nn.example.com:40743"
    } ]
  }, {
    "api" : "classpath:org.apache.slider.management",
    "addressType" : "uri",
    "protocol" : "REST",
    "addresses" : [ {
      "uri" : "http://nn.example.com:40743/ws/v1/slider/mgmt"
    } ]
  }, {
    "api" : "classpath:org.apache.slider.publisher",
    "addressType" : "uri",
    "protocol" : "REST",
    "addresses" : [ {
      "uri" : "http://nn.example.com:40743/ws/v1/slider/publisher"
    } ]
  }, {
    "api" : "classpath:org.apache.slider.registry",
    "addressType" : "uri",
    "protocol" : "REST",
    "addresses" : [ {
      "uri" : "http://nn.example.com:40743/ws/v1/slider/registry"
    } ]
  }, {
    "api" : "classpath:org.apache.slider.publisher.configurations",
    "addressType" : "uri",
    "protocol" : "REST",
    "addresses" : [ {
      "uri" : "http://nn.example.com:40743/ws/v1/slider/publisher/slider"
    } ]
  }, {
    "api" : "classpath:org.apache.slider.publisher.exports",
    "addressType" : "uri",
    "protocol" : "REST",
    "addresses" : [ {
      "uri" : "http://nn.example.com:40743/ws/v1/slider/publisher/exports"
    } ]
  } ],
  "internal" : [ {
    "api" : "classpath:org.apache.slider.agents.secure",
    "addressType" : "uri",
    "protocol" : "REST",
    "addresses" : [ {
      "uri" : "https://nn.example.com:52705/ws/v1/slider/agents"
    } ]
  }, {
    "api" : "classpath:org.apache.slider.agents.oneway",
    "addressType" : "uri",
    "protocol" : "REST",
    "addresses" : [ {
      "uri" : "https://nn.example.com:33425/ws/v1/slider/agents"
    } ]
  } ]
}

它發布了許多端點,包括內部和外部端點。

外部

  1. 用於客戶端-AM 通訊的 IPC 主機名稱和埠
  2. AM 的 Web UI 的 URL
  3. Web UI 下針對特定應用程式服務的一系列 REST URL。詳細資訊無關緊要,請注意它們使用特定於應用程式的 API 值來確保唯一性。

內部

  1. AM 提供的兩個 REST API URL,供應用程式本身部署的容器使用。

在容器中執行的 Python 代理程式會擷取內部端點 URL,以與其 AM 通訊。記錄會在容器啟動時解析,並快取直到發生通訊問題。在那個時間點,會查詢登錄以取得目前的記錄,然後嘗試重新連線到 AM。

這裡的「連線」問題是指「低階 socket/IO 錯誤」和「HTTPS 驗證失敗」。代理程式使用雙向 HTTPS 驗證,如果 AM 失敗,而另一個應用程式開始在同一個埠上監聽,它會觸發驗證失敗,因此會重新讀取服務記錄。