ES 6.1.1 使用 scroll 拉取全量数据,size:10000,每次都是将上一次返回的 scroll id 作为下一次查询条件。但是偶尔会出现中途一批次返回为空的情况,甚至连 scroll id 都没有,返回中提示分片数为 147 和实际索引的分片数也完全不一致。但如果继续使用之前的 scroll id 依然可以正常拉取数据,就是少了中间的那批数据。
例如:
{"took":84,"timed_out":false,"_shards":{"total":147,"successful":147,"skipped":140,"failed":0},"hits":{"total":0,"max_score":null,"hits":},"aggregations":{"code":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":}},"code":200}
GET index_name/_search?scroll=5m
{
"size": 10000
...
}
GET _search/scroll
{
"scroll": "5m",
"scroll_id": "上一次返回的id"
}
例如:
{"took":84,"timed_out":false,"_shards":{"total":147,"successful":147,"skipped":140,"failed":0},"hits":{"total":0,"max_score":null,"hits":},"aggregations":{"code":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":}},"code":200}
GET index_name/_search?scroll=5m
{
"size": 10000
...
}
GET _search/scroll
{
"scroll": "5m",
"scroll_id": "上一次返回的id"
}
2 个回复
sardineYJA
赞同来自:
Fred2000 - 与其抱怨世界,不如改变自己
赞同来自:
原因分析:
1. Scroll Context 过期:
Scroll API 在长时间运行时可能导致 scroll context 过期,特别是在多次请求之间有较长延迟时。虽然你设置了 5 分钟的 scroll,但如果执行的查询时间较长或间隔较长,scroll context 可能在服务器端被清理掉,导致下一次请求无法正常获取数据。
2. 集群状态波动或分片重分配:
在执行 scroll 请求的过程中,如果集群发生了状态变化(如分片重分配、节点宕机等),可能会导致 scroll id 对应的部分数据不可用,从而导致返回的分片数与实际索引的分片数不一致,或者中途出现空结果。
3. Scroll ID 不一致:
Scroll id 是一种轻量级的快照,它保留了搜索的上下文状态。但是,由于 Elasticsearch 的内部机制或是集群内部状态的改变,scroll id 在某些情况下可能会失效或者关联的数据发生变化,导致无法继续检索到期望的数据。
4. 分片合并或数据变化:
Elasticsearch 在后台会自动执行分片合并等维护操作,这些操作可能会影响 scroll 的一致性,从而导致偶尔的数据不一致或数据丢失。
解决方案:
1. 增加 scroll 时间:
适当增加 scroll 的生存时间(如设置更长的时间,例如 10 分钟或以上),确保在高负载或长时间查询的场景下,scroll context 不会轻易过期。
2. 减少查询间隔:
缩短每次 scroll 请求之间的时间间隔,尽量减少 scroll context 过期的可能性,确保数据的连续性。
3. 检查集群健康状态:
在 scroll 操作前,检查集群的健康状态,确保在查询过程中不会发生分片重分配或节点宕机等可能导致 scroll 失效的操作。
4. 使用 Search After 替代 Scroll:
如果 scroll 的稳定性无法满足要求,可以考虑使用 search_after 来分页查询大规模数据。这种方式避免了 scroll id 的复杂性,适用于数据相对静态且需要严格分页的场景。
5. 日志分析:
检查 Elasticsearch 的日志文件,看是否有任何异常提示或错误信息,可以帮助定位集群在 scroll 过程中的问题。