<!-- review: finished -->

<a id="stream-upstream"></a>

# Upstream

提供用于描述服务器组的上下文,可在 [proxy_pass](https://cn.angie.software//angie/docs/configuration/modules/stream/stream_proxy.md#s-proxy-pass) 指令中使用。

<a id="configuration-example-73"></a>

## 配置示例

```nginx
upstream backend {
    hash $remote_addr consistent;
    zone backend 1m;

    server backend1.example.com:1935  weight=5;
    server unix:/tmp/backend3;
    server backend3.example.com       service=_example._tcp resolve;

    server backup1.example.com:1935   backup;
    server backup2.example.com:1935   backup;
}

resolver 127.0.0.53 status_zone=resolver;

server {
    listen 1936;
    proxy_pass backend;
}
```

<a id="directives-82"></a>

## 指令

<a id="index-0"></a>

<a id="s-u-upstream"></a>

### upstream

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `upstream` name { ... }   |
|--------------------------------------------------------------------------------------|---------------------------|
| 默认值                                                                                  | —                         |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | stream                    |

描述一个服务器组。服务器可以监听不同的端口。此外,监听 TCP 和 UNIX 域套接字的服务器可以混合使用。

示例:

```nginx
upstream backend {
    server backend1.example.com:1935 weight=5;
    server 127.0.0.1:1935            max_fails=3 fail_timeout=30s;
    server unix:/tmp/backend2;
    server backend3.example.com:1935 resolve;

    server backup1.example.com:1935  backup;
}
```

<a id="s-round-robin"></a>

默认情况下,连接使用加权轮询均衡方法在服务器之间分配。在上面的示例中,每 7 个连接将按如下方式分配:5 个连接到 backend1.example.com:1935,第二个和第三个服务器各 1 个连接。

如果在与服务器通信期间发生错误,连接将传递给下一个服务器,依此类推,直到尝试所有正常工作的服务器。如果与所有服务器的通信都失败,连接将被关闭。

<a id="index-1"></a>

<a id="s-u-server"></a>

### server

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `server` address [parameters];   |
|--------------------------------------------------------------------------------------|----------------------------------|
| 默认值                                                                                  | —                                |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | upstream                         |

定义服务器的地址和其他参数。地址可以指定为域名或带有必需端口的 IP 地址,或者指定为 `unix:` 前缀后的 UNIX 域套接字路径。解析为多个 IP 地址的域名会一次定义多个服务器。

可以定义以下参数:

| `weight=`number    | 设置服务器的权重;默认为 1。                                                                |
|--------------------|--------------------------------------------------------------------------------|
| `max_conns=`number | 限制到代理服务器的最大同时活动连接数。默认值为 `0`,表示没有限制。如果服务器组不在 [共享内存](#s-u-zone) 中,则该限制对每个工作进程生效。 |

<a id="s-max-fails"></a>

`max_fails=`number — 设置在 [fail_timeout](#s-fail-timeout) 设置的持续时间内
与服务器通信的失败尝试次数,
达到该次数后将服务器视为不可用;
然后在相同的持续时间后重试。

这里,失败尝试是指与服务器建立连接时的错误或超时。

#### NOTE
如果组中的 `server` 指令解析为多个服务器,
其 `max_fails` 设置将单独应用于每个服务器。

如果在解析所有 `server` 指令后,upstream 只包含一个服务器,
则 `max_fails` 设置无效并将被忽略。

| `max_fails=1`   | 默认尝试次数。   |
|-----------------|-----------|
| `max_fails=0`   | 禁用尝试次数统计。 |

<a id="s-fail-timeout"></a>

`fail_timeout=`time — 设置时间段,在此期间应发生指定次数的
与服务器通信失败尝试([max_fails](#s-max-fails))才将服务器视为不可用。
然后服务器在相同的时间段内保持不可用状态,
之后才会重试。

默认情况下,此值设置为 10 秒。

#### NOTE
如果组中的 `server` 指令解析为多个服务器,
其 `fail_timeout` 设置将单独应用于每个服务器。

如果在解析所有 `server` 指令后,upstream 只包含一个服务器,
则 `fail_timeout` 设置无效并将被忽略。

| `backup`      | 将服务器标记为备份服务器。当主服务器不可用时,它将接收请求。                                                       |
|---------------|--------------------------------------------------------------------------------------|
| `down`        | 将服务器标记为永久不可用。                                                                        |
| `drain` (PRO) | 将服务器标记为排空状态;这意味着<br/>它只接收来自之前通过 [sticky](#s-u-sticky) 绑定的会话的请求。<br/>否则其行为类似于 `down`。 |

#### WARNING
`backup` 参数不能与 [hash](#s-u-hash) 和 [random](#s-u-random) 负载均衡方法一起使用。

`down` 和 `drain` 参数互斥。

<a id="s-reresolve"></a>

| `resolve`      | 启用监控与域名对应的 IP 地址列表的变化,<br/>无需重新加载配置即可更新。<br/>该组必须位于<br/>[共享内存区域](#s-u-zone) 中;<br/>还必须定义 [resolver](https://cn.angie.software//angie/docs/configuration/modules/stream/index.md#s-resolver)。                                                                                                                                                                                                                                                                                                                                     |
|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `service=`name | 启用解析 DNS SRV 记录并设置服务名称。<br/>要使此参数生效,还必须指定 resolve 参数,<br/>且不在主机名中指定服务器端口。<br/><br/>如果服务名称中没有点,<br/>则根据 RFC 标准形成名称:<br/>服务名称前加 `_` 前缀,<br/>然后在点后添加 `_tcp`。<br/>因此,服务名称 `http` 将变成 `_http._tcp`。<br/><br/>Angie 通过组合规范化的服务名称和主机名来解析 SRV 记录,<br/>并通过 DNS 获取该组合的服务器列表,<br/>以及它们的优先级和权重。<br/><br/>- 最高优先级的 SRV 记录<br/>  (共享最小优先级值的记录)<br/>  解析为主服务器,<br/>  其他记录成为备份服务器。<br/>  如果 `server` 设置了 `backup`,<br/>  最高优先级的 SRV 记录解析为备份服务器,<br/>  其他记录被忽略。<br/>- 权重类似于 `server` 指令的 `weight` 参数。<br/>  如果指令和 SRV 记录都设置了权重,<br/>  则使用指令设置的权重。 |

此示例将查找 `_http._tcp.backend.example.com` 记录:

```nginx
server backend.example.com service=http resolve;
```

| `sid=`id   | 设置组中的服务器 ID。如果未指定该参数,<br/>ID 将设置为 IP 地址和端口或 UNIX 域套接字路径的<br/>十六进制 MD5 哈希值。   |
|------------|------------------------------------------------------------------------------|

<a id="s-slow-start"></a>

| `slow_start=`time   | 设置服务器在恢复服务时，<br/>使用 [轮询](https://cn.angie.software//angie/docs/configuration/modules/http/http_upstream.md#round-robin) 或 [least_conn](#s-u-least-conn)<br/>负载均衡方法恢复其权重的 [时间](https://cn.angie.software//angie/docs/configuration/configfile.md#syntax)。<br/><br/>如果设置了该参数，<br/>并且服务器在根据 [max_fails](#s-max-fails) 和 [upstream_probe (PRO)](https://cn.angie.software//angie/docs/configuration/modules/stream/stream_upstream_probe.md#s-u-upstream-probe) 判定失败后再次被认为健康，<br/>服务器将在指定的时间段内逐渐恢复其指定的权重。<br/><br/>如果未设置该参数，<br/>在类似情况下，<br/>服务器将立即以其指定的权重开始工作。   |
|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### NOTE
如果 upstream 中只指定了一个 `server`，
`slow_start` 将不起作用并被忽略。

<a id="index-2"></a>

<a id="s-u-state"></a>

### state (PRO)

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `state` file;   |
|--------------------------------------------------------------------------------------|-----------------|
| 默认值                                                                                  | —               |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | upstream        |

指定持久化存储上游服务器列表的 file。
从 [我们的软件包](https://cn.angie.software//angie/docs/installation/index.md#install-packages) 安装时，
会创建一个具有适当权限的专用目录
`/var/lib/angie/state/` （FreeBSD 上为 `/var/db/angie/state/`）
用于存储此类文件，
因此您只需在配置中添加文件名：

```nginx
upstream backend {

    zone backend 1m;
    state /var/lib/angie/state/<文件名>;
}
```

这里的服务器列表格式类似于 `server`。
每当通过配置 API 在
[/config/stream/upstreams/](https://cn.angie.software//angie/docs/configuration/modules/http/http_api.md#api-config-stream-upstreams-servers) 部分
修改服务器时，文件内容都会更改。
该文件在 Angie 启动或配置重载时读取。

#### WARNING
要在 `upstream` 块中使用 `state` 指令，
其中不应有 `server` 指令，
但需要共享内存区（[zone](#s-u-zone)）。

<a id="index-3"></a>

<a id="s-u-zone"></a>

### zone

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `zone` name [size];   |
|--------------------------------------------------------------------------------------|-----------------------|
| 默认值                                                                                  | —                     |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | upstream              |

定义共享内存区的名称和大小，该内存区存储组的配置和运行时状态，在工作进程之间共享。多个组可以使用同一个区。在这种情况下，只需指定一次大小即可。

#### NOTE
只有在配置的 `size` 不变时，重载才会保留区域内容。
任何大小变更——增大或减小——都会导致区域被重新创建为空。

<a id="index-4"></a>

<a id="s-u-backup-switch"></a>

### backup_switch (PRO)

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `backup_switch` `permanent`[=time];   |
|--------------------------------------------------------------------------------------|---------------------------------------|
| 默认值                                                                                  | —                                     |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | upstream                              |

该指令启用从  *活动* 组而不是主组开始服务器选择的能力，
即从之前成功找到服务器的组开始。
如果在活动组中无法为下一个请求找到服务器，
并且搜索移至备份组，
该备份组将成为活动组，
后续请求将首先定向到该组中的服务器。

如果定义了 `permanent` 参数但没有 [时间](https://cn.angie.software//angie/docs/configuration/configfile.md#syntax) 值，
该组在选择后保持活动状态，
不会自动重新检查优先级较低的组。
如果指定了 time，
组的活动状态在指定的时间间隔后过期，
负载均衡器将再次检查优先级较低的组，
如果服务器正常工作则返回到这些组。

示例：

```nginx
upstream media_backend {
    server primary1.example.com:1935;
    server primary2.example.com:1935;

    server reserve1.example.com:1935 backup;
    server reserve2.example.com:1935 backup;

    backup_switch permanent=2m;
}
```

如果负载均衡器从主服务器切换到备份组，
所有后续请求将由该备份组处理 2 分钟。
2 分钟过期后，负载均衡器重新检查主服务器，
如果它们正常工作，则再次使其成为活动组。

<a id="index-5"></a>

<a id="s-u-feedback"></a>

### feedback (PRO)

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `feedback` variable [`inverse`] [`factor=`number] [`account=`condition_variable];   |
|--------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
| 默认值                                                                                  | —                                                                                   |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | upstream                                                                            |

为 `upstream` 启用基于反馈的负载均衡机制。
它通过将每个代理服务器的权重乘以平均反馈值来动态调整负载均衡决策，
该值根据 variable 值随时间变化，
并受可选条件约束。

可以指定以下参数：

| variable   | 从中获取反馈值的变量。<br/>它应该表示性能或健康指标；<br/>假定由服务器提供。<br/><br/>该值在服务器的每个响应中进行评估，<br/>并根据 `inverse` 和 `factor` 设置<br/>纳入移动平均值。                                                                                                                                                                                                                                                                                                                      |
|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `inverse`  | 如果设置了该参数，反馈值将被反向解释：<br/>较低的值表示更好的性能。                                                                                                                                                                                                                                                                                                                                                                                                     |
| `factor`   | 计算平均值时反馈值的加权因子。<br/>有效值为 0 到 99 的整数。<br/>默认值为 `90`。<br/><br/>平均值使用 [指数平滑](https://en.wikipedia.org/wiki/Exponential_smoothing) 公式计算。<br/><br/>因子越大，新值对平均值的影响越小；<br/>如果指定 `90`，将取 90% 的先前值<br/>和仅 10% 的新值。                                                                                                                                                                                                                                |
| `account`  | 指定一个条件变量，<br/>用于控制如何在计算中统计连接。<br/>仅当条件变量<br/>不等于 `""` 或 `"0"` 时，<br/>才使用反馈值更新平均值。<br/><br/>#### NOTE<br/>默认情况下，来自 [探测](https://cn.angie.software//angie/docs/configuration/modules/stream/stream_upstream_probe.md#s-u-upstream-probe) 的流量<br/>不包含在计算中；<br/>将 [$upstream_probe](https://cn.angie.software//angie/docs/configuration/modules/http/http_upstream_probe.md#v-upstream-probe) 变量<br/>与 `account` 结合使用可以包含它们<br/>或甚至排除其他所有内容。 |

示例：

```nginx
upstream backend {

    zone backend 1m;

    feedback $feedback_value factor=80 account=$condition_value;

    server backend1.example.com:1935  weight=1;
    server backend2.example.com:1935  weight=2;
}

map $protocol $feedback_value {
    "TCP"                      100;
    "UDP"                      75;
    default                    10;
}

map $upstream_probe $condition_value {
    "high_priority" "1";
    "low_priority"  "0";
    default         "1";
}
```

此配置根据各个会话中使用的协议
按反馈级别对服务器进行分类，
并在 [$upstream_probe](https://cn.angie.software//angie/docs/configuration/modules/http/http_upstream_probe.md#v-upstream-probe) 上添加条件，
仅统计 `high_priority` 探测
或常规客户端会话。

<a id="index-6"></a>

<a id="s-u-hash"></a>

### hash

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `hash` key [`consistent`];   |
|--------------------------------------------------------------------------------------|------------------------------|
| 默认值                                                                                  | —                            |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | upstream                     |

为组指定负载均衡方法，其中客户端-服务器映射使用哈希键值确定。键可以包含文本、变量及其组合。请注意，从组中添加或删除任何服务器可能会导致大多数键重新映射到不同的服务器。该方法与 Perl [Cache::Memcached](https://metacpan.org/pod/Cache::Memcached) 库兼容。

使用示例：

```nginx
hash $remote_addr;
```

当使用解析为多个 IP 地址的域名时
（例如，使用 `resolve` 参数），
服务器不会对接收到的地址进行排序，因此它们的顺序可能在
不同服务器之间有所不同，这会影响客户端分布。
为确保一致的分布，
请使用 `consistent` 参数。

如果指定了 `consistent` 参数，将使用 ketama 一致性哈希方法代替上述方法。该方法确保当从组中添加或删除服务器时，只有最少数量的键会重新映射到其他服务器。将该方法用于缓存服务器可提供更高的缓存命中率。该方法与 Perl [Cache::Memcached::Fast](https://metacpan.org/pod/Cache::Memcached::Fast) 库兼容，其中 `ketama_points` 参数设置为 160。

<a id="index-7"></a>

<a id="s-u-least-conn"></a>

### least_conn

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `least_conn`;   |
|--------------------------------------------------------------------------------------|-----------------|
| 默认值                                                                                  | —               |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | upstream        |

为组指定负载均衡方法，其中连接传递给活动连接数最少的服务器，同时考虑服务器权重。如果有多个合适的服务器，则按照它们的权重以循环（轮询）方式选择它们。

<a id="index-8"></a>

<a id="s-u-least-time"></a>

### least_time (PRO)

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `least_time` `connect` | `first_byte` | `last_byte` [`factor=`number] [`account=`condition_variable];   |
|--------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
| 默认值                                                                                  | —                                                                                                       |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | upstream                                                                                                |

为组指定负载均衡方法，将连接传递给活动服务器的概率与其平均响应时间成反比；响应时间越低，服务器将接收到的连接就越多。

| `connect`    | 该指令考虑建立连接的平均时间。      |
|--------------|----------------------|
| `first_byte` | 该指令使用接收响应第一个字节的平均时间。 |
| `last_byte`  | 该指令使用接收完整响应的平均时间。    |

| `factor`   | 执行与 [response_time_factor (PRO)](#s-u-response-time-factor) 相同的功能，<br/>如果指定了该参数，则会覆盖它。                                                                                                                                                                                                                                                                                                                                           |
|------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `account`  | 指定一个条件变量，<br/>用于控制在计算中考虑哪些连接。<br/>仅当连接的条件变量<br/>不等于 `""` 或 `"0"` 时，<br/>才会更新平均值。<br/><br/>#### NOTE<br/>默认情况下，[探测](https://cn.angie.software//angie/docs/configuration/modules/stream/stream_upstream_probe.md#s-u-upstream-probe)<br/>不包含在计算中；<br/>将 [$upstream_probe](https://cn.angie.software//angie/docs/configuration/modules/http/http_upstream_probe.md#v-upstream-probe) 变量<br/>与 `account` 结合使用可以包含它们，<br/>甚至排除其他所有内容。 |

当前值在 API 的 [upstream 指标](https://cn.angie.software//angie/docs/configuration/modules/http/http_api.md#api-status-stream-upstreams) 中，
以服务器的 `health` 对象中的 `connect_time`、`first_byte_time`
和 `last_byte_time` 形式呈现。

<a id="index-9"></a>

<a id="s-u-random"></a>

### random

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `random` [`two`];   |
|--------------------------------------------------------------------------------------|---------------------|
| 默认值                                                                                  | —                   |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | upstream            |

为组指定负载均衡方法，将连接传递给随机选择的服务器，同时考虑服务器权重。

如果指定了可选的 `two` 参数，Angie 会随机选择两个服务器，然后使用指定的方法选择一个服务器。默认方法是 [least_conn](#s-u-least-conn)，它将连接传递给活动连接数最少的服务器。

<a id="index-10"></a>

<a id="s-u-response-time-factor"></a>

### response_time_factor (PRO)

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `response_time_factor` number;   |
|--------------------------------------------------------------------------------------|----------------------------------|
| 默认值                                                                                  | `response_time_factor 90;`       |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | upstream                         |

为 [least_time (PRO)](#s-u-least-time) 负载均衡方法指定在使用
[指数加权移动平均](https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average) 公式计算平均响应时间时，
**先前** 值的平滑因子。

指定的 number 越大，新值对平均值的影响就越小；如果
指定为 `90`，将采用 90% 的先前值，仅采用 10% 的
新值。有效值范围为 0 到 99（含）。

当前计算结果在 API 的 [upstream 指标](https://cn.angie.software//angie/docs/configuration/modules/http/http_api.md#api-status-stream-upstreams) 中，以服务器的 `health` 对象中的 `connect_time` （建立连接的时间）、`first_byte_time` （接收响应第一个字节的时间）和 `last_byte_time` （接收完整响应的时间）形式呈现。

#### NOTE
计算中仅考虑成功的响应；
什么构成不成功的响应
由 [proxy_next_upstream](https://cn.angie.software//angie/docs/configuration/modules/stream/stream_proxy.md#s-proxy-next-upstream) 指令确定。

<a id="index-11"></a>

<a id="s-u-sticky"></a>

### sticky

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `sticky route` value...;<br/><br/>`sticky learn` `zone=`zone `create=`$create_var1... `lookup=`$lookup_var1... [`connect`] [`norefresh`] [`timeout=`time];<br/><br/>`sticky learn` `lookup=`$lookup_var1... `remote_action=`uri `remote_result=`$remote_var [`remote_uri=`uri];   |
|--------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 默认值                                                                                  | —                                                                                                                                                                                                                                                                                 |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | upstream                                                                                                                                                                                                                                                                          |

根据第一个参数中指定的模式，
配置客户端与上游服务器之间的粘性会话。
要逐步将带有 `sticky` 的服务器退出轮换，
可以在 [server](#s-u-server) 块中使用 `drain` 选项（PRO）。

#### WARNING
`sticky` 指令必须出现在所有负载均衡方法指令之后，
否则将无法工作。

`route` 模式

此模式使用预定义的路由标识符，
这些标识符可以嵌入到 Angie 可访问的连接属性中。
它的灵活性较低，因为它依赖于预定义的值，
但如果已经在使用此类标识符，则更适合。

在这里，建立连接时，上游服务器
可以为客户端分配一个路由，并以双方
都知道的方式返回其标识符。
路由标识符
应使用 [server](#s-u-server) 指令的
[sid](#s-reresolve) 参数的值。
请注意，如果指定了 [sticky_secret](#s-u-sticky-secret) 指令，
该参数会被额外哈希处理。

希望使用此路由的客户端的后续连接
必须包含服务器颁发的标识符，并以这样的方式
使其最终出现在 Angie 变量中。

指令参数指定可能包含变量的字符串，
用于路由。要选择传入连接定向到的服务器，
使用第一个非空值；
然后将其与 [server](#s-u-server) 指令的
[sid](#s-reresolve) 参数进行比较。
如果服务器选择失败
或所选服务器无法接受连接，
将根据配置的负载均衡方法
选择另一台服务器。

这里 Angie 在 `$route` 变量中查找路由标识符，
该变量根据 [$ssl_preread_server_name](https://cn.angie.software//angie/docs/configuration/modules/stream/stream_ssl_preread.md#v-ssl-preread-server-name)
接收其值（注意必须启用 [ssl_preread](https://cn.angie.software//angie/docs/configuration/modules/stream/stream_ssl_preread.md#s-ssl-preread)）：

```nginx
stream {

    map $ssl_preread_server_name $route {

        a.example.com            a;
        b.example.com            b;
        default                  "";
    }

    upstream backend {

        server 127.0.0.1:8081 sid=a;
        server 127.0.0.1:8082 sid=b;

        sticky route $route;
    }

    server {

        listen 127.0.0.1:8080;

        ssl_preread on;

        proxy_pass backend;
    }
}
```

`learn` 模式（PRO）

在此模式下，使用动态生成的密钥
将客户端绑定到特定的上游服务器；
此模式更加灵活，
因为它动态分配服务器，
将会话存储在共享内存区域中，
并支持多种传递会话标识符的方式。

在这里，会话是基于
来自上游服务器的连接属性创建的。
`create` 和 `lookup` 参数列出了
指定如何创建新会话和查找现有会话的变量。
这两个参数都可以多次使用。

会话标识符是使用 `create` 指定的
第一个非空变量的值；
例如，这可以是
[上游服务器名称](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#v-server-name)。

会话存储在共享内存区域中；
其名称和大小由 `zone` 参数指定。
如果会话在 `timeout` 指定的 [时间](https://cn.angie.software//angie/docs/configuration/configfile.md#syntax) 内
未被访问，则会被删除。
默认值为 1 小时。

默认情况下，Angie 通过在每次使用会话时
更新最后访问时间戳来延长会话生命周期。
`norefresh` 参数改变了这种行为：
会话严格按超时时间过期，即使正在使用中。

希望使用会话的客户端的后续连接
必须包含其标识符。
`lookup` 参数使用指定的变量列表
在连接中搜索会话标识符，
在第一个非空变量处停止。
如果未找到任何内容，则该请求被视为新请求。
找到的标识符的值
与共享内存中的会话进行匹配。
如果服务器选择失败
或所选服务器无法处理连接，
将根据配置的负载均衡方法
选择另一台服务器。

`connect` 参数允许在与上游服务器
建立连接后立即创建会话。
如果没有它，会话仅在连接处理完成后创建。
（对于 UDP 连接，会话在服务器选择后立即创建。）

在示例中，Angie 使用 [$rdp_cookie](https://cn.angie.software//angie/docs/configuration/modules/stream/stream_rdp_preread.md#v-rdp-cookie) 变量
创建和查找会话：

```nginx
stream {

    upstream backend {

        server 127.0.0.1:3390;
        server 127.0.0.1:3391;

        sticky learn lookup=$rdp_cookie create=$rdp_cookie zone=sessions:1m;
    }

    server {

        listen 127.0.0.1:3389;

        rdp_preread on;

        proxy_pass backend;
    }
}
```

带 `remote_action` 的 `learn` 模式（PRO 1.10.0+）

`remote_action` 和 `remote_result` 参数
允许使用远程会话存储（PRO）
动态分配和管理会话标识符。

与带 `zone` 的 `learn` 模式不同，
此模式不在本地缓存会话，
而是为每个连接查询远程存储。

`remote_action` 参数必须指向
[client](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#client) 上下文中的 `location`。
`remote_uri` 参数指定客户端 HTTP 请求
到指定 `location` 的 URI。
默认情况下，它是 `/`。
`remote_uri` 值可以包含变量。

此模式的一般操作原理如下：
如果在本地未找到会话标识符，
Angie 会向 `remote_action` 参数指定的
远程存储发送同步子请求。

当新连接到达时，Angie 执行以下操作：

- 首先，从 `lookup` 列表中的
  第一个非空变量中提取会话标识符。
  如果所有变量都为空，
  则使用正常的负载均衡算法，不使用粘性会话。
- 然后 Angie 向 `remote_action` 参数指定的
  远程存储发送同步 HTTP 子请求，该请求应以
  存储能理解的格式包含：
  - 来自 `lookup` 参数的  *会话* 标识符
    （在配置中，这是
    [$sticky_sessid](#v-s-sticky-sessid) 变量）；
  - 预选  *服务器* 的标识符：
    `server` 指令中 `sid=` 参数的值
    （如果指定），
    或服务器名称的 MD5 哈希
    （在配置中，这是
    [$sticky_sid](#v-s-sticky-sid) 变量）。

  `$sticky_sessid` 和 `$sticky_sid` 变量会自动
  以 `stream_` 前缀导出到 HTTP 上下文：
  `$stream_sticky_sessid`、`$stream_sticky_sid`。
  这允许直接在 HTTP 指令中使用它们，
  例如通过 [proxy_set_header](https://cn.angie.software//angie/docs/configuration/modules/http/http_proxy.md#proxy-set-header) 使用 HTTP 头。
- 远程存储处理请求并返回 HTTP 响应：

  代码为 200、201 或 204 的响应确认所选服务器。
  远程存储可以同时
  在 HTTP 头或响应正文（PRO）中返回替代服务器标识符；
  可以通过 `remote_result` 提取它。

  当从存储接收到任何其他 HTTP 代码时
  （包括网络错误和超时）
  或不存在的服务器标识符，
  Angie 使用最初选择的服务器。

服务器标识符通过 `remote_result` 参数
从远程存储响应中提取：
它可以指定带有 `upstream_http_` 前缀的变量，
这些变量由 Angie 自动创建，用于访问
来自远程存储的 HTTP 响应头，
或使用 [$sent_body](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#v-sent-body) 来使用响应正文。
例如，此类响应中的 `X-Sid: server1` 头
在 `$upstream_http_x_sid` 变量中可访问，
其值为 `server1`。

下面是一个简化的配置示例。
远程存储在 `X-Sticky-Sid` 头中返回服务器标识符，
从而确认或覆盖 Angie 的选择：

```nginx
http {

    client {

        location @sticky_client1 {

            # 使用来自 stream upstream 的变量；
            # 它将这些变量以 stream_* 前缀添加到 HTTP 上下文
            proxy_set_header X-Sticky-Sessid $stream_sticky_sessid;
            proxy_set_header X-Sticky-Sid $stream_sticky_sid;
            proxy_set_header X-Sticky-Last $msec;
            proxy_pass http://127.0.0.1:8080;

            proxy_cache remote;
            proxy_cache_valid 200 1d;
            proxy_cache_key $scheme$proxy_host$request_uri$stream_sticky_sessid;
        }
    }
}

stream {

    upstream u {

        server 127.0.0.1:8081 sid=backend-01;
        server 127.0.0.1:8082 sid=backend-02;

        sticky learn lookup=$remote_addr            # stream 变量
        remote_action=@sticky_client1               # 来自 client 块的 location
        remote_result=$upstream_http_x_sticky_sid   # HTTP 变量
        remote_uri=/foo;                            # 默认为 /
    }

    server {

        listen 127.0.0.1:8080;
        proxy_pass u;
    }
}
```

这里，来自远程存储的响应如下：

```none
HTTP/1.1 200 OK
...
X-Sticky-Sid: backend-01
X-Session-Info: active
```

两个变量变为可用：

- `$upstream_http_x_sticky_sid`，
  值为 `backend-01`；
- `$upstream_http_x_session_info`，
  值为 `active`。

由于 `$upstream_http_x_sticky_sid` 变量
在 `remote_result` 参数中指定，
其值将被用于
选择具有 `sid=backend-01` 的服务器。

`sticky` 指令会考虑 [upstream](#s-u-upstream) 中服务器的状态：

- 标记为 `down` 或由于故障而暂时不可用的服务器
  将被排除在选择之外。
- 已达到最大连接数的服务器
  （使用 `max_conns` 时）将被暂时跳过。
- 带有 `drain` 选项的服务器（PRO）
  在 `sticky` 模式下当标识符匹配时
  可以被选择用于创建新会话。
- 如果先前不可用的服务器恢复，
  `sticky` 会自动恢复使用它。

`sticky` 的行为可以通过
[sticky_secret](#s-u-sticky-secret) 和 [sticky_strict](#s-u-sticky-strict) 指令进一步配置。
如果 `sticky` 无法选择服务器或服务器不可用，
请求将根据所选的负载均衡方法进行处理，
除非启用了 `sticky_strict` 指令。
在 `sticky_strict on;` 模式下，请求将被拒绝并返回错误。

在 `sticky` 指令的 `zone` 参数中
指定的共享内存区域
不能在不同的 `upstream` 组之间共享；
每个组必须使用自己的区域。

<a id="index-12"></a>

<a id="s-u-sticky-secret"></a>

### sticky_secret

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `sticky_secret` string;   |
|--------------------------------------------------------------------------------------|---------------------------|
| 默认值                                                                                  | —                         |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | upstream                  |

将 string 作为盐值添加到 MD5 哈希函数中，
用于 `route` 模式下的 [sticky](#s-u-sticky) 指令。
String 可以包含变量，例如 `$remote_addr`：

```nginx
upstream backend {
    server 127.0.0.1:8081 sid=a;
    server 127.0.0.1:8082 sid=b;

    sticky route $route;
    sticky_secret my_secret.$remote_addr;
}
```

盐值添加在哈希值之后；
要独立验证哈希机制：

```console
$ echo -n "<VALUE><SALT>" | md5sum
```

<a id="index-13"></a>

<a id="s-u-sticky-strict"></a>

### sticky_strict

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `sticky_strict` `on` | `off`;   |
|--------------------------------------------------------------------------------------|---------------------------------|
| 默认值                                                                                  | `sticky_strict off;`            |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | upstream                        |

启用时，如果所需的服务器不可用，
Angie 将向客户端返回连接错误，
而不是回退到另一个可用的服务器，
后者是未找到匹配服务器时的默认行为。

<a id="built-in-variables-25"></a>

## 内置变量

`stream_upstream` 模块支持以下内置变量:

<a id="v-s-sticky-sessid"></a>

### `$sticky_sessid`

与 [sticky](#s-u-sticky) 中的 `remote_action` 一起使用;
存储从 `lookup` 获取的初始会话标识符。

<a id="v-s-sticky-sid"></a>

### `$sticky_sid`

与 [sticky](#s-u-sticky) 中的 `remote_action` 一起使用;
存储先前与会话关联的服务器标识符。

`sticky_sid` 包含 [upstream](#s-u-upstream) 块中 `server` 指令的 `sid=` 参数的值(如果指定),
或者服务器名称的 MD5 哈希值。

<a id="v-s-upstream-addr"></a>

### `$upstream_addr`

存储上游服务器的 IP 地址和端口,或 UNIX 域套接字的路径。如果在代理过程中联系了多个服务器,它们的地址用逗号分隔,例如:

> 192.168.1.1:1935, 192.168.1.2:1935, unix:/tmp/sock

如果无法选择服务器,该变量保留 [服务器组](#s-u-upstream) 的名称。

<a id="v-s-upstream-bytes-received"></a>

### `$upstream_bytes_received`

从上游服务器接收的字节数。多个连接的值用逗号和冒号分隔,类似于 [$upstream_addr](#v-s-upstream-addr) 变量中的地址。

<a id="v-s-upstream-bytes-sent"></a>

### `$upstream_bytes_sent`

发送到上游服务器的字节数。多个连接的值用逗号和冒号分隔,类似于 [$upstream_addr](#v-s-upstream-addr) 变量中的地址。

<a id="v-s-upstream-connect-time"></a>

### `$upstream_connect_time`

连接到上游服务器的时间;时间以秒为单位保存,具有毫秒分辨率。多个连接的时间用逗号和冒号分隔,类似于 [$upstream_addr](#v-s-upstream-addr) 变量中的地址。

<a id="v-s-upstream-first-byte-time"></a>

### `$upstream_first_byte_time`

接收第一个数据字节的时间;时间以秒为单位保存,具有毫秒分辨率。多个连接的时间用逗号分隔,类似于 [$upstream_addr](#v-s-upstream-addr) 变量中的地址。

<a id="v-s-upstream-session-time"></a>

### `$upstream_session_time`

会话持续时间,以秒为单位,具有毫秒分辨率。多个连接的时间用逗号分隔,类似于 [$upstream_addr](#v-s-upstream-addr) 变量中的地址。

<a id="v-s-upstream-sticky-status"></a>

### `$upstream_sticky_status`

粘性连接的状态。

| `""`   | 连接路由到未启用 sticky 的服务器组。     |
|--------|----------------------------|
| `NEW`  | 连接不包含粘性信息。                 |
| `HIT`  | 包含粘性信息的连接路由到所需的服务器。        |
| `MISS` | 包含粘性信息的连接路由到由负载均衡算法选择的服务器。 |

多个连接的值用逗号和冒号分隔,
类似于 [$upstream_addr](#v-s-upstream-addr) 变量中的地址。
