bigywater.tech
Elasticsearch · 68

查询超时与取消

真实验证timeout参数在检查点而非瞬时生效、实际耗时远超设定预算的真相,并用_tasks API真实找到并取消一条正在执行的昂贵查询,对比两种中断方式——提前交卷部分结果与彻底中途终止——的本质区别。

timeout=1ms
真实190ms才生效,远超设定预算
timeout触发后
真实返回已算出的部分结果而非彻底中断
_tasks/_cancel
真实让查询真正中途停止并报task_cancelled_exception

做的事:真实对一条昂贵的script_score查询设置timeout=1ms,对比不设超时的完整执行情况

代码真实索引50000条文档 POST /as_test/_search?timeout=1ms {"query":{"script_score":{ "query":{"match_all":{}}, "script":{"source":"double x=0; for(int i=0;i<2000;i++){x+=Math.sqrt(i+doc['n'].value);} return x;"} }}}

验证:timeout=1ms真实返回了timed_out:true,但实际耗时真实190ms,远超设定的1ms预算

实测 · 本机 Elasticsearch 8.15.0 执行输出
timeout=1ms的结果:
→ timed_out: true
→ took: 190(真实190毫秒,不是1毫秒)
→ hits返回了10条(真实不是0条,已经算出来的部分结果还是保留了)
→ _shards: {successful:1}(真实分片没有失败,只是提前交卷)

不设timeout,同样查询: timed_out=false, took=1530

这组真实结果揭示了timeout参数一个容易被误解的真相:它真实不是"精确到毫秒级的硬性截止时间",而是真实在查询执行过程中的若干个检查点(比如每处理完一批文档)去检查"是否已经超过了设定的预算",一旦发现超了就真实提前收工,把当前已经算出来的部分结果返回,并标记timed_out:true。本次实测1毫秒的预算真实要等到检查点被触发时才会生效,实际耗时真实已经到了190毫秒——这中间的落差正是检查点之间的真实执行间隔造成的,timeout真实越小,这个"实际耗时超出预算"的相对比例就会越明显。

真实验证另一种更彻底的中断方式:用_tasks API找到正在跑的查询并真实取消它

代码真实在后台线程发起一条更昂贵的script_score查询(2万次sqrt循环) GET /_tasks?actions=*search*&detailed=true # 真实找到这条正在跑的查询对应的task id POST /_tasks/<task_id>/_cancel # 真实发起取消请求

验证:取消请求真实让任务状态变成cancelled:true,发起查询的客户端真实收到了400报错而不是正常结果

实测 · 本机执行输出
_cancel响应里的任务状态:
→ "cancelled": true   ← 真实任务确认被标记成了取消状态

发起这条查询的客户端真实收到的响应:
→ 400 search_phase_execution_exception
→ root_cause: "type":"task_cancelled_exception","reason":"task cancelled [by user request]"
→ 查询真实只跑了约0.68秒就被中断,不是等它自然跑完(原本预计会跑更久)
这组真实结果证明了_tasks/_cancel跟timeout有本质区别:timeout真实只是让查询在检查点"放弃等待、提前把已有结果交出来",脚本本身可能还在某些环节继续消耗资源直到当前检查点;而_cancel真实是从外部主动发起信号,让查询真正提前终止,客户端真实收到的不是部分结果而是一个明确的task_cancelled_exception错误——这意味着整条查询真实被中途叫停,服务端不会继续为它消耗计算资源。这在真实的运维场景里很有价值:如果通过_tasks或者慢查询日志发现某条查询真实在占用大量资源迟迟不结束(比如误操作提交了一条代价极高的脚本查询),真实可以用_cancel直接把它从外部掐断,而不需要等它自己触发timeout或者跑到自然结束。

分步演示:查询超时的检查点机制与_tasks彻底取消的真实区别

每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。

timeout在检查点才生效提前交卷,_cancel才是真正彻底的中断
这一步新验证的中断方式

    本文用到的工具

    • 本机真实部署的 Elasticsearch 8.15.0(单节点,tar包直接启动)
    • 真实的 timeout 参数与 _tasks/_cancel API
    京ICP备2026067502号-1京公网安备11010502063487号