--- title: "INFINI Gateway 如何防止大跨度查询" date: 2023-12-19 lastmod: 2023-12-19 description: "为限制业务查询多天数据导致负载过高,通过网关代理ES集群并配置过滤器,仅允许查询单日索引。若需查询多天数据,可通过申请创建符合格式的别名实现,同时严格管控别名创建。" tags: ["Gateway"] summary: "背景 # 业务每天生成一个日期后缀的索引,写入当日数据。 业务查询有时会查询好多天的数据,导致负载告警。 现在想对查询进行限制–只允许查询一天的数据(不限定是哪天),如果想查询多天的数据就走申请。 技术分析 # 在每天一个索引的情况下,要进行多天的数据查询,有三种途径: 查询时,指定多个索引 查询时,写前缀+*号,模糊匹配多个索引 查询别名,别名关联多个索引 需求实现 # 我们只需用网关代理 ES 集群,并在 default_flow 中增加一段 request_path_filter 过滤器的配置,只允许查询一个索引且格式如 “xxx-2023-12-06”, “xxx.2023.12.06”, “xxx20231206” 。 - request_path_filter: message: "Query scope exceeds limit, please contact the administrator for application." must: suffix: - _search regex: - \/[a-z]+[-.]?\d{4}[-.]?\d{1,2}[-.]?\d{1,2}\/ 如果需要指定其他格式,请自行修改 regex 的正则表达式。 创建测试索引 # 在 INFINI Console 开发工具中执行下列语句: POST test-2023-12-06/_doc { "test":"test" } POST test-2023-12-6/_doc { "test":"test" } POST test." --- ## 背景 业务每天生成一个日期后缀的索引,写入当日数据。 业务查询有时会查询好多天的数据,导致负载告警。 现在想对查询进行限制--只允许查询一天的数据(不限定是哪天),如果想查询多天的数据就走申请。 ## 技术分析 在每天一个索引的情况下,要进行多天的数据查询,有三种途径: 1. 查询时,指定多个索引 2. 查询时,写前缀+\*号,模糊匹配多个索引 3. 查询别名,别名关联多个索引 ## 需求实现 我们只需用网关代理 ES 集群,并在 default_flow 中增加一段 [request_path_filter](https://docs.infinilabs.com/gateway/main/zh/references/filters/request_path_filter/) 过滤器的配置,只允许查询一个索引且格式如 "xxx-2023-12-06", "xxx.2023.12.06", "xxx20231206" 。 ``` - request_path_filter: message: "Query scope exceeds limit, please contact the administrator for application." must: suffix: - _search regex: - \/[a-z]+[-.]?\d{4}[-.]?\d{1,2}[-.]?\d{1,2}\/ ``` {{% load-img "/img/blog/2023/prevent-large-span-query-using-gateway/1.png" "" %}} 如果需要指定其他格式,请自行修改 regex 的正则表达式。 ## 创建测试索引 在 [INFINI Console](https://docs.infinilabs.com/console/main/zh/) 开发工具中执行下列语句: ``` POST test-2023-12-06/_doc { "test":"test" } POST test-2023-12-6/_doc { "test":"test" } POST test.2023.12.06/_doc { "test":"test" } POST test.2023.12.6/_doc { "test":"test" } POST test20231206/_doc { "test":"test" } POST test/_doc { "test":"test" } ``` ## 查询测试语句 ``` #预计成功的查询 curl localhost:8000/test-2023-12-06/_search?pretty curl localhost:8000/test-2023-12-6/_search?pretty curl localhost:8000/test.2023.12.06/_search?pretty curl localhost:8000/test.2023.12.6/_search?pretty curl localhost:8000/test20231206/_search?pretty #预计失败的查询 curl localhost:8000/test-2023-12-06,test-2023-12-6/_search?pretty curl localhost:8000/test-2023-12*/_search?pretty curl localhost:8000/test*/_search?pretty curl localhost:8000/*/_search?pretty ``` ## 查询结果 #### 预计成功的查询 {{% load-img "/img/blog/2023/prevent-large-span-query-using-gateway/2.png" "" %}} #### 预计失败的查询 {{% load-img "/img/blog/2023/prevent-large-span-query-using-gateway/3.png" "" %}} 此外,我们在 Console 中的 Request Analysis 看板中也能看到,哪些请求被拒绝,哪些请求被“放行”。 {{% load-img "/img/blog/2023/prevent-large-span-query-using-gateway/4.png" "" %}} ## 查询多个索引(多天) 现在我们已经实现了业务只能查一个索引,即一天的数据。当业务需要查询多天的索引时,我们只需创建一个别名,关联多个索引就行了。注意别名也要符合格式要求:字母开头 + 日期格式后缀。 下面我们创建一个 test-1111-1-1 的别名,关联前面的三个测试索引。 ``` POST /_aliases { "actions" : [ { "add" : { "indices" : ["test-2023-12-06", "test.2023.12.06","test-2023-12-6"], "alias" : "test-1111-1-1" } } ] } ``` **查询别名** {{% load-img "/img/blog/2023/prevent-large-span-query-using-gateway/5.png" "" %}} 待业务查询用完之后,删除别名即可。 ``` POST /_aliases { "actions" : [ { "remove": { "indices" : ["test-2023-12-06", "test.2023.12.06","test-2023-12-6"], "alias" : "test-1111-1-1" } } ] } ``` 最后,我们只需严格控制别名的创建,就能实现我们最初的需求了。