--- title: "使用 INFINI Gateway 保护 Elasticsearch 集群之阻断不合理的查询" date: 2025-02-11 lastmod: 2025-02-11 description: "本文介绍如何使用INFINI Gateway阻止不合理查询发送至Elasticsearch,防止OOM问题。通过配置context_filter过滤器,识别并阻断高消耗查询,保障集群稳定。方法同样适用于Opensearch和INFINI Easysearch。" tags: ["Easysearch", "Gateway"] summary: "本文将探讨如何使用 INFINI Gateway 阻止不合理的查询发送到 Elasticsearch,此方法同样适用于 Opensearch 和 INFINI Easysearch 。 在以往处理 Elasticsearch OOM(内存溢出)问题的经验中,我们发现许多案例是由于查询操作导致节点出现 OOM 的情况。经过调查,这些案例主要分为两类:一类是由于查询吞吐量超出了集群的处理能力,另一类则是在执行某些不合理的查询时触发了 OOM。 具体来说: 查询吞吐量过高:当查询请求的频率或复杂度超过了集群的处理能力时,可能会导致节点内存耗尽,从而引发 OOM。 执行不合理查询:某些特殊类型的查询(例如涉及大量嵌套、深度分页或复杂的聚合操作)可能需要大量的内存资源,在执行过程中也可能导致 OOM。 通过识别并优化这些查询模式,可以有效减少 OOM 事件的发生。针对查询吞吐量过高的情况,可以参考之前的 文章来管理查询吞吐。接下来的内容将介绍如何阻挡不合理查询,保护集群稳定。 不合理查询 # 不合理查询是指那些消耗过多系统资源(如 CPU、内存)、设计复杂、执行时间过长或需要大量计算资源的查询。这类查询不仅会导致高负载和资源耗尽,影响整个集群的稳定性和响应速度,还可能对用户体验产生负面影响。 典型的不合理查询包括但不限于: 嵌套聚合查询 使用复杂的正则表达式进行模糊匹配 深度分页查询(如 from: 10000, size: 10) 脚本查询(Script Query) 大规模嵌套聚合查询 为了防止这些查询对 Elasticsearch 集群造成影响,我们可以使用 INFINI Gateway 对这些查询进行阻断。 请求上下文 # INFINI Gateway 运行环境中有非常多的信息可被利用,而请求上下文就是访问这些信息的入口。如请求来源、请求体信息等,都可使用关键字 _ctx 作为前缀访问相应的上下文信息。 HTTP 请求内置的 _ctx 上下文对象主要包括如下: 更多的上下文信息请访问 文档。 context_filter # Context Filter 是 INFINI Gateway 提供的一种在线过滤器,能够根据请求上下文来过滤流量。通过定义一组匹配规则,可以灵活地对流量进行筛选。该过滤器支持多种匹配模式,包括:" --- 本文将探讨如何使用 INFINI Gateway 阻止不合理的查询发送到 Elasticsearch,此方法同样适用于 Opensearch 和 INFINI Easysearch 。 在以往处理 Elasticsearch OOM(内存溢出)问题的经验中,我们发现许多案例是由于查询操作导致节点出现 OOM 的情况。经过调查,这些案例主要分为两类:一类是由于查询吞吐量超出了集群的处理能力,另一类则是在执行某些不合理的查询时触发了 OOM。 具体来说: - 查询吞吐量过高:当查询请求的频率或复杂度超过了集群的处理能力时,可能会导致节点内存耗尽,从而引发 OOM。 - 执行不合理查询:某些特殊类型的查询(例如涉及大量嵌套、深度分页或复杂的聚合操作)可能需要大量的内存资源,在执行过程中也可能导致 OOM。 通过识别并优化这些查询模式,可以有效减少 OOM 事件的发生。针对查询吞吐量过高的情况,可以参考之前的[文章](https://infinilabs.cn/blog/2024/how-to-prevent-es-oom/)来管理查询吞吐。接下来的内容将介绍如何阻挡不合理查询,保护集群稳定。 ## 不合理查询 不合理查询是指那些消耗过多系统资源(如 CPU、内存)、设计复杂、执行时间过长或需要大量计算资源的查询。这类查询不仅会导致高负载和资源耗尽,影响整个集群的稳定性和响应速度,还可能对用户体验产生负面影响。 典型的不合理查询包括但不限于: - 嵌套聚合查询 - 使用复杂的正则表达式进行模糊匹配 - 深度分页查询(如 from: 10000, size: 10) - 脚本查询(Script Query) - 大规模嵌套聚合查询 为了防止这些查询对 Elasticsearch 集群造成影响,我们可以使用 INFINI Gateway 对这些查询进行阻断。 ## 请求上下文 INFINI Gateway 运行环境中有非常多的信息可被利用,而**请求上下文**就是访问这些信息的入口。如请求来源、请求体信息等,都可使用关键字 **\_ctx** 作为前缀访问相应的上下文信息。 HTTP 请求内置的 \_ctx 上下文对象主要包括如下: {{% load-img "/img/blog/2025/block-unreasonable-queries-with-infini-gateway/1.png" "" %}} 更多的上下文信息请访问[文档](https://docs.infinilabs.com/gateway/main/zh/docs/references/context/)。 ## context_filter Context Filter 是 INFINI Gateway 提供的一种在线过滤器,能够根据**请求上下文**来过滤流量。通过定义一组匹配规则,可以灵活地对流量进行筛选。该过滤器支持多种匹配模式,包括: - 前缀匹配 - 后缀匹配 - 模糊匹配 - 正则匹配 对于匹配到的请求,可以直接阻断(拒绝)并返回自定义的消息。因此,关键点就是要明确不合理请求的关键字信息。 ## 使用步骤 1. **确定关键字信息**:确定特殊查询请求中的关键特征或关键字。 2. **配置匹配规则**:在 context_filter 中定义相应的匹配规则,选择合适的匹配模式(如前缀、后缀、模糊或正则匹配)。 3. **阻断请求**:一旦匹配到这些关键字,INFINI Gateway 将自动阻断请求并返回指定的消息。 更多详细内容,请参阅相关 [文档](https://docs.infinilabs.com/gateway/main/zh/docs/references/filters/context_filter/)。 ## 举个例子 阻止 wildcard 查询(模糊匹配查询),我们先看一个 wildcard 查询的样子。 ```plain GET yf-test-1shard/_search { "query": { "wildcard": { "path.keyword": { "value": "/a*" } } } } ``` 上面的查询,会查询 path 字段,所有以 /a 开头的文档。 {{% load-img "/img/blog/2025/block-unreasonable-queries-with-infini-gateway/2.png" "" %}} 第一步:我们可确定关键字是 wildcard,为了进一步限制是 wildcard 查询里的情况,我们可将关键字确定为 `wildcard":`,因为有时候查询 url 里会有 expand_wildcards 字样。 第二步:编辑 INFINI Gateway 默认配置文件,增加 context_filter 匹配规则。 ```plain - name: default_flow filter: - context_filter: context: _ctx.request.to_string message: 'Request blocked. Reason: Forbidden. Please contact the administrator at 010-111111.' status: 403 action: deny must_not: contain: - "wildcard\":" ``` 通过上面的修改,我们在 INFINI Gatway 的默认处理流程开头添加了 context_filter 过滤器,阻止查询请求种带关键字 `wildcard":` 的查询,并返回消息"Request blocked. Reason: Forbidden. Please contact the administrator at 010-111111." 第三步,测试 wildcard 请求能否被阻断。 {{% load-img "/img/blog/2025/block-unreasonable-queries-with-infini-gateway/3.png" "" %}} 可以看到,INFINI Gateway 成功阻止了 wildcard 查询,并返回了我们定义的信息。通过此方法,我们可以阻断高消耗类查询被发送到 ES 集群,避免引发集群性能问题。对业务上合理的需求,我们可以进一步沟通,确定合理的方案。 有任何问题,欢迎加我微信沟通。 {{% load-img "/img/blog/banner/about_yangf.png" "" %}}