# 服务器浏览器

快速开始使用 Server Browser，并探索适用于各种游戏类型的示例场景。

Server Browser 是一种托管服务，适用于 [部署](/zh/learn/bian-pai/deployments.md#match-bound) 和 [持久化](/zh/learn/bian-pai/chi-jiu-hua.md) 服务器：

* **帮助玩家搜索并加入合适的服务器** ，基于容量、延迟或游戏参数；
* **预热新服务器** 以便大规模服务全球玩家并避免令人沮丧的排队；
* **简化服务器运维** 包括更新、重启、持久化、网格化等。

{% hint style="success" %}
如果你想基于严格规则匹配玩家，而不允许选择服务器，可以考虑 [匹配](/zh/learn/pi-pei.md).
{% endhint %}

## ✔️ 准备

### 功能与流程

<figure><img src="/files/f0ec3b2982968b574e907b650e12ae4068dce02b" alt=""><figcaption><p>Server Browser：流程与层级</p></figcaption></figure>

Server Browser 提供两项主要功能：

[#start-browsing](#start-browsing "mention") 与游戏客户端一起：

* 发现并找到合适的服务器实例，查看槽位，并保留可用容量。
* 在实例槽位中保留座位，获取连接详情，并连接到服务器。
* 在部署中使用以下方式验证玩家连接 联合身份[^1].
* 更新实例槽位的可用容量和/或元数据，以修改发现条件。

[#automated-scaling](#automated-scaling "mention") （可选）与扩缩容策略一起：

* 监控可用的服务器实例、槽位、容量——按区域和/或其他条件。
* 部署服务器以通过预热或即时扩容来增加容量。
* 使用适用于演示、更新、测试、QA、锦标赛等的特殊策略自动化运维。

{% hint style="info" %}
发布后， **你的服务器浏览器需要 24/7 运行** 以确保全球玩家都能加入服务器。
{% endhint %}

## ▶️ 开始浏览

了解服务器/玩家生命周期及其职责，以确保高效使用服务器。

### 验证身份

Server Browser 会自动生成两种类型的令牌：

* **服务器令牌** - 这是以下操作所必需的： [服务器 API](#server-lifecycle) 方法，可 [作为应用版本变量注入](/zh/learn/bian-pai/application-and-versions.md#injected-variables).
  * 可访问所有 API 方法，适合测试、DevOps 或自定义编排。
* **客户端令牌** - 这是以下操作所必需的： [监控 API 和座位预留 API](#player-lifecycle) 供游戏客户端使用。
  * 我们建议将此令牌存储在第三方密钥库中，以便更轻松地轮换令牌。

### 发现实例

{% hint style="warning" %}
**新建** [部署](/zh/learn/bian-pai/deployments.md) **必须创建一个新的实例** ，以在初始化时跟踪新增容量。
{% endhint %}

{% hint style="info" %}
查看 [#automated-scaling](#automated-scaling "mention") 以了解扩缩容策略并自动启动部署。
{% endhint %}

**所需信息** 每个服务器实例包括：

* 初始化实例时至少定义一个槽位，
* 服务器连接详情——URL、IP、端口信息和位置。

**可选的自定义元数据参数** 用于玩家筛选、排序和浏览；例如：

* 槽位信息——团队容量和特定团队的元数据（例如团队名称），
* 名称和标签——可自定义、唯一、易读且可搜索的标签；
* 兼容性数据——服务器版本或受支持的客户端版本；
* 延迟限定条件——城市和区域标识符，以及分配的 [Ping 信标](/zh/learn/bian-pai/ping-beacons.md) 详情；
* 游戏参数——关卡/场景/地图、游戏模式、难度、所用模组；
* 任何其他自定义参数，用于帮助玩家筛选并找到合适的服务器。

{% hint style="info" %}
上面的元数据参数只是示例，你可以根据需要定义任意数量的参数。
{% endhint %}

{% hint style="success" %}
要序列化嵌套对象，可以尝试在键中将其访问路径编码为 `“object.child.property”`.
{% endhint %}

服务器可以 **随时更新实例或槽位元数据** 以修改其可发现性条件。更新元数据时，必须提供所有已索引键的有效值（即使未修改）。

**服务器实例必须定期发送保活心跳** 以验证其持续可用性，并防止玩家加入崩溃或离线的服务器。若在配置的过期周期内未收到心跳，实例及任何待处理的座位预留将被自动删除。

{% hint style="info" %}
查看 [持久化](/zh/learn/bian-pai/chi-jiu-hua.md) 用于管理持久化世界状态，并 [应用与版本](/zh/learn/bian-pai/application-and-versions.md#active-caching) 用于更快的部署。
{% endhint %}

### 分配容量

实例和槽位容量可通过两种方式分配，可单独使用或组合使用：

* [#auto-assigned-reservation](#auto-assigned-reservation "mention") 选择通过特定扩缩容策略启动的服务器，
* [#search-and-browse](#search-and-browse "mention") 让玩家定义筛选条件并浏览可用服务器进行选择。

{% hint style="success" %}
我们建议先从 [#auto-assigned-reservation](#auto-assigned-reservation "mention") 开始，因为这是更简单的选项。
{% endhint %}

#### 自动分配预留

{% hint style="info" %}
如果你希望实现此功能，请 **自动选择服务器**，基于区域容量。
{% endhint %}

玩家可以仅提供玩家 ID 和扩缩容策略名称来创建自动分配的预留。Server Browser 将自动查找一个具有足够可加入容量的槽位实例并预留座位，立即返回实例连接详情。

如果没有适合此预留的实例槽位，响应：

* **状态码指示该策略是否正在扩容** 并将增加更多容量，
* **头部 `Retry-After`  指示重试前的等待时间（秒）**，如果可重试。

一旦预留完成，你可以跳到 [#connect-to-server](#connect-to-server "mention").

#### 搜索与浏览

{% hint style="info" %}
如果你希望实现此功能，请 **向用户显示服务器列表并允许自定义预留**.
{% endhint %}

玩家可以列出服务器实例并 [分页浏览结果](#pagination) 以找到他们想加入的服务器。

实例和槽位可使用内置参数或 [已索引元数据](#configuration):

<table><thead><tr><th width="400">属性</th><th width="140">数据类型</th><th width="105">实例</th><th width="105">槽位</th></tr></thead><tbody><tr><td><code>request_id</code></td><td><code>字符串</code></td><td>✅</td><td>❌</td></tr><tr><td><code>total_joinable_seats</code>, <code>total_available_seats</code></td><td><code>整数</code></td><td>✅</td><td>❌</td></tr><tr><td><code>name</code></td><td><code>字符串</code></td><td>❌</td><td>✅</td></tr><tr><td><code>available_seats</code>, <code>reserved_seats</code></td><td><code>整数</code></td><td>❌</td><td>✅</td></tr><tr><td><code>created_at</code>, <code>updated_at</code></td><td><code>字符串</code></td><td>✅</td><td>✅</td></tr><tr><td><code>metadata.{index}</code> （自定义）</td><td><code>字符串</code>, <code>整数</code>, <code>浮点数</code>, <code>布尔值</code></td><td>✅</td><td>✅</td></tr></tbody></table>

可用的筛选操作符取决于被筛选属性的数据类型：

<table><thead><tr><th width="125">参数</th><th width="135">操作符</th><th>示例筛选条件（基于简单示例）</th></tr></thead><tbody><tr><td><code>字符串</code></td><td><p><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  或 <a data-footnote-ref href="#user-content-fn-3"><code>ne</code></a> 或 </p><p><a data-footnote-ref href="#user-content-fn-4"><code>lt</code></a>  或 <a data-footnote-ref href="#user-content-fn-5"><code>le</code></a> 或 </p><p><a data-footnote-ref href="#user-content-fn-6"><code>gt</code></a>  或 <a data-footnote-ref href="#user-content-fn-7"><code>ge</code></a>  或<br><code>包含</code></p></td><td><pre><code>?$filter=metadata.custom_name contains 'my game'
and metadata.server_version le '1.1.0'
and metadata.server_version ge '1.0.0'
&#x26;$order=metadata.custom_name asc
</code></pre></td></tr><tr><td><code>整数</code>, <code>浮点数</code></td><td><p><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  或 <a data-footnote-ref href="#user-content-fn-3"><code>ne</code></a> 或 </p><p><a data-footnote-ref href="#user-content-fn-4"><code>lt</code></a>  或 <a data-footnote-ref href="#user-content-fn-5"><code>le</code></a> 或 </p><p><a data-footnote-ref href="#user-content-fn-6"><code>gt</code></a>  或 <a data-footnote-ref href="#user-content-fn-7"><code>ge</code></a>  </p></td><td><pre><code>?$filter=metadata.xp_multiplier gt 1.0
&#x26;$order=metadata.xp_multiplier desc
</code></pre></td></tr><tr><td><code>布尔值</code></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  或 <a data-footnote-ref href="#user-content-fn-3"><code>ne</code></a></td><td><pre><code>?$filter=metadata.allows_new_connections eq true
</code></pre></td></tr></tbody></table>

{% hint style="success" %}
按区域和/或城市元数据进行筛选，以在测量服务器延迟前缩小选择范围。
{% endhint %}

{% hint style="info" %}
了解基于游标的 [#pagination](#pagination "mention") 分页，以便让用户获取更多结果。
{% endhint %}

#### 预留座位

在加入服务器之前，需要先进行座位预留，以确保该实例拥有足够的可用容量。预留可以包含一组玩家，也可以是单个玩家。

联合身份：玩家必须在预留中提供唯一的第三方玩家 ID。当他们发送相同的 ID 时， [#connect-to-server](#connect-to-server "mention") 服务器将可验证其身份。

一旦预留成功（[200 OK](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/200)），玩家应立即尝试连接。待处理的 **预留在 30 秒后过期（可配置），除非被** 你的服务器确认。

**超过槽位可加入座位容量的预留将被自动拒绝** ([409 Conflict](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/409)）。可加入座位是指尚未被其他玩家预留的所有可用座位。

{% hint style="info" %}
服务器可以强制更改任意槽位的容量，添加、删除或更新任意槽位。 **如果任何待处理预留超出新的槽位可用容量，则该槽位的所有预留都将被移除。**
{% endhint %}

### 连接到服务器

一旦玩家找到合适的实例，他们 **从中获取所需的连接详情** （URL 或 IP， [外部端口](/zh/learn/bian-pai/application-and-versions.md#port-mapping)）。座位预留一旦完成， **玩家即可连接到你部署的游戏服务器，并传递他们的玩家 ID**.

{% tabs %}
{% tab title="Unreal Engine" %}
要 **从 PIE（编辑器）连接** ，在开发和测试期间，按波浪号键 `~`  并输入 `open {URL}:{port}` 然后等待编辑器加载地图。

{% hint style="success" %}
如果连接失败或出现黑屏，请参阅我们的 [故障排除指南](/zh/unreal-engine.md#troubleshooting-and-faq-1).
{% endhint %}
{% endtab %}

{% tab title="Unity" %}
要 **连接你的 Unity 编辑器** 或 **游戏客户端** 到你的云部署，请输入：

* **部署** **URL** 指向服务器 IP，通常在 `NetworkManager`  组件中。
* **外部端口** 映射到 [服务器的内部监听端口](https://docs.edgegap.com/learn/advanced-features/application-and-versions#port-mapping)，通常在 Transport 组件中。

{% hint style="success" %}
如果出现连接超时或其他问题，请参阅我们的 [故障排除指南](/zh/unity.md#troubleshooting-and-faq-4).
{% endhint %}
{% endtab %}
{% endtabs %}

要验证新连接， **你的服务器必须发送批量预留确认** 请求，包含所有新玩家的 ID，并在确认响应中接收信息：

* 将已接受的玩家预留分配到其首选槽位，
* 将已过期的玩家预留分配到其首选槽位，
* 未知玩家 ID 列表。

你的 **服务器可以决定如何处理每一组玩家** 以及是否允许或踢出/封禁过期或被拒绝的用户。每个 **实例的槽位都必须立即更新为新的可用座位数量** 以确保未来的预留不会超过槽位容量。

### 放弃服务器

当玩家离开时，你的服务器必须增加分配给该槽位的可用座位容量。

{% hint style="success" %}
如果你的游戏设计允许重新连接时间窗口，服务器可以在更新槽位前等待。
{% endhint %}

阅读 [持久化](/zh/learn/bian-pai/chi-jiu-hua.md#recovery-objectives) 以防止令人沮丧的持久服务器回滚。

## 🚀 自动扩缩容

Server Browser 兼容多种不同的自动扩容方法：

* **预热方法** - 严格使用 Server Browser 扩缩容策略启动服务器，
* **即时方法** - 通过 [匹配](/zh/learn/pi-pei.md) 和 [使用 Server Browser 填充](#allocate-capacity),
* **自定义自动扩容器** - 通过自定义游戏后端和 [使用 Server Browser 填充](#allocate-capacity).

以下指南将重点介绍 **使用扩缩容策略进行预热** 作为主要方法。

{% hint style="success" %}
了解如何在 [Unreal Engine](/zh/unreal-engine.md#stop-deployments), [Unity](/zh/unity.md#stop-deployments)中停止部署，或 [使用 API](/zh/docs/api/zhuan-yong-fu-wu-qi.md#delete-v1-self-stop-request_id-access_point_id) 来可靠地管理生命周期。
{% endhint %}

### 监控容量

扩缩容策略会持续刷新你的服务器实例列表（已发现的部署），每隔 [`monitoring_interval`](#user-content-fn-8)[^8] 筛选语法 [，](#search-and-browse) 按区域、容量或其他条件。

你配置的 [`minimum_active_instances`](#user-content-fn-9)[^9]  数量可被视为以下其中之一：

* **固定容量** 即你希望始终保持运行的部署数量，
* **预热待机** 部署缓冲，以隐藏初始化延迟。

#### 固定容量

为以下游戏保持固定数量的活跃服务器： [持久化](/zh/learn/bian-pai/chi-jiu-hua.md)，尤其当此类游戏允许玩家预置 [持久化](/zh/learn/bian-pai/chi-jiu-hua.md#community-servers).

这种策略配置有时也用于质量保证、锦标赛、封闭 Alpha、发行商演示或其他有限容量的活动与运维。

{% hint style="info" %}
扩缩容策略可帮助你自动重启并即时循环回收崩溃的服务器。
{% endhint %}

#### 预热待机

如果满足以下条件，请在玩家需求到来之前提前启动服务器：

* 你正在推出重大版本，并预计玩家会在短时间内大量涌入，
* 或者服务器初始化需要超过 30 秒（不包括部署时间[^10]),
* 或者游戏实现了需要分层或环形网络依赖的网格策略。

### 部署服务器

当被监控的服务器实例数量*s* 低于配置的最小活跃实例数时，新部署将自动启动。所有部署请求会立即发出，并在每个监控间隔后无限重试，直到 [`deployment_registration_period`](#user-content-fn-8)[^8]  结束。

{% hint style="warning" %}
验证新部署是否 [执行自动发现并创建实例](#discover-instance) 正确匹配你的策略筛选条件，或者 **你的策略可能会无限循环并创建大量未使用的部署**!&#x20;
{% endhint %}

策略会以 [私有舰队](/zh/learn/bian-pai/si-you-jian-dui.md) （带溢出到云）或直接到云的方式启动部署。

可用参数包括（[参见 API 规范](/zh/docs/api/zhuan-yong-fu-wu-qi.md#private-fleets)):

* [**应用程序和版本**](/zh/learn/bian-pai/application-and-versions.md) - 构建版本、资源以及其他编排参数，
* **用户** - 一组单独的地理坐标，用于首选 [服务器放置](/zh/learn/bian-pai/deployments.md#regional-standby),
* [**私有主机 ID**](/zh/learn/bian-pai/si-you-jian-dui.md) - 云环境留空，或指定目标区域内的主机，
* [**标签**](/zh/learn/bian-pai/deployments.md#dashboard-monitoring) - 使用策略名称打标签，以便之后查找通过此策略启动的部署，
* [**环境变量**](/zh/learn/bian-pai/deployments.md#custom-variables) - 向服务器传递自定义参数和密钥，
* [**webhook**](/zh/learn/bian-pai/deployments.md#webhooks-and-postbacks) - 将部署生命周期事件通知你的游戏后端（或匹配器），
* [**需要缓存位置**](/zh/learn/bian-pai/application-and-versions.md#active-caching) - 如果你只希望在缓存位置获得更快的部署。

### 示例策略

按需测试并修改这些策略。大多数游戏会使用多个策略。

{% tabs %}
{% tab title="🍀 QA 池" %}
一个简单策略，始终保持一台服务器用于测试。

<pre class="language-json" data-title=""><code class="lang-json">{
  "name": "sb-qa-pool",
<strong>  <a data-footnote-ref href="#user-content-fn-11">"filter"</a>："metadata.policy_name eq 'sb-qa-pool'",
</strong>  "deployment_request": {
    "private_host_ids": [],
    "application": <a data-footnote-ref href="#user-content-fn-12">"my-game-server"</a>,
    "version": <a data-footnote-ref href="#user-content-fn-13">"2024.01.30-16.23.00-UTC"</a>,
    "users": [
      {
        "user_type": "geo_coordinates",
        "<a data-footnote-ref href="#user-content-fn-14">user_data</a>": {
<strong>          "latitude": 41.881832,
</strong><strong>          "longitude": -87.623177
</strong>        }
      }
    ],
<strong>    "tags": ["sb-qa-pool"],
</strong>    "environment_variables": [
      {
<strong>        "key": "SB_POLICY_NAME",
</strong><strong>        "value": "sb-qa-pool",
</strong>        "is_hidden": false
      }
    ]
  },
<strong>  "minimum_active_instances": 1
</strong>}
</code></pre>

{% endtab %}

{% tab title="🌡️ 预热" %}
在发布前启动 10 倍的部署，以应对需求。每个区域复制一份。

<pre class="language-json" data-title=""><code class="lang-json">{
  "name": "sb-v1.0.0-chicago",
<strong>  <a data-footnote-ref href="#user-content-fn-15">"filter"</a>："total_joinable_seats gt 0 and metadata.policy_name eq 'sb-v1.0.0-chicago'",
</strong>  "deployment_request": {
    "private_host_ids": [],
    "application": <a data-footnote-ref href="#user-content-fn-12">"my-game-server"</a>,
    "version": <a data-footnote-ref href="#user-content-fn-13">"2024.01.30-16.23.00-UTC"</a>,
    "users": [
      {
        "user_type": "geo_coordinates",
        "<a data-footnote-ref href="#user-content-fn-14">user_data</a>": {
<strong>          "latitude": 41.881832,
</strong><strong>          "longitude": -87.623177
</strong>        }
      }
    ],
<strong>    "tags": ["sb-v1.0.0-chicago"],
</strong>    "environment_variables": [
      {
<strong>        "key": "SB_POLICY_NAME",
</strong><strong>        "value": "sb-v1.0.0-chicago",
</strong>        "is_hidden": false
      }
    ]
  },
<strong>  <a data-footnote-ref href="#user-content-fn-16">"minimum_active_instances"</a>: 10
</strong>}
</code></pre>

{% endtab %}

{% tab title="🔒 MMO" %}
每个区域都会在可用容量低于阈值时增加部署。

<pre class="language-json" data-title=""><code class="lang-json">{
<strong>  "name": "sb-mmo-chicago",
</strong><strong>  <a data-footnote-ref href="#user-content-fn-17">"filter"</a>："total_joinable_seats gt 5 and metadata.policy_name eq 'sb-mmo-chicago'",
</strong>  "deployment_request": {
<strong>    <a data-footnote-ref href="#user-content-fn-18">"private_host_ids"</a>：[
</strong>    "application": <a data-footnote-ref href="#user-content-fn-12">"my-game-server"</a>,
    "version": <a data-footnote-ref href="#user-content-fn-13">"2024.01.30-16.23.00-UTC"</a>,
    "users": [
      {
        "user_type": "geo_coordinates",
        "<a data-footnote-ref href="#user-content-fn-14">user_data</a>": {
<strong>          "latitude": 41.881832,
</strong><strong>          "longitude": -87.623177
</strong>        }
      }
    ],
<strong>    "tags": ["sb-mmo-chicago"],
</strong>    "environment_variables": [
      {
<strong>        "key": "SB_POLICY_NAME",
</strong><strong>        "value": "sb-mmo-chicago",
</strong>        "is_hidden": false
      }
    ],
<strong>    <a data-footnote-ref href="#user-content-fn-19">"webhook_on_terminated"</a>: {
</strong>      "url": "https://my-webhook.com"
    }
  },
<strong>  "minimum_active_instances": 3
</strong>}
</code></pre>

{% endtab %}

{% tab title="🔑 社区" %}
每个服务器所有者一个策略，传递用于服务器认证的自定义密码。

<pre class="language-json" data-title=""><code class="lang-json">{
<strong>  "name": "sb-owner-jnjnc8mid",
</strong><strong>  <a data-footnote-ref href="#user-content-fn-20">"filter"</a>："metadata.policy_name eq 'sb-owner-jnjnc8mid'",
</strong>  "deployment_request": {
<strong>    <a data-footnote-ref href="#user-content-fn-18">"private_host_ids"</a>：[
</strong>    "application": <a data-footnote-ref href="#user-content-fn-12">"my-game-server"</a>,
    "version": <a data-footnote-ref href="#user-content-fn-13">"2024.01.30-16.23.00-UTC"</a>,
    "users": [
      {
        "user_type": "geo_coordinates",
        "<a data-footnote-ref href="#user-content-fn-14">user_data</a>": {
<strong>          "latitude": 41.881832,
</strong><strong>          "longitude": -87.623177
</strong>        }
      }
    ],
<strong>    "tags": ["community", "sb-owner-jnjnc8mid"],
</strong>    "environment_variables": [
      {
<strong>        "key": "SB_POLICY_NAME",
</strong><strong>        "value": "sb-owner-jnjnc8mid",
</strong>        "is_hidden": false
      },
      {
<strong>        "key": "SB_SERVER_PASSWORD",
</strong><strong>        "value": "password1234",
</strong>        "is_hidden": false
      }
    ],
<strong>    <a data-footnote-ref href="#user-content-fn-21">"webhook_on_ready"</a>: {
</strong>      "url": "https://my-webhook.com"
    },
<strong>    <a data-footnote-ref href="#user-content-fn-22">"webhook_on_error"</a>: {
</strong>      "url": "https://my-webhook.com"
    },
<strong>    <a data-footnote-ref href="#user-content-fn-19">"webhook_on_terminated"</a>: {
</strong>      "url": "https://my-webhook.com"
    }
  },
  "minimum_active_instances": 1
}
</code></pre>

{% endtab %}

{% tab title="❄️ 网格组" %}
每组服务器一个策略。游戏后端启动一个主节点，再由其生成副本。每个节点都会读取注入的网格组 ID，并搜索其他节点以建立网络连接。

<pre class="language-json" data-title=""><code class="lang-json">{
<strong>  "name": "sb-meshgroup-pqyt8sxcb",
</strong><strong>  <a data-footnote-ref href="#user-content-fn-11">"filter"</a>："metadata.policy_name eq 'sb-meshgroup-pqyt8sxcb'",
</strong>  "deployment_request": {
    "private_host_ids": [],
    "application": <a data-footnote-ref href="#user-content-fn-12">"my-game-server"</a>,
    "version": <a data-footnote-ref href="#user-content-fn-13">"2024.01.30-16.23.00-UTC"</a>,
    "users": [
      {
        "user_type": "geo_coordinates",
        "<a data-footnote-ref href="#user-content-fn-14">user_data</a>": {
<strong>          "latitude": 41.881832,
</strong><strong>          "longitude": -87.623177
</strong>        }
      }
    ],
<strong>    "tags": ["sb-meshgroup-pqyt8sxcb"],
</strong>    "environment_variables": [
      {
<strong>        "key": "SB_POLICY_NAME",
</strong><strong>        "value": "sb-meshgroup-pqyt8sxcb",
</strong>        "is_hidden": false
      },
      {
<strong>        "key": "SB_MESH_GROUP_ID",
</strong><strong>        "value": "pqyt8sxcb",
</strong>        "is_hidden": false
      }
    ],
<strong>    <a data-footnote-ref href="#user-content-fn-21">"webhook_on_ready"</a>: {
</strong>      "url": "https://my-webhook.com"
    },
<strong>    <a data-footnote-ref href="#user-content-fn-23">"webhook_on_terminated"</a>: {
</strong>      "url": "https://my-webhook.com"
    }
  },
<strong>  <a data-footnote-ref href="#user-content-fn-24">"minimum_active_instances"</a>: 9
</strong>}
</code></pre>

{% endtab %}
{% endtabs %}

## ⚙️ 配置

Server Browser API 由你在创建新的（或快速重启的）Server Browser 时指定的 JSON 配置生成。你可以指定服务器和槽位过期时间，以及自定义元数据：

{% tabs %}
{% tab title="🍀 简单示例" %}

<pre class="language-json" data-title="sb-simple-example-v1-0-0.json"><code class="lang-json">{
	"version": "1.0.0",
	"server_instances": {
		"expiration_period": "1m",
		"<a data-footnote-ref href="#user-content-fn-25">索引</a>": {
			"policy_name": "string",
			"name": "string"
		}
	},
	"server_instance_slots": {
		"<a data-footnote-ref href="#user-content-fn-25">索引</a>": {}
	},
	"seat_reservations": {
		"expiration_period": "30s"
	},
	"scaling_policies": {
		"monitoring_interval": "10s",
		"deployment_registration_period": "1m"
	}
}
</code></pre>

{% endtab %}

{% tab title="🎈 社交游戏" %}

<pre class="language-json" data-title="sb-social-example-v1-0-0.json"><code class="lang-json">{
	"version": "1.0.0",
	"server_instances": {
		"expiration_period": "15s",
		"<a data-footnote-ref href="#user-content-fn-25">索引</a>": {
			"policy_name": "string",
			"name": "string",
			"third_party_id": "string",
			"level": "string",
			"mode": "string",
			"difficulty": "string",
			"seed": "string",
			"max_players": "int",
			"app_version": "string",
			"location.city": "string"
		}
	},
	"server_instance_slots": {
		"<a data-footnote-ref href="#user-content-fn-25">索引</a>": {
			"third_party_id": "string",
			"max_players": "int",
			"avg_latency": "int",
			"player_ids": "string"
		}
	},
	"seat_reservations": {
		"expiration_period": "30s"
	},
	"scaling_policies": {
		"monitoring_interval": "10s",
		"deployment_registration_period": "30s"
	}
}
</code></pre>

{% endtab %}

{% tab title="🤝 合作游戏" %}

<pre class="language-json" data-title="sb-cooperative-example-v1-0-0.json"><code class="lang-json">{
	"version": "1.0.0",
	"server_instances": {
		"expiration_period": "15s",
		"<a data-footnote-ref href="#user-content-fn-25">索引</a>": {
			"policy_name": "string",
			"name": "string",
			"third_party_id": "string",
			"level": "string",
			"mode": "string",
			"difficulty": "string",
			"avg_rank": "int",
			"max_players": "int",
			"app_version": "string",
			"tags": "string",
			"match_id": "string",
			"location.city": "string"
		}
	},
	"server_instance_slots": {
		"<a data-footnote-ref href="#user-content-fn-25">索引</a>": {
			"third_party_id": "string",
			"max_players": "int",
			"player_ids": "string"
		}
	},
	"seat_reservations": {
		"expiration_period": "30s"
	},
	"scaling_policies": {
		"monitoring_interval": "10s",
		"deployment_registration_period": "30s"
	}
}
</code></pre>

{% endtab %}

{% tab title="⚔️ 竞技游戏" %}

<pre class="language-json" data-title="sb-competitive-example-v1-0-0.json"><code class="lang-json">{
	"version": "1.0.0",
	"server_instances": {
		"expiration_period": "15s",
		"<a data-footnote-ref href="#user-content-fn-25">索引</a>": {
			"policy_name": "string",
			"name": "string",
			"third_party_id": "string",
			"avg_rank": "int",
			"max_players": "int",
			"is_ranked": "bool",
			"app_version": "string",
			"cpu_frequency": "int",
			"match_id": "string",
			"location.city": "string"
		}
	},
	"server_instance_slots": {
		"<a data-footnote-ref href="#user-content-fn-25">索引</a>": {
			"third_party_id": "string",
			"max_players": "int",
			"avg_rank": "int",
			"avg_latency": "int"
		}
	},
	"seat_reservations": {
		"expiration_period": "30s"
	},
	"scaling_policies": {
		"monitoring_interval": "10s",
		"deployment_registration_period": "15s"
	}
}
</code></pre>

{% endtab %}
{% endtabs %}

{% hint style="info" %}
为获得最佳性能，请避免为未用于筛选或排序的元数据指定索引。非索引参数仍可通过服务器实例或槽位详情 API 方法设置和读取，参见 [#api](#api "mention").
{% endhint %}

## ☁️ 托管集群

Server Browser 由 Edgegap 以方便的方式全天候 24/7 托管和管理。

选择最适合你目标的托管选项：

### 私有集群层级

一键升级到私有集群，享受由 Edgegap 团队维护的高可用托管，以及面向公开发布游戏的 24/7 在线支持。

您的实例资源需求将取决于以下因素：

* **玩家数量** - 玩家越多，API 请求越多，
* **每位玩家的请求数** - 重试越快，服务负载越高，资源消耗越大，
* **服务器数量** - 服务器越多，存储的数据越多，API 请求越多，
* **客户端重试回退逻辑** - 使用带抖动的退避进行重试有助于分散流量突发峰值，
* **平均匹配时长** - 更短的会话需要更频繁地与服务器浏览器交互。

## 📗 API

**考虑使用我们的 SDK 来** [**Unreal Engine**](/zh/unreal-engine/developer-tools.md) **或** [**Unity**](/zh/unity/fu-wu-qi-liu-lan-qi.md) **以便通过预构建示例快速上手。**

游戏客户端和专用服务器在整个生命周期中都会向 Server Browser 发送 API 请求。

{% file src="/files/7d2c918178c58f8dedab23c3bb87a44a7fd8ae8a" %}

导入 API 规范到 [Scalar API Web 客户端](https://client.scalar.com/workspace/default/request/default) 或 [Swagger 编辑器](https://editor.swagger.io/) 以查看详细信息。

### 分页

**Server Browser 提供游标分页，以特定顺序逐步获取筛选后的数据。** 这种方法要求在获取更多结果时发送游标（起始点）和页面大小（响应项数量），这不同于传统的 limit-offset 分页。

{% hint style="info" %}
结合我们为游戏服务器元数据开发的专有数据库索引系统，游标分页为筛选高度动态的数据提供了快速、一致且灵活的用户体验。
{% endhint %}

我们的目标是让用户在第一页就找到合适的服务器。为获得最佳体验，我们建议显示之前页面的缓存结果，并且只在用户点击搜索时刷新结果。

## 🔖 更新日志

{% hint style="info" %}
**服务器浏览器的最新版本是 `1.0.0`** 。请留意 [更新和公告](/zh/docs/release-notes.md).
{% endhint %}

[^1]: 第三方玩家标识符

[^2]: 等于

[^3]: 不等于

[^4]: 小于

[^5]: 小于或等于

[^6]: 大于

[^7]: 大于或等于

[^8]: 重复一次，见配置。每个策略都需要使用与玩家查找实例时相同的

[^9]: 见示例策略

[^10]: 使用主动缓存可轻松缩短部署时间

[^11]: * 固定容量
    * 假设实例会通过注入变量在元数据中提供策略名称

[^12]: 替换为你自己的应用名称

[^13]: 替换为你自己的应用版本

[^14]: 芝加哥坐标

[^15]: * 当找到的可加入实例少于 10 个时进行部署
    * 假设实例会通过注入变量在元数据中提供策略名称

[^16]: 我们预计芝加哥区域至少有 10 个部署

[^17]: * 当找到少于 3 个、且每个具有 5 个或更少可加入座位的实例时进行部署
    * 假设实例会通过注入变量在元数据中提供策略名称

[^18]: 如果容量可用，则优先使用私有机群

[^19]: 当服务器重启时通知游戏后端

[^20]: * 不监控容量
    * 假设实例会通过注入变量在元数据中提供策略名称

[^21]: 准备就绪时通知游戏后端

[^22]: 当部署失败时通知游戏后端

[^23]: 当停止时通知游戏后端

[^24]: 3x3 网格 = 每个世界 9 台服务器

[^25]: 索引包含用于筛选或排序的自定义元数据参数


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.edgegap.com/zh/learn/fu-wu-qi-liu-lan-qi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
