

# 高级配置：在多个用户之间共享开发终端节点
<a name="dev-endpoint-sharing"></a>

本节介绍如何在典型使用案例中将开发终端节点与 SageMaker 笔记本结合使用，以在多个用户之间共享开发终端节点。

## 单一租户配置
<a name="dev-endpoint-sharing-sharing-single"></a>

在单一租户使用案例中，为了简化开发人员体验并避免争用资源，建议您让每个开发人员针对他们正在处理的项目使用自己的开发终端节点。这也简化了与工作线程类型和 DPU 计数相关的决策，让它们由开发人员和他们正在处理的项目自行决定。

除非同时运行多个笔记本文件，否则无需处理资源分配。如果您同时在多个笔记本文件中运行代码，将同时启动多个 Livy 会话。要隔离 Spark 集群配置以便同时运行多个 Livy 会话，您可以按照多租户使用案例中引入的步骤进行操作。

例如，如果您的开发终端节点有 10 个工作线程，并且工作线程类型为 ` G.1X`，那么您将有 9 个 Spark 执行程序，整个集群将有 90G 的执行程序内存，因为每个执行程序都有 10G 的内存。

无论指定的工作线程类型如何，都将打开 Spark 动态资源分配。如果数据集足够大，Spark 可能会将所有执行程序分配给单个 Livy 会话，因为默认情况下 `spark.dynamicAllocation.maxExecutors` 未设置。这意味着同一开发端点上的其他 Livy 会话将等待启动新的执行程序。如果数据集很小，Spark 将能够同时将执行程序分配给多个 Livy 会话。

