--- title: "最大打开滚动上下文配置" date: 2026-02-26 lastmod: 2026-02-26 description: "控制节点上允许同时打开的最大滚动上下文数量的配置项说明" tags: ["搜索配置", "滚动查询", "资源限制"] summary: "配置项作用 # search.max_open_scroll_context 配置项限制节点上允许同时打开的最大滚动上下文(Scroll Context)数量。滚动上下文用于维持滚动查询的状态,每个滚动查询都会占用内存和文件句柄等资源。 配置项类型 # 该配置项为动态配置,可以在运行时通过集群设置 API 进行修改。 默认值 # 500 是否必需 # 可选配置项(有默认值) 取值范围 # 0 ~ Integer.MAX_VALUE 工作原理 # 滚动查询通过维护上下文来支持大量数据分页: ┌─────────────────────────────────────────────────────────┐ │ 初始化滚动查询 │ │ GET /my_index/_search?scroll=5m │ └─────────────────────────────────────────────────────────┘ │ ▼ 创建滚动上下文 (占用内存和资源) │ ▼ ┌───────────────┴───────────────┐ │ │ 未达限制 达到限制 │ │ ▼ ▼ 返回 scroll_id 拒绝创建新上下文 │ EsRejectedExecutionException ▼ 后续请求使用 scroll_id 继续获取数据 资源占用: 每个滚动上下文占用: 内存:存储查询状态和结果集 文件句柄:保持索引 reader 打开 CPU:维护上下文需要额外开销 配置格式 # # 默认配置 search." --- ## 配置项作用 `search.max_open_scroll_context` 配置项限制节点上允许同时打开的最大滚动上下文(Scroll Context)数量。滚动上下文用于维持滚动查询的状态,每个滚动查询都会占用内存和文件句柄等资源。 ## 配置项类型 该配置项为**动态配置**,可以在运行时通过集群设置 API 进行修改。 ## 默认值 ``` 500 ``` ## 是否必需 **可选配置项**(有默认值) ## 取值范围 ``` 0 ~ Integer.MAX_VALUE ``` ## 工作原理 滚动查询通过维护上下文来支持大量数据分页: ``` ┌─────────────────────────────────────────────────────────┐ │ 初始化滚动查询 │ │ GET /my_index/_search?scroll=5m │ └─────────────────────────────────────────────────────────┘ │ ▼ 创建滚动上下文 (占用内存和资源) │ ▼ ┌───────────────┴───────────────┐ │ │ 未达限制 达到限制 │ │ ▼ ▼ 返回 scroll_id 拒绝创建新上下文 │ EsRejectedExecutionException ▼ 后续请求使用 scroll_id 继续获取数据 ``` **资源占用:** 每个滚动上下文占用: - 内存:存储查询状态和结果集 - 文件句柄:保持索引 reader 打开 - CPU:维护上下文需要额外开销 ## 配置格式 ```yaml # 默认配置 search.max_open_scroll_context: 500 # 增加限制(大批量导出场景) search.max_open_scroll_context: 1000 # 减少限制(资源有限) search.max_open_scroll_context: 200 # 禁用滚动查询 search.max_open_scroll_context: 0 ``` ## 使用示例 **基本滚动查询:** ```bash # 1. 初始化滚动查询 GET /my_index/_search?scroll=5m { "size": 1000, "query": { "match_all": {} } } # 返回: # { # "_scroll_id": "c2NhbjsxOzE7dG90YWxfaGl0czo1MDt...", # "hits": { ... } # } # 2. 使用 scroll_id 获取下一批数据 GET /_search/scroll { "scroll": "5m", "scroll_id": "c2NhbjsxOzE7dG90YWxfaGl0czo1MDt..." } # 3. 完成后清理滚动上下文 DELETE /_search/scroll/c2NhbjsxOzE7dG90YWxfaGl0czo1MDt... ``` ## 推荐设置建议 **生产环境建议**:根据使用场景和资源设置 | 场景 | 推荐值 | 说明 | |-----|-------|------| | 默认 | 500 | 通用场景 | | 数据导出 | 1000-2000 | 需要大量并发滚动查询 | | 实时搜索 | 100-300 | 滚动查询较少 | | 资源受限 | 100-200 | 内存或文件句柄有限 | ## 资源消耗估算 **每个滚动上下文约占:** | 资源类型 | 占用量 | 说明 | |---------|-------|------| | JVM 堆内存 | 1-10MB | 取决于查询复杂度 | | 文件句柄 | 1-3 个 | 保持 segment reader | | CPU | 低 | 主要是维护开销 | **示例计算:** ``` 每个上下文平均占用: 5MB max_open_scroll_context: 500 总内存占用: 500 × 5MB = 2.5GB 如果 JVM 堆: 16GB 滚动上下文占用: 2.5GB / 16GB = 15.6% ``` ## 常见问题 **问题 1:超出限制被拒绝** ``` EsRejectedExecutionException[trying to create too many scroll contexts. maximum: 500] ``` **可能原因:** 1. 应用未清理滚动上下文 2. 并发滚动查询过多 3. 滚动时间过长 **解决方案:** 1. **增加限制** ```bash PUT /_cluster/settings { "transient": { "search.max_open_scroll_context": 1000 } } ``` 2. **清理旧的滚动上下文** ```bash # 清理所有滚动上下文 DELETE /_search/scroll/_all # 清理特定的滚动上下文 DELETE /_search/scroll/c2NhbjsxOzE7... ``` 3. **使用 search_after 替代滚动** ```json // 使用 search_after 进行深分页 GET /my_index/_search { "size": 100, "query": {"match_all": {}}, "sort": [ {"_id": "asc"}, {"_score": "desc"} ], "search_after": ["last_doc_id", 0.5] } ``` 4. **优化滚动查询** ```json // 减小每次请求的数据量 GET /my_index/_search?scroll=2m { "size": 100, // 减小 size "query": { "range": { "timestamp": { "gte": "now-1h" // 缩小时间范围 } } } } ``` **问题 2:滚动上下文泄漏** **症状:** - 滚动上下文数量持续增长 - 内存使用持续增长 - 未达到限制但资源紧张 **解决方案:** 1. **设置自动清理** ```bash # 在 easysearch.yml 中设置 search.keep_alive_interval: 1m ``` 2. **应用层正确处理** ```javascript // 伪代码示例 try { do { result = client.scroll({ scroll: '5m', scroll_id: scrollId }); // 处理数据... // 检查是否完成 if (result.hits.hits.length === 0) { break; } } while (true); } finally { // 务必清理滚动上下文 client.clearScroll({ scroll_id: scrollId }); } ``` 3. **定期清理** ```bash # 定期执行清理任务 DELETE /_search/scroll/_all ``` ## 动态修改 ```bash # 临时修改 PUT /_cluster/settings { "transient": { "search.max_open_scroll_context": 1000 } } # 持久修改 PUT /_cluster/settings { "persistent": { "search.max_open_scroll_context": 1000 } } ``` ## 查看当前状态 ```bash # 查看当前设置 GET /_cluster/settings?flat_settings=true # 查看节点统计信息 GET /_nodes/stats/indices/search?pretty # 查看当前打开的滚动上下文数量 GET /_nodes/stats/indices/search?filter_path=**.open_contexts ``` **输出字段说明:** | 字段 | 说明 | |-----|------| | open_contexts | 当前打开的滚动上下文数 | | scroll_current | 当前活跃的滚动查询数 | | scroll_total | 总滚动查询数 | ## 替代方案 **1. 使用 search_after** ```json // search_after 适用于实时深分页 GET /my_index/_search { "size": 100, "query": {"match_all": {}}, "sort": [ {"timestamp": "asc"}, {"_id": "asc"} ] } // 获取下一页,使用上一页最后的 sort 值 GET /my_index/_search { "size": 100, "query": {"match_all": {}}, "sort": [ {"timestamp": "asc"}, {"_id": "asc"} ], "search_after": [1609459200000, "doc_id_123"] } ``` **2. 使用 PIT(Point In Time)** ```bash # 创建 PIT POST /my_index/_pit { "keep_alive": "10m" } # 使用 PIT 进行搜索 GET /_search { "size": 100, "pit": { "id": "pit_id_value", "keep_alive": "10m" }, "query": {"match_all": {}}, "sort": [{"_shard_doc": "asc"}] } # 关闭 PIT DELETE /_pit { "pit_id": "pit_id_value" } ``` ## 性能优化建议 **1. 合理设置滚动时间** ```bash # 根据处理速度设置 # 快速处理:1-2 分钟 GET /my_index/_search?scroll=1m # 慢速处理:5-10 分钟 GET /my_index/_search?scroll=5m # 避免设置过长 GET /my_index/_search?scroll=1h # 不推荐 ``` **2. 控制每次返回数量** ```json // 根据网络和内存情况调整 size GET /my_index/_search?scroll=5m { "size": 1000 // 100-1000 之间 } ``` **3. 使用字段过滤** ```json // 只获取需要的字段,减少内存占用 GET /my_index/_search?scroll=5m { "size": 1000, "_source": ["field1", "field2", "field3"], "query": {"match_all": {}} } ``` ## 相关配置项 | 配置项 | 默认值 | 说明 | |-------|-------|------| | `search.max_keep_alive` | 24h | 最大滚动保持时间 | | `search.default_keep_alive` | 5m | 默认滚动保持时间 | | `search.keep_alive_interval` | 1m | 清理间隔 | | `search.max_open_pit_context` | 300 | 最大 PIT 上下文数 | ## 监控建议 ```bash # 持续监控滚动上下文数量 GET /_nodes/stats/indices/search?pretty # 设置告警 # 当 open_contexts > 80% 限制时告警 ``` **健康阈值:** | 指标 | 健康 | 警告 | 严重 | |-----|------|------|------| | open_contexts / max | < 60% | 60-80% | > 80% | ## 注意事项 1. **动态更新**:此配置为动态配置,可在线修改 2. **资源占用**:每个滚动上下文占用内存和文件句柄 3. **及时清理**:使用完毕后务必清理滚动上下文 4. **替代方案**:考虑使用 search_after 或 PIT 5. **监控重要**:定期监控打开的上下文数量