> 原始 Markdown 孪生体（构建期从源 Markdown 生成）。渲染页：https://docs.gatellm.io/zh-CN/howto/enable-sticky-session · 文档索引：https://docs.gatellm.io/zh-CN/llms.txt


# 开启粘性会话与静态绑定

启用后，同一个客户端的请求会持续路由到同一个上游节点，适用于需要会话上下文的场景（如有状态对话）、减少跨节点缓存失效。

前置：先按 [创建负载均衡器](/zh-CN/howto/setup-load-balancer.md) 建好 LB。

## 启用粘性会话

控制台 → 负载均衡器 → 编辑目标 LB → 勾选「粘性会话」（对应 `extra_config.sticky_session_enabled`，**默认即为 `true`**，勾选为显式确认），填：

| 字段 | 值 | 说明 |
|------|-----|------|
| 粘性 TTL | `600`（示例，单位秒） | `binding_ttl_secs`，绑定有效期；`0` = 永久绑定 |
| 绑定键模板 | `{{header:X-Session-Id}}` | `binding_key_template`，自定义绑定键 |

```json
{
  "extra_config": { "sticky_session_enabled": true },
  "binding_ttl_secs": 600,
  "binding_key_template": "{{header:X-Session-Id}}"
}
```

> ℹ️ `sticky_session_enabled` 嵌在 `extra_config` 对象下（不是顶层字段），默认 `true`。`binding_ttl_secs`、`binding_key_template`、`static_bindings` 才是顶层字段。关闭粘性会话（让每请求按权重重选）设 `"extra_config": { "sticky_session_enabled": false }`。

保存。从此同一 `X-Session-Id` 的请求会持续路由到同一节点，直到 TTL 过期或节点不可用。

## 绑定键

绑定键决定"哪些请求算同一个客户端"。绑定键模板支持 `{{...}}` 表达式与回退链；此上下文可用的变量（完整清单与各配置处可用范围见 [模板变量速查](/zh-CN/reference/template-variables.md)）：

| 模板变量 | 来源 |
|---------|------|
| `{{request_access_key_name}}` | 访问密钥名 |
| `{{request_access_key_group}}` | 访问密钥分组名 |
| `{{request_id}}` | 客户端 `z-request-id` 头 |
| `{{access_key_hash}}` | 访问密钥的哈希（默认） |
| `{{header:X-Session-Id}}` | 客户端自定义请求头 |

> ℹ️ 注意 `{{system_prompt_hash}}` 在绑定键上下文**不可用**（恒空）：绑定键解析发生在请求体可用的更早阶段，拿不到 system 提示词。粘性会话通常用 `access_key_hash` 或会话头。链全空或含未解析变量时回退为原始访问密钥作绑定键。

### 回退链示例

```json
{
  "binding_key_template": "{{header:X-Session-Id|access_key_hash}}"
}
```

逐级降级：有会话头→用头（同一会话同节点）；无头但已认证→用 access key 哈希（同用户同节点）；两者皆空→回退为原始访问密钥作绑定键（保证每会话唯一，避免所有请求挤进同一个动态绑定会话）。

## 静态绑定

管理员预设固定绑定，让特定密钥或密钥组始终路由到指定节点。

> **配置入口**：`static_bindings` 是顶层字段，控制台的 LB 编辑表单**没有**它的批量编辑入口——下面这份完整数组经 **Console API**（PUT 负载均衡器）配置。若想在控制台 UI 里管理，进该 LB 的「**监控**」面板，可对活跃会话逐条操作：把某条动态会话固定为静态绑定（Pin）、改绑目标节点、或删除静态绑定。

```json
{
  "static_bindings": [
    {
      "binding_key": "vip-user-hash",
      "upstream": "openai-us",
      "model": "gpt-4o",
      "access_key": "alice-key"
    },
    {
      "binding_key": "team-a-hash",
      "upstream": "openai-eu",
      "model": "gpt-4o",
      "access_key_group": "team-a"
    }
  ]
}
```

- `binding_key`：手动指定的绑定键值（不是模板，直接写实际值）
- `upstream` + `model`：固定路由目标
- `access_key` / `access_key_group`：限定到某密钥或密钥组（可选）

适合给 VIP 用户或团队固定节点（如：A 团队固定走欧洲节点满足合规要求）。

## 验证粘性会话

带同一 `X-Session-Id` 连发两条请求，确认它们落在同一上游节点：

```bash
for i in 1 2; do
  curl -s http://localhost:7890/v1/chat/completions \
    -H "Authorization: Bearer <你的访问密钥>" \
    -H "X-Session-Id: demo-session-1" \
    -H "Content-Type: application/json" \
    -d '{"model":"gpt-4o-ha","messages":[{"role":"user","content":"hi"}]}' > /dev/null
done
```

再到控制台 → [日志](/zh-CN/console/logs-viewer.md) 看这两条请求的「上游」列——应落在**同一**上游节点。若分散到不同节点，检查粘性会话是否启用、绑定键模板是否把两次请求解析成同一个键（本例绑定键为 `{{header:X-Session-Id}}`）。

## 常见问题

**Q：绑定键模板支持哪些变量？**
`request_access_key_name` / `request_access_key_group` / `request_id` / `access_key_hash` / `{{header:Key}}`。**`system_prompt_hash` 恒空**，因为绑定键解析阶段还没拿到请求体。详见 [模板变量速查](/zh-CN/reference/template-variables.md)。

**Q：链全空时怎么办？**
回退为原始访问密钥作绑定键，保证每会话唯一，避免所有请求挤进同一个动态绑定会话。模板含未解析 `{{...}}` 时同样回退。

**Q：粘性会话的绑定能手动清除吗？**
绑定有过期时间（`binding_ttl_secs`），到期自动清除。如需立即清除，可重启网关（内存绑定丢失）或等 TTL 过期。

**Q：粘性会话和静态绑定冲突时怎么办？**
静态绑定优先于动态绑定。某请求匹配了静态绑定，会直接走静态绑定的节点；不匹配才走动态绑定。

**Q：节点故障时粘性绑定会迁移吗？**
会。绑定的节点不可用时，自动切换到下一个可用节点；节点恢复后，下次请求又会回到原绑定节点（TTL 未过期）。

**下一步**：[创建负载均衡器](/zh-CN/howto/setup-load-balancer.md) 看完整 LB 创建步骤；[负载均衡字段](/zh-CN/reference/load-balancing-fields.md) 看完整字段表与重试配置；[模板变量速查](/zh-CN/reference/template-variables.md) 看完整变量清单。