**注意**  
有关如何在不同使用案例中分配资源，以及如何设置配置以修改行为的详细信息，请参阅 [高级配置：在多个用户之间共享开发终端节点](#dev-endpoint-sharing)。

### 多租户配置
<a name="dev-endpoint-sharing-sharing-multi"></a>

**注意**  
请注意，开发终端节点旨在模拟 AWS Glue ETL 环境作为单一租户环境。虽然多租户使用是可能的，但这是一个高级使用案例，建议大多数用户为每个开发终端节点维护单一租户模式。

在多租户使用案例中，您可能需要处理资源分配问题。关键因素是同时使用 Jupyter notebook 的并发用户的数量。如果您的团队在“follow-the-sun”工作流中工作，并且每个时区只有一个 Jupyter 用户，则并发用户的数量只有一个，因此您无需担心资源分配。但是，如果您的笔记本在多个用户之间共享，并且每个用户都以临时的方式提交代码，那么您需要考虑以下几点。

要在多个用户之间分区 Spark 集群资源，您可以使用 SparkMagic 配置。可以使用两种不同的方法来配置 SparkMagic。

#### （A）使用 %%configure -f 指令
<a name="dev-endpoint-sharing-sharing-multi-a"></a>

如果要从笔记本中修改每个 Livy 会话的配置，可以在笔记本段落上运行 `%%configure -f` 指令。

例如，如果您要在 5 个执行程序上运行 Spark 应用程序，可以对笔记本段落运行以下命令。

```
%%configure -f
{"numExecutors":5}
```

然后，您将在 Spark UI 上看到只有 5 个执行程序正在运行此任务。

我们建议限制动态资源分配的最大执行程序数量。

```
%%configure -f
{"conf":{"spark.dynamicAllocation.maxExecutors":"5"}}
```

#### （B）修改 SparkMagic config 文件
<a name="dev-endpoint-sharing-sharing-multi-b"></a>

SparkMagic 基于 [Livy API](https://livy.incubator.apache.org/docs/latest/rest-api.html) 工作。SparkMagic 使用配置（如 `driverMemory`、` driverCores`、`executorMemory`、`executorCores`、` numExecutors`、`conf` 等）创建 Livy 会话。这些是决定整个 Spark 集群消耗多少资源的关键因素。SparkMagic 允许您提供一个配置文件来指定那些被发送到 Livy 的参数。您可以在此 [GitHub 存储库](https://github.com/jupyter-incubator/sparkmagic/blob/master/sparkmagic/example_config.json)中看到一个示例配置文件。

如果要从笔记本修改所有 Livy 会话的配置，可以修改 `/home/ec2-user/.sparkmagic/config.json` 以添加 `session_config`。

要修改 SageMaker 笔记本实例上的配置文件，可以执行以下步骤。

1. 打开 SageMaker 笔记本。

1. 打开终端内核。

1. 运行以下 命令：

   ```
   sh-4.2$ cd .sparkmagic
   sh-4.2$ ls
   config.json logs
   sh-4.2$ sudo vim config.json
   ```

   例如，您可以将以下行添加到 ` /home/ec2-user/.sparkmagic/config.json` 并从笔记本重新启动 Jupyter 内核。

   ```
     "session_configs": {
       "conf": {
         "spark.dynamicAllocation.maxExecutors":"5"
       }
     },
   ```

### 指南和最佳实践
<a name="dev-endpoint-sharing-sharing-guidelines"></a>

为了避免这种资源冲突，可以使用以下基本方法：
+ 具有更大的 Spark 集群，方法是增加 `NumberOfWorkers`（水平扩展）并升级 `workerType`（垂直扩展）
+ 每个用户分配更少的资源（每个 Livy 会话分配更少的资源）

您的方法将取决于您的使用案例。如果您拥有较大的开发终端节点，并且没有大量数据，则资源冲突的可能性将显著降低，因为 Spark 可以根据动态分配策略分配资源。

如上所述，可以基于 DPU（或 `NumberOfWorkers`）和工作线重型类型的组合自动计算 Spark 执行程序的数量。每个 Spark 应用程序都会启动一个驱动程序和多个执行程序。要进行计算，您将需要 ` NumberOfWorkers` = `NumberOfExecutors + 1`。下面的矩阵根据并发用户的数量说明了您的开发终端节点需要多少容量。


****  

| 并发笔记本用户数 | 要为每个用户分配的 Spark 执行程序数量 | 您的开发端点的 NumberOfWorkers 总数 | 
| --- | --- | --- | 
| 3 | 5 | 18 | 
| 10 | 5 | 60 | 
| 50 | 5 | 300 | 

如果要为每个用户分配更少的资源，则 ` spark.dynamicAllocation.maxExecutors`（或 `numExecutors`）将是配置为 Livy 会话参数的最简单参数。如果在 `/home/ec2-user/.sparkmagic/config.json` 中设置以下配置，那么 SparkMagic 将为每个 Livy 会话分配最多 5 个执行程序。这将有助于隔离每个 Livy 会话的资源。

```
"session_configs": {
    "conf": {
      "spark.dynamicAllocation.maxExecutors":"5"
    }
  },
```

假设有一个具有 18 个工作线程（G.1X）的开发端点，并且同时有 3 个并发笔记本用户。如果您的会话配置具有 ` spark.dynamicAllocation.maxExecutors=5`，那么每个用户可以使用 1 个驱动程序和 5 个执行程序。即使您同时运行多个笔记本段落，也不会发生任何资源冲突。

#### 权衡措施
<a name="dev-endpoint-sharing-sharing-multi-tradeoffs"></a>

使用此会话配置 `"spark.dynamicAllocation.maxExecutors":"5"`，您将能够避免资源冲突错误，并且在存在并发用户访问时不需要等待资源分配。但是，即使有许多可用资源（例如，没有其他并发用户），Spark 也不能为您的 Livy 会话分配 5 个以上的执行程序。

#### 其他说明
<a name="dev-endpoint-sharing-sharing-multi-notes"></a>

停止使用笔记本时，最好停止 Jupyter 内核。这将释放资源，其他笔记本用户可以立即使用这些资源，而无需等待内核过期（自动关闭）。

### 常见问题
<a name="dev-endpoint-sharing-sharing-issues"></a>

即使遵循指南，您也可能会遇到某些问题。

#### 未找到会话
<a name="dev-endpoint-sharing-sharing-issues-session"></a>

当您尝试运行笔记本段落时，即使您的 Livy 会话已经终止，也将看到以下消息。要激活 Livy 会话，您需要重启 Jupyter 内核，方法是在 Jupyter 菜单中，选择 **Kernel (内核)** > **Restart (重新启动)**，然后再次运行笔记本段落。

```
An error was encountered:
Invalid status code '404' from http://localhost:8998/sessions/13 with error payload: "Session '13' not found."
```

#### YARN 资源不足
<a name="dev-endpoint-sharing-sharing-issues-yarn-resources"></a>

当您尝试运行笔记本段落，即使您的 Spark 集群没有足够的资源来启动新的 Livy 会话，您也将看到以下消息。您通常可以通过遵循指南来避免此问题，但是，您可能会遇到此问题。要解决此问题，你可以检查是否有任何不需要的活跃 Livy 会话。如果存在不需要的 Livy 会话，则需要终止这些会话才能释放集群资源。有关详细信息，请参阅下一节。

```
Warning: The Spark session does not have enough YARN resources to start. 
The code failed because of a fatal error:
    Session 16 did not start up in 60 seconds..

Some things to try:
a) Make sure Spark has enough available resources for Jupyter to create a Spark context.
b) Contact your Jupyter administrator to make sure the Spark magics library is configured correctly.
c) Restart the kernel.
```

### 监控和调试
<a name="dev-endpoint-sharing-sharing-debugging"></a>

本节介绍监控资源和会话的技术。

#### 监控和调试集群资源分配
<a name="dev-endpoint-sharing-sharing-debugging-a"></a>

您可以观看 Spark UI 如何监控每个 Livy 会话分配的资源数量，以及任务上的有效 Spark 配置内容。要激活 Spark UI，请参阅[为开发终端节点启用 Apache Spark Web UI](https://docs.aws.amazon.com/glue/latest/dg/monitor-spark-ui-dev-endpoints.html)。

（可选）如果需要实时查看 Spark UI，可以针对 Spark 集群上运行的 Spark 历史记录服务器配置 SSH 隧道。

```
ssh -i <private-key.pem> -N -L 8157:<development endpoint public address>:18080 glue@<development endpoint public address>
```

然后您可以在浏览器中打开 http://localhost:8157 以查看 Spark UI。

#### 免费的不需要的 Livy 会话
<a name="dev-endpoint-sharing-sharing-debugging-b"></a>

查看这些过程以关闭笔记本或 Spark 集群中的任何不需要的 Livy 会话。

**（a）。从笔记本终止 Livy 会话**  
您可以关闭 Jupyter notebook 上的内核以终止不需要的 Livy 会话。

**（b）。从 Spark 集群终止 Livy 会话**  
如果仍在运行不需要的 Livy 会话，您可以关闭 Spark 集群上的 Livy 会话。

作为执行此过程的先决条件，您需要为开发终端节点配置 SSH 公钥。

要登录到 Spark 集群，您可以运行以下命令：

```
$ ssh -i <private-key.pem> glue@<development endpoint public address>
```

您可以运行以下命令以查看活跃的 Livy 会话：

```
$ yarn application -list
20/09/25 06:22:21 INFO client.RMProxy: Connecting to ResourceManager at ip-255-1-106-206.ec2.internal/172.38.106.206:8032
Total number of applications (application-types: [] and states: [SUBMITTED, ACCEPTED, RUNNING]):2
Application-Id Application-Name Application-Type User Queue State Final-State Progress Tracking-URL
application_1601003432160_0005 livy-session-4 SPARK livy default RUNNING UNDEFINED 10% http://ip-255-1-4-130.ec2.internal:41867
application_1601003432160_0004 livy-session-3 SPARK livy default RUNNING UNDEFINED 10% http://ip-255-1-179-185.ec2.internal:33727
```

然后，您可以使用以下命令关闭 Livy 会话：

```
$ yarn application -kill application_1601003432160_0005
20/09/25 06:23:38 INFO client.RMProxy: Connecting to ResourceManager at ip-255-1-106-206.ec2.internal/255.1.106.206:8032
Killing application application_1601003432160_0005
20/09/25 06:23:39 INFO impl.YarnClientImpl: Killed application application_1601003432160_0005
```