【1月8日】Elastic 中国开发者大会 2021 日程新鲜出炉!福利票抢先购!

重要的事情说三遍

  • Elastic 中国开发者大会 2021 的精彩日程现已上线!
  • Elastic 中国开发者大会 2021 的精彩日程现已上线!
  • Elastic 中国开发者大会 2021 的精彩日程现已上线!

关于本次大会

Elastic 中国开发者大会 2021 是由 Elastic 官方、Elastic 足球社区和极限科技联合主办的开发者大会,作为中国国内唯一一个专门讨论 Elasticsearch 开源技术的大会,是中国最权威和最具实力干货的技术大会,其专业性和内容的质量一直以来在业内都是有口皆碑。本次大会邀请的演讲嘉宾有来自 Elastic 官方、Google、腾讯、阿里巴巴、字节跳动、vivo等众多公司的技术专家,为中国广大的 Elasticsearch 开发者提供一个技术交流和学习切磋的地方,汇集业界众多的成功案例,集思广益,发散思维,促进社区和行业的进步。

更多详细介绍请参见大会官网:

https://conf.www.ksh17j.com

关于大会议程

开发者大会2021议程_8折.png

精彩内容不容错过,八折购票火热进行中(折扣码: 80OFF),扫码购买。

继续阅读 »

重要的事情说三遍

  • Elastic 中国开发者大会 2021 的精彩日程现已上线!
  • Elastic 中国开发者大会 2021 的精彩日程现已上线!
  • Elastic 中国开发者大会 2021 的精彩日程现已上线!

关于本次大会

Elastic 中国开发者大会 2021 是由 Elastic 官方、Elastic 足球社区和极限科技联合主办的开发者大会,作为中国国内唯一一个专门讨论 Elasticsearch 开源技术的大会,是中国最权威和最具实力干货的技术大会,其专业性和内容的质量一直以来在业内都是有口皆碑。本次大会邀请的演讲嘉宾有来自 Elastic 官方、Google、腾讯、阿里巴巴、字节跳动、vivo等众多公司的技术专家,为中国广大的 Elasticsearch 开发者提供一个技术交流和学习切磋的地方,汇集业界众多的成功案例,集思广益,发散思维,促进社区和行业的进步。

更多详细介绍请参见大会官网:

https://conf.www.ksh17j.com

关于大会议程

开发者大会2021议程_8折.png

精彩内容不容错过,八折购票火热进行中(折扣码: 80OFF),扫码购买。

收起阅读 »

Elastic 7.16 版:精简的数据集成驱动重要的结果


7.16_.png

我们很高兴地宣布 Elastic 7.16 版正式发布,这个版本为 Elastic Search Platform(包括 Elasticsearch 和 Kibana)及其三个内置解决方案(Elastic 企业搜索、Elastic 可观测性和 Elastic 安全)带来一系列广泛的全新功能。

Elastic 7.16 版简化了将各类数据从任何来源采集到 Elastic Search Platform 的过程。这个版本引入了数十个预构建的 Elastic 代理数据集成、适用于持续集成和持续交付 (CI/CD) 管道的可观测性工具、两个新获认证的 ServiceNow 应用程序,以及 Amazon Web Services (AWS) 和 Elastic Cloud 之间的原生数据集成,极大扩展了对复杂的分布式云原生服务的可见性。

此外,Elastic 企业搜索的一体化用户界面现已在 Kibana 中正式上线,让您可以更轻松地使用强大的可视化功能深入了解最终用户的搜索体验。而且,由自适应相关性提供支持的搜索结果管理功能现已推出公测版,这样一来,Elastic App Search 用户可以利用收集到的分析和自动建议,打造更好的搜索体验。

从改善最终用户的搜索体验,到使用临时分析加快故障排除速度、扩展管道构建和部署的可见性,以及保护终端免受高级威胁的影响,Elastic 7.16 版的正式发布,将能够协助组织打造出色的搜索体验,提升解决问题的能力,为组织取得成功助一臂之力。
 
详细阅读,请参阅 
继续阅读 »

7.16_.png

我们很高兴地宣布 Elastic 7.16 版正式发布,这个版本为 Elastic Search Platform(包括 Elasticsearch 和 Kibana)及其三个内置解决方案(Elastic 企业搜索、Elastic 可观测性和 Elastic 安全)带来一系列广泛的全新功能。

Elastic 7.16 版简化了将各类数据从任何来源采集到 Elastic Search Platform 的过程。这个版本引入了数十个预构建的 Elastic 代理数据集成、适用于持续集成和持续交付 (CI/CD) 管道的可观测性工具、两个新获认证的 ServiceNow 应用程序,以及 Amazon Web Services (AWS) 和 Elastic Cloud 之间的原生数据集成,极大扩展了对复杂的分布式云原生服务的可见性。

此外,Elastic 企业搜索的一体化用户界面现已在 Kibana 中正式上线,让您可以更轻松地使用强大的可视化功能深入了解最终用户的搜索体验。而且,由自适应相关性提供支持的搜索结果管理功能现已推出公测版,这样一来,Elastic App Search 用户可以利用收集到的分析和自动建议,打造更好的搜索体验。

从改善最终用户的搜索体验,到使用临时分析加快故障排除速度、扩展管道构建和部署的可见性,以及保护终端免受高级威胁的影响,Elastic 7.16 版的正式发布,将能够协助组织打造出色的搜索体验,提升解决问题的能力,为组织取得成功助一臂之力。
 
详细阅读,请参阅  收起阅读 »

Elastic:在 CentOS 上一步一步安装 Elastic Stack

在我之前的许多文章中,我介绍了如何在 Ubuntu 系统上安装 Elasticsearch。没有 centos 的安装步骤。其中的原因是我自己没有一台 centos 的机器。在今天的教程中,我来详述如何使用 Vagrant 来安装 centos,并在它上面安装 Elastic Stack。

如果你从来还没有安装过 Vagrant,请参照我之前的教程 “Vagrant 入门教程” 来进行学习。在今天的练习中,我们使用如下的配置:



centos.png

详细阅读,请参阅 
继续阅读 »
在我之前的许多文章中,我介绍了如何在 Ubuntu 系统上安装 Elasticsearch。没有 centos 的安装步骤。其中的原因是我自己没有一台 centos 的机器。在今天的教程中,我来详述如何使用 Vagrant 来安装 centos,并在它上面安装 Elastic Stack。

如果你从来还没有安装过 Vagrant,请参照我之前的教程 “Vagrant 入门教程” 来进行学习。在今天的练习中,我们使用如下的配置:



centos.png

详细阅读,请参阅  收起阅读 »

使用极限网关来处置 Elasticsearch 的 Apache Log4j 漏洞

昨日爆出的 Log4j 安全漏洞,业界一片哗然,今天给大家介绍一下,如何使用极限网关来快速处置 Elasticsearch 的 Apache Log4j 漏洞。

【CVE 地址】

【漏洞描述】

Apache Log4j 是一款非常流行的开源的用于 Java 运行环境的日志记录工具包,大量的 Java 框架包括 Elasticsearch 的最新版本都使用了该组件,故影响范围非常之大。

近日, 随着 Apache Log4j 的远程代码执行最新漏洞细节被公开,攻击者可通过构造恶意请求利用该漏洞实现在目标服务器上执行任意代码。可导致服务器被黑客控制,从而进行页面篡改、数据窃取、挖矿、勒索等行为。建议使用该组件的用户第一时间启动应急响应进行修复。

简单总结一下就是,在使用 Log4j 打印输出的日志中,如果发现日志内容中包含关键词 ${,那么这个里面包含的内容会当做变量来进行替换和执行,导致攻击者可以通过恶意构造日志内容来让 Java 进程来执行任意命令,达到攻击的效果。

【漏洞等级】:非常紧急

此次漏洞是用于 Log4j2 提供的 lookup 功能造成的,该功能允许开发者通过一些协议去读取相应环境中的配置。但在实现的过程中,并未对输入进行严格的判断,从而造成漏洞的发生。

【影响范围】:Java 类产品:Apache Log4j 2.x < 2.15.0-rc2,Elasticsearch 当前所有版本。

【攻击检测】

可以通过检查日志中是否存在 jndi:ldap://jndi:rmi 等字符来发现可能的攻击行为。

处理办法

最简单的办法是通过修改 config/jvm.options,新增以下参数,重启集群所有节点即可。

 -Dlog4j2.formatMsgNoLookups=true

不过,如果集群规模较大,数据较多,业务不能中断,不能通过修改 Elasticsearch 配置、或者替换 Log4j 的最新 jar 包来重启集群的情况,可以考虑使用极限网关来进行拦截或者参数替换甚至是直接阻断请求。

通过在网关层对发往 Elasticsearch 的请求统一进行参数检测,将包含的敏感关键词 ${ 进行替换或者直接拒绝, 可以防止带攻击的请求到达 Elasticsearch 服务端而被 Log4j 打印相关日志的时候执行恶意攻击命令,从而避免被攻击。

极限网关是透明代理,只需要在应用端,将以往配置指向 Elasticsearch 的地址替换为现在网关的地址即可,其他都不用动。

参考配置

下载最新的 1.5.0-SNAPSHOT 版本https://release.www.ksh17j.com/gateway/snapshot/

使用极限网关的 context_filter 过滤器,对请求上下文 _ctx.request.to_string 进行关键字检测,过滤掉恶意流量,从而阻断攻击。

新增一个配置文件 gateway.yml

path.data: data
path.logs: log

entry:
  - name: es_entrypoint
    enabled: true
    router: default
    max_concurrency: 20000
    network:
      binding: 0.0.0.0:8000

router:
  - name: default
    default_flow: main_flow

flow:
  - name: main_flow
    filter:
      - context_filter:
          context: _ctx.request.to_string
          action: redirect_flow
          status: 403
          flow: log4j_matched_flow
          must_not: # any match will be filtered
            regex:
              - \$\{.*?\}
              - "%24%7B.*?%7D" #urlencode
            contain:
              - "jndi:"
              - "jndi:ldap:"
              - "jndi:rmi:"
              - "jndi%3A" #urlencode
              - "jndi%3Aldap%3A" #urlencode
              - "jndi%3Armi%3A" #urlencode
      - elasticsearch:
          elasticsearch: es-server
  - name: log4j_matched_flow
    filter:
      - echo:
          message: 'Apache Log4j 2, Boom!'

elasticsearch:
  - name: es-server
    enabled: true
    endpoints:
      - https://localhost:9200

启动网关:

➜  ./bin/gateway -config /tmp/gateway.yml
   ___   _   _____  __  __    __  _       
  / _ \ /_\ /__   \/__\/ / /\ \ \/_\ /\_/\
 / /_\///_\\  / /\/_\  \ \/  \/ //_\\\_ _/
/ /_\\/  _  \/ / //__   \  /\  /  _  \/ \ 
\____/\_/ \_/\/  \__/    \/  \/\_/ \_/\_/ 

[GATEWAY] A light-weight, powerful and high-performance elasticsearch gateway.
[GATEWAY] 1.0.0_SNAPSHOT, 2021-12-10 23:55:34, 2212aff
[12-11 01:55:49] [INF] [app.go:250] initializing gateway.
[12-11 01:55:49] [INF] [instance.go:26] workspace: /Users/medcl/go/src/infini.sh/gateway/data/gateway/nodes/0
[12-11 01:55:49] [INF] [api.go:261] api listen at: https://0.0.0.0:2900
[12-11 01:55:49] [INF] [reverseproxy.go:253] elasticsearch [es-server] hosts: [] => [localhost:9200]
[12-11 01:55:49] [INF] [entry.go:296] entry [es_entrypoint] listen at: https://0.0.0.0:8000
[12-11 01:55:49] [INF] [module.go:116] all modules started
[12-11 01:55:49] [INF] [app.go:357] gateway is running now.
[12-11 01:55:49] [INF] [actions.go:236] elasticsearch [es-server] is available

将要使用的测试命令 ${java:os} 使用 urlencode 转码为 %24%7Bjava%3Aos%7D,构造查询语句,分别测试。

不走网关:

~%  curl 'https://localhost:9200/index1/_search?q=%24%7Bjava%3Aos%7D' 
{"error":{"root_cause":[{"type":"index_not_found_exception","reason":"no such index","resource.type":"index_or_alias","resource.id":"index1","index_uuid":"_na_","index":"index1"}],"type":"index_not_found_exception","reason":"no such index","resource.type":"index_or_alias","resource.id":"index1","index_uuid":"_na_","index":"index1"},"status":404}%   

查看 Elasticsearch 端日志为:

[2021-12-11T01:49:50,303][DEBUG][r.suppressed             ] path: /index1/_search, params: {q=Mac OS X 10.13.4 unknown, architecture: x86_64-64, index=index1}
org.elasticsearch.index.IndexNotFoundException: no such index
    at org.elasticsearch.cluster.metadata.IndexNameExpressionResolver$WildcardExpressionResolver.infe(IndexNameExpressionResolver.java:678) ~[elasticsearch-5.6.15.jar:5.6.15]
    at org.elasticsearch.cluster.metadata.IndexNameExpressionResolver$WildcardExpressionResolver.innerResolve(IndexNameExpressionResolver.java:632) ~[elasticsearch-5.6.15.jar:5.6.15]
    at org.elasticsearch.cluster.metadata.IndexNameExpressionResolver$WildcardExpressionResolver.resolve(IndexNameExpressionResolver.java:580) ~[elasticsearch-5.6.15.jar:5.6.15]

可以看到查询条件里面的 q=${java:os} 被执行了,变成了 q=Mac OS X 10.13.4 unknown, architecture: x86_64-64, index=index1,说明变量被解析且执行,存在漏洞利用的风险。

那走网关之后呢:

~%  curl 'https://localhost:8000/index1/_search?q=%24%7Bjava%3Aos%7D' 

Apache Log4j 2, Boom!%    

可以看到请求被过滤掉了,返回了自定义的信息。

还有一些其他测试命令,大家也可以试试:

#{java:vm}
~%  curl 'https://localhost:9200/index/_search?q=%24%7Bjava%3Avm%7D'
[2021-12-11T02:36:04,764][DEBUG][r.suppressed             ] [INFINI-2.local] path: /index/_search, params: {q=OpenJDK 64-Bit Server VM (build 25.72-b15, mixed mode), index=index}

~%  curl 'https://localhost:8000/index/_search?q=%24%7Bjava%3Avm%7D'
Apache Log4j 2, Boom!% 

#{jndi:rmi://localhost:1099/api}
~%  curl 'https://localhost:9200/index/_search?q=%24%7Bjndi%3Armi%3A%2F%2Flocalhost%3A1099%2Fapi%7D'
2021-12-11 03:35:06,493 elasticsearch[YOmFJsW][search][T#3] ERROR An exception occurred processing Appender console java.lang.SecurityException: attempt to add a Permission to a readonly Permissions object

~%  curl 'https://localhost:8000/index/_search?q=%24%7Bjndi%3Armi%3A%2F%2Flocalhost%3A1099%2Fapi%7D'
Apache Log4j 2, Boom!% 

另外不同版本的 Elasticsearch 对于攻击的复现程度参差不齐,因为 es 不同版本是否有 Java Security Manager 、不同版本 JDK 、以及默认配置也不相同,新一点的 es 其实同样可以触发恶意请求,只不过网络调用被默认的网络策略给拒绝了,相对安全,当然如果设置不当同样存在风险,见过很多用户一上来就关默认安全配置的,甚至还放开很多暂时用不上的权限,另外未知的攻击方式也一定有,比如大量日志产生的系统调用可能会拖垮机器造成服务不可用,所以要么还是尽快改配置换 log4j 包重启集群,或者走网关来过滤阻断请求吧。

使用极限网关处置类似安全事件的好处是,Elasticsearch 服务器不用做任何变动,尤其是大规模集群的场景,可以节省大量的工作,提升效率,非常灵活,缩短安全处置的时间,降低企业风险。

继续阅读 »

昨日爆出的 Log4j 安全漏洞,业界一片哗然,今天给大家介绍一下,如何使用极限网关来快速处置 Elasticsearch 的 Apache Log4j 漏洞。

【CVE 地址】

【漏洞描述】

Apache Log4j 是一款非常流行的开源的用于 Java 运行环境的日志记录工具包,大量的 Java 框架包括 Elasticsearch 的最新版本都使用了该组件,故影响范围非常之大。

近日, 随着 Apache Log4j 的远程代码执行最新漏洞细节被公开,攻击者可通过构造恶意请求利用该漏洞实现在目标服务器上执行任意代码。可导致服务器被黑客控制,从而进行页面篡改、数据窃取、挖矿、勒索等行为。建议使用该组件的用户第一时间启动应急响应进行修复。

简单总结一下就是,在使用 Log4j 打印输出的日志中,如果发现日志内容中包含关键词 ${,那么这个里面包含的内容会当做变量来进行替换和执行,导致攻击者可以通过恶意构造日志内容来让 Java 进程来执行任意命令,达到攻击的效果。

【漏洞等级】:非常紧急

此次漏洞是用于 Log4j2 提供的 lookup 功能造成的,该功能允许开发者通过一些协议去读取相应环境中的配置。但在实现的过程中,并未对输入进行严格的判断,从而造成漏洞的发生。

【影响范围】:Java 类产品:Apache Log4j 2.x < 2.15.0-rc2,Elasticsearch 当前所有版本。

【攻击检测】

可以通过检查日志中是否存在 jndi:ldap://jndi:rmi 等字符来发现可能的攻击行为。

处理办法

最简单的办法是通过修改 config/jvm.options,新增以下参数,重启集群所有节点即可。

 -Dlog4j2.formatMsgNoLookups=true

不过,如果集群规模较大,数据较多,业务不能中断,不能通过修改 Elasticsearch 配置、或者替换 Log4j 的最新 jar 包来重启集群的情况,可以考虑使用极限网关来进行拦截或者参数替换甚至是直接阻断请求。

通过在网关层对发往 Elasticsearch 的请求统一进行参数检测,将包含的敏感关键词 ${ 进行替换或者直接拒绝, 可以防止带攻击的请求到达 Elasticsearch 服务端而被 Log4j 打印相关日志的时候执行恶意攻击命令,从而避免被攻击。

极限网关是透明代理,只需要在应用端,将以往配置指向 Elasticsearch 的地址替换为现在网关的地址即可,其他都不用动。

参考配置

下载最新的 1.5.0-SNAPSHOT 版本https://release.www.ksh17j.com/gateway/snapshot/

使用极限网关的 context_filter 过滤器,对请求上下文 _ctx.request.to_string 进行关键字检测,过滤掉恶意流量,从而阻断攻击。

新增一个配置文件 gateway.yml

path.data: data
path.logs: log

entry:
  - name: es_entrypoint
    enabled: true
    router: default
    max_concurrency: 20000
    network:
      binding: 0.0.0.0:8000

router:
  - name: default
    default_flow: main_flow

flow:
  - name: main_flow
    filter:
      - context_filter:
          context: _ctx.request.to_string
          action: redirect_flow
          status: 403
          flow: log4j_matched_flow
          must_not: # any match will be filtered
            regex:
              - \$\{.*?\}
              - "%24%7B.*?%7D" #urlencode
            contain:
              - "jndi:"
              - "jndi:ldap:"
              - "jndi:rmi:"
              - "jndi%3A" #urlencode
              - "jndi%3Aldap%3A" #urlencode
              - "jndi%3Armi%3A" #urlencode
      - elasticsearch:
          elasticsearch: es-server
  - name: log4j_matched_flow
    filter:
      - echo:
          message: 'Apache Log4j 2, Boom!'

elasticsearch:
  - name: es-server
    enabled: true
    endpoints:
      - https://localhost:9200

启动网关:

➜  ./bin/gateway -config /tmp/gateway.yml
   ___   _   _____  __  __    __  _       
  / _ \ /_\ /__   \/__\/ / /\ \ \/_\ /\_/\
 / /_\///_\\  / /\/_\  \ \/  \/ //_\\\_ _/
/ /_\\/  _  \/ / //__   \  /\  /  _  \/ \ 
\____/\_/ \_/\/  \__/    \/  \/\_/ \_/\_/ 

[GATEWAY] A light-weight, powerful and high-performance elasticsearch gateway.
[GATEWAY] 1.0.0_SNAPSHOT, 2021-12-10 23:55:34, 2212aff
[12-11 01:55:49] [INF] [app.go:250] initializing gateway.
[12-11 01:55:49] [INF] [instance.go:26] workspace: /Users/medcl/go/src/infini.sh/gateway/data/gateway/nodes/0
[12-11 01:55:49] [INF] [api.go:261] api listen at: https://0.0.0.0:2900
[12-11 01:55:49] [INF] [reverseproxy.go:253] elasticsearch [es-server] hosts: [] => [localhost:9200]
[12-11 01:55:49] [INF] [entry.go:296] entry [es_entrypoint] listen at: https://0.0.0.0:8000
[12-11 01:55:49] [INF] [module.go:116] all modules started
[12-11 01:55:49] [INF] [app.go:357] gateway is running now.
[12-11 01:55:49] [INF] [actions.go:236] elasticsearch [es-server] is available

将要使用的测试命令 ${java:os} 使用 urlencode 转码为 %24%7Bjava%3Aos%7D,构造查询语句,分别测试。

不走网关:

~%  curl 'https://localhost:9200/index1/_search?q=%24%7Bjava%3Aos%7D' 
{"error":{"root_cause":[{"type":"index_not_found_exception","reason":"no such index","resource.type":"index_or_alias","resource.id":"index1","index_uuid":"_na_","index":"index1"}],"type":"index_not_found_exception","reason":"no such index","resource.type":"index_or_alias","resource.id":"index1","index_uuid":"_na_","index":"index1"},"status":404}%   

查看 Elasticsearch 端日志为:

[2021-12-11T01:49:50,303][DEBUG][r.suppressed             ] path: /index1/_search, params: {q=Mac OS X 10.13.4 unknown, architecture: x86_64-64, index=index1}
org.elasticsearch.index.IndexNotFoundException: no such index
    at org.elasticsearch.cluster.metadata.IndexNameExpressionResolver$WildcardExpressionResolver.infe(IndexNameExpressionResolver.java:678) ~[elasticsearch-5.6.15.jar:5.6.15]
    at org.elasticsearch.cluster.metadata.IndexNameExpressionResolver$WildcardExpressionResolver.innerResolve(IndexNameExpressionResolver.java:632) ~[elasticsearch-5.6.15.jar:5.6.15]
    at org.elasticsearch.cluster.metadata.IndexNameExpressionResolver$WildcardExpressionResolver.resolve(IndexNameExpressionResolver.java:580) ~[elasticsearch-5.6.15.jar:5.6.15]

可以看到查询条件里面的 q=${java:os} 被执行了,变成了 q=Mac OS X 10.13.4 unknown, architecture: x86_64-64, index=index1,说明变量被解析且执行,存在漏洞利用的风险。

那走网关之后呢:

~%  curl 'https://localhost:8000/index1/_search?q=%24%7Bjava%3Aos%7D' 

Apache Log4j 2, Boom!%    

可以看到请求被过滤掉了,返回了自定义的信息。

还有一些其他测试命令,大家也可以试试:

#{java:vm}
~%  curl 'https://localhost:9200/index/_search?q=%24%7Bjava%3Avm%7D'
[2021-12-11T02:36:04,764][DEBUG][r.suppressed             ] [INFINI-2.local] path: /index/_search, params: {q=OpenJDK 64-Bit Server VM (build 25.72-b15, mixed mode), index=index}

~%  curl 'https://localhost:8000/index/_search?q=%24%7Bjava%3Avm%7D'
Apache Log4j 2, Boom!% 

#{jndi:rmi://localhost:1099/api}
~%  curl 'https://localhost:9200/index/_search?q=%24%7Bjndi%3Armi%3A%2F%2Flocalhost%3A1099%2Fapi%7D'
2021-12-11 03:35:06,493 elasticsearch[YOmFJsW][search][T#3] ERROR An exception occurred processing Appender console java.lang.SecurityException: attempt to add a Permission to a readonly Permissions object

~%  curl 'https://localhost:8000/index/_search?q=%24%7Bjndi%3Armi%3A%2F%2Flocalhost%3A1099%2Fapi%7D'
Apache Log4j 2, Boom!% 

另外不同版本的 Elasticsearch 对于攻击的复现程度参差不齐,因为 es 不同版本是否有 Java Security Manager 、不同版本 JDK 、以及默认配置也不相同,新一点的 es 其实同样可以触发恶意请求,只不过网络调用被默认的网络策略给拒绝了,相对安全,当然如果设置不当同样存在风险,见过很多用户一上来就关默认安全配置的,甚至还放开很多暂时用不上的权限,另外未知的攻击方式也一定有,比如大量日志产生的系统调用可能会拖垮机器造成服务不可用,所以要么还是尽快改配置换 log4j 包重启集群,或者走网关来过滤阻断请求吧。

使用极限网关处置类似安全事件的好处是,Elasticsearch 服务器不用做任何变动,尤其是大规模集群的场景,可以节省大量的工作,提升效率,非常灵活,缩短安全处置的时间,降低企业风险。

收起阅读 »

Elasticsearch 内存占用分析及 page cache 监控

前言

对于广大 Elasticsearch 使用者而言,在面对系统资源分配、问题请求排查时是否曾遇到以下问题:

  • 只知道需要预留许多内存资源给 lucene(一般为系统资源的一半),但是分配的这些是否够用,以及这些内存资源被什么文件所占用,往往都不得而知;
  • 线上服务突然出现一波超时告警,告警波及的索引面积较广,但波动具体由哪个索引,甚至哪个查询导致的,在排查时容易陷入无从下手的困境。

通常在 Elasticsearch 的监控层面,我们会选择去查看 kibana 的监控报表,但 kibana 在内存方面的监控指标通常都基于 JVM 本身,无法追溯到 lucene 层面。而 lucene 的文件使用的是操作系统的 page cache,如何监控 page cache,并将之映射到 Elasticsearch 的索引维度,便是本文着手解决的问题。 ​

接下来本文将分为三个主要部分,第一部分介绍和 Elasticsearch 内存使用相关的基础知识,适合对 ES 内存资源占用有兴趣的同学,第二部分介绍 Elasticsearch 的 page cache 监控工具和使用说明,第三部分列举一些典型的使用案例。

基础知识

对搜索引擎而言,各级缓存的命中率和查询效率密切相关。ES 的缓存主要由 JVM 堆内存,以及 lucene 所依赖的堆外内存两部分组成。考虑到大多数查询场景的多样性,ES 的 query cache 覆盖能力有限,因此 ES 的查询性能和 lucene 各类文件的缓存状况息息相关,能否通过 page cache 尽量减少查询过程中产生的文件IO 将直接影响到查询效率。本节将从 Elasticsearch 内存分布,lucene 文件类型和使用场景,文件读取方式几个层面展开介绍。

Elasticsearch 内存相关

ES 进程的 JVM 堆内存主要包括以下几部分内容(不详细展开)

  • Indexing Buffer:索引缓冲区,用于存储新索引的文档,当其达到阈值时,会触发 ES flush 将段落到磁盘上;
  • Fielddata:用于 text 字段分词或排序时获取字段值,基于 lucene 的 segment 构建,伴随 segment 生命周期常驻在堆内存中。
  • Node Query Cache:负责缓存 filter 查询结果,基于 lucene 的 segment 构建,缓存在堆内存中,ES 节点默认的 cache 大小为堆内存的10%,采用LRU机制。
  • Shard Request Cache:针对 ES 的 query 请求,缓存各分片的查询结果,主要用于缓存聚合结果,采用LRU机制,当分片 refresh 后会失效。

对于 lucene 而言,其使用的是堆外内存

  • Page Cache:lucene 读写段文件时会依赖操作系统的 page cache 缓存,如果多次查询都涉及到读取某个段文件的同一部分内容,就直接使用 page cache 进行读取,无需再从磁盘获取数据。page cahce 由操作系统管理,淘汰策略类似LRU。

    lucene 文件类型

    ES 的一个分片就是一个 lucene 实例,实例由一个或多个 segment 构成。lucene 每次 flush 操作都会对一个 segment 进行持久化操作(会将内存中的 segment 写到文件,但不执行 FileChannel::force,即存在数据丢失的可能),其内容为期间有变更的文档,同一个段涉及到的文件前缀都是相同的 generation(36进制的一个数字,每次 flush 会加一),每个段可能涉及到的文件如下表所示。

文件后缀 存放信息 关联 ES 的查询场景
.tip 词典的fst,以及到.tim的索引 term查询、全文搜索等场景
.tim 存放term info以及指向.doc、.pos、.pay的指针 term查询、全文搜索等场景
.doc 倒排表及词频
.pos 记录term的位置信息 match_pharse等需要位置信息的查询
.pay payload信息
.fdt 存放原始文档,正向存储 获取source等字段值
.fdx fdt的索引
.dvd DocValues 列式存储 聚合、排序、脚本等场景
数值类型的range查询
.dvm .dvd的索引
.nvd Norms data 全文搜索的tfNorms计算
.nvm .nvd的索引
.dim 数值类型的索引,BKD树结构 数值类型的range查询
.dii .dim的索引
.liv 记录被删除的文档号
.cfs 复合文件 新写入数据生成的段文件,引入该文件主要用于减少文件句柄数
.cfe 复合文件,.cfs的索引
.si 记录段的元信息

lucene 文件功能说明备注

  • tip 和 fdx 类型的文件在 ES 7.3 以前都是常驻 JVM 堆内存的,ES 7.3 之后将 fst 移至堆外,交由系统的 page cache 管理,若某个索引的 fst cache 不幸被置换出去,理论上会给搜索带来较大的抖动,对于使用 7.x 版本的用户,建议多关注 tip 文件的 cache 情况;
  • 上述文件中占用存储空间较多的是 tim、doc、fdt、dvd 以及 cfs 这几类数据文件,除 cfs 以外的几类文件加载情况和查询条件密切相关;
  • range 查询即可能使用 dim BKD 索引,也可能使用 dvd DocValue,其背后是一个基于代价的优化器处理逻辑 ,如有兴趣,细节逻辑可自行参考 IndexOrDocValuesQuery。

    lucene 文件读取方式

    lucene 文件的读取方式将影响磁盘 IO 调用,以及 page cache 中缓存的内容,常用的主要是如下两种类型:

  • niofs:通过 NIO 的方式读取文件内容,基于 Java 提供的 FileChannel::read 方法读取数据,支持多线程读取同一个文件,按需读取,需要注意的是 niofs 模式下读取到的内容在系统层面也会进 page cache。
  • mmapfs:通过mmap读写文件,会比常规文件读写方式减少一次内存拷贝的过程,因此对于命中 page cache 的文件读取会非常快,该模式即零拷贝的一种实现(可减少内核态和用户态间的数据拷贝)。不过 mmap 系统调用在内核层面会产生预读,对于 .fdt 这类文件,预读读到的内容后续命中的概率极低,还容易引起page cache的争用,进而产生频繁的缺页中断,相关问题可参考

ES 支持通过 index.store.type 设定文件加载方式

  • ES 6.*版本默认为 mmapfs
  • ES 7.0开始默认为 hybridfs,该模式下每类文件会选择最优的读取方式,例如 .doc 由于倒排表的缓存命中率较高,被设定为 mmapfs,而 .fdt 只在获取 _source 时使用,访问较为稀疏,被设定为 niofs。

    工具使用说明

    综上所述,lucene 各类文件占用 page cache 的情况将极大的影响 Elasticsearch 的查询效率,如何系统的监控各类文件在 page cache 中的占用,以及换入换出的波动,将为 ES 的资源分析和性能监控提供一种新的角度。 ​

如果想采集系统的 page cache,可以借助 pcstat、vmtouch 等工具,其实现原理均是通过 mincore(2) 系统调用,mincore能确定一块虚拟内存区域中的分页是否驻留在物理内存中。其中 pcstat 是款基于Go的开源工具(),开发初衷是用于监控 Cassandra 中 ssTables 的占用情况。 ​

本工具 es-pcstat 基于 pcstat 进行二次开发,以 ES 索引为维度,细化到 lucene 文件的粒度来对 page cache 占用情况进行采集,可对cfs、fdt、doc、pos、tim、dvd等重要文件进行细粒度的采集和监控。支持数据输出到控制台、日志、ES,配套kibana仪表盘支持查看各索引、各类文件的时序变化曲线。

源码地址

功能点

采集目标:ES索引下各类 lucene 文件的 page cache 占用,单位MB,默认采集全部索引,支持配置采集的索引前缀。 ​

运行环境

  • 系统环境: 类unix、linux环境
  • ES 版本:6.x、7.x

功能项

  • 数据输出:控制台、日志和ES
    • 控制台:查看各索引 cache,支持排序
    • 日志和ES:采集维度从上到下依次为 节点->索引->主副分片->文件后缀
  • 可视化:数据输出为 ES 时,支持 kibana 仪表盘配置
    • 支持按节点、索引、主副分片类型筛选查看
    • 支持查看索引 page cache top10 波动曲线

获取可执行文件

linux_x64

linux 64位可通过如下命令获取可执行文件

curl -L -o es-pcstat https://gitee.com/verdant/es-pcstat/attach_files/835465/download/es-pcstat-linux-x64
chmod 755 es-pcstat

mac

mac 64位可通过如下命令获取可执行文件

curl -L -o es-pcstat https://gitee.com/verdant/es-pcstat/attach_files/835463/download/es-pcstat-darwin-x64
chmod 755 es-pcstat

运行

执行命令

./es-pcstat [parameters] <config_file>

例:./es-pcstat -collectIntervalFlag=30 -sortFlag=true ./es.conf

运行可选参数

  -collectIntervalFlag int
        采集间隔 (default 60)
  -outputTypeFlag string
        数据输出方式 [es, log, console] (default "console")
  -sortFlag
        仅对console类型生效,结果按page cache大小排序

配置文件

配置文件需填写es ip、端口、节点名、集群名和数据目录,其中path需要填写indices目录,一般为es的 data.path配置后增加"/nodes/0/indices"。

名称 描述 默认值
es.ip 采集的es节点ip
es.port 采集的es节点端口
es.indicesPath 采集的es节点indices目录,一般为"${data.path}/nodes/0/indices"
es.nodeName 采集的es节点名
es.clusterName 采集的es集群名
es.collection.indicesPrefix 需采集的索引名前缀,不填则采集全部;样例:pcstat
output.log.keepLogNum 针对日志形式输出生效,保留日志文件个数(按天拆分) 5
output.log.logPath 针对日志形式输出生效,日志全路径 /tmp/pcstat.log
output.es.keepIndexNum 针对es输出生效,保留索引个数(按天拆分) 5
output.es.pcIndexName 针对es输出生效,索引名(如需使用kibana仪表盘配置请勿修改) pc_stat
#es conf
es.ip=127.0.0.1
es.port=9200
es.indicesPath=/xxx/xxx/elasticsearch-6.7.1/data/nodes/0/indices
es.nodeName=node1
es.clusterName=es_local

#采集索引前缀,设置为空则采集全部
es.collection.indicesPrefix=

#该配置仅日志输出生效 output log,保留个数单位为天
output.log.keepLogNum=5
output.log.logPath=/tmp/pcstat.log

#该配置仅es输出生效 output es,保留个数单位为天
output.es.keepIndexNum=5
output.es.pcIndexName=pc_stat

输出模式

控制台输出

执行命令

./es-pcstat -collectIntervalFlag=30 -sortFlag=true ./es.conf

结果示例


| index_name                            | cache (MB) | pri cache  | rep cache  |
+---------------------------------------+------------+------------+------------+
| fusion-media.task.task                |  247       |  247       |  0         |
| total                                 |  247       |  247       |  0         |
+---------------------------------------+------------+------------+------------+

日志输出

执行命令

./es-pcstat -outputTypeFlag=log ./es.conf

对应日志文件得到的内容,日志可进一步通过日志服务采集分析(如阿里云sls等)

{"cache":{"cfs":0,"dim":0,"doc":0,"dvd":0,"fdt":0,"nvd":0,"other":0,"pos":0,"tim":0,"total":0},"cluster_name":"es_local","fields.time":"2021-05-06T15:16:30.525475+08:00","index_name":"total","level":"info","msg":"","node_name":"node1","primary":false,"time":"2021-05-06T15:16:30"}

ES 输出

执行命令

./es-pcstat -outputTypeFlag=es ./es.conf

运行后会将采集到的数据回写到被监控的 ES 集群 可导入kibana仪表盘配置文件,通过图表进行page cache分析。 ​

导入方式

image-2.png
图1 kibana导入仪表盘配置 ​

导入后打开dashboards菜单栏,page_cache仪表盘

image-3.png
图2 kibana仪表盘入口 ​

细节可查看如下图表 1)cache占用top10的索引波动图

image-4.png
图3 kibana仪表盘-cache top10

2)cache详细信息,可筛选节点、索引、主副分片,不选择展示合计数据。

image-5.png
图4 kibana仪表盘-cache占用详情

备注

  • 如需使用上述kibana仪表盘导入文件,请勿修改conf文件中的output.es.pcIndexName以及运行命令的collectIntervalFlag,修改output.es.pcIndexName会导致仪表盘读不到数据,修改collectIntervalFlag会导致仪表盘聚合数据异常;
  • kibana7.5后Date Histogram的interval有所调整,会导致时间拉长后interval成倍增大,统计值不准,建议选取时间范围在4-6小时内,https://www.ksh17j.com/question/11062

    使用案例

    通过 es-pcstat 采集得到的 page cache 时序图,可为性能监控、资源分析、异常请求定位等问题提供一定帮助,以下将从笔者团队使用中的几个案例进行展开。 ​

一个简单示例:每条横线代表一个索引的所有 lucene 文件资源占用,一小时内的采样可以发现两个转折点

  • 1 触发了副本清0操作,由于该集群副本不涉及搜索,所占用的内存比例较少
  • 2 触发了一些查询请求,部分索引所占资源上涨

image-6.png
图5 索引资源波动-基于阿里云sls仪表盘

案例一:资源分析

通过观察一段时间的资源波动可评估预留给 lucene 的 page cache 是否充裕,如下两张图展示了两个集群中单个节点一天的资源占用情况,图6资源较为充裕,整体趋势几乎无大的波动,图7资源较为紧张,频繁出现 page cache 的换入换出。

image-7.png
图6 索引内存资源评估-充足

image-8.png
图7 索引内存资源评估-不足

案例二:merge的影响

如图8所示,通过监控可以发现某个索引的 page cache 上涨非常明显,导致其他索引的资源被换出,这种抢占会导致搜索服务波动;通过kibana排查该时间段内该索引的监控,发现段的数量有所下降,查看段文件后发现在该时间段后生成了几个较大的段文件,判定是 merge 导致 page cache 上涨,通过图9可以看到 merge 过程中 fdt 文件的上涨尤其明显(主要因为 merge 需要 load 原始内容进行处理),merge 完成后 fdt 的 cache 会慢慢的换出。 ​

由于采用了存储计算分离的架构,后续可考虑将数据规模达到一定阈值的 merge 操作移到专属的 merge 节点处理,以此减少 merge 引起的 cache 换入换出对搜索服务节点带来的波动。

image-9.png
图8 整体资源波动,某个索引资源迅速上涨

image-10.png
图9 引起问题的索引波动,fdt上涨尤为明显

案例三:异常查询请求定位

有时集群的整体响应突然变慢,却不知道是由哪个索引、或哪个查询引起的? ​

例如某天一个 ES 集群突然出现大量超时请求,查看节点监控,ygc有所下降,cpu利用率一直在高位;再查看磁盘监控,发现磁盘读吞吐处于高负荷状态。

image-11.png
图10 异常请求引起的磁盘IO满负荷

通过这些常规的监控无法进一步定位到异常原因,再来看看 page cache 的监控。根据“索引cache top N”图表可以明显发现异常时间点有个索引的cache大幅度上涨,其他索引的 cache 都有所下降,在异常时间段内,曲线的毛刺极为明显,由此可以判断是堆外内存不够,导致各索引的 page cache 出现争用,进而需要从磁盘上获取数据。

image-12.png
图11 索引内存资源占用波动-top10 ​

再进一步查看 cache 上涨期间问题索引各类文件的 cache 情况,可看到 doc和pos 有明显上涨,doc文件存储倒排表及词频,由包含每个 term 以及频率的 docs 列表组成,pos 存储出现在索引中 term 的位置信息。二者在 phrase 查询中会被联合使用。当一个平时使用率不高的索引突然出现了大量的 phrase 查询,内存资源比较吃紧(该节点预留给堆外的只有7 GB),进而就产生了上述问题。

image-13.png
图12 索引内存资源占用波动-异常索引详情 ​

对于某些突发的,却给集群造成较大压力的请求,可以尝试通过 page cache 监控去排查定位。 ​

当然要把具体的 lucene 文件类型变化趋势和查询关联起来,需要对各类查询涉及的文件有一定了解,相关细节可查看“基础知识->lucene 文件类型”一节,典型的如

  • dvd 上涨可以猜测是有聚合、脚本、排序的请求
  • doc、pos上涨可以联想到是否有 phrase 查询请求
  • fdt 上涨可能涉及大量的源数据拉取或 merge 操作

案例四:为性能优化制定方向

随着系统的发展、数据量的增长,在某个业务场景 ES 相关的资源和效率可能逐渐成为瓶颈,这时候我们就需要从底层视角来推动上层的优化,如图13所示,根据监控曲线可发现 fdt、doc、pos 几类文件的常驻内存资源较多,便可从这3类文件的使用情况出发来制定优化方向:

  • fdt 常用于获取_source字段的内容,如果存储并在查询结果中获取大量字段很容易导致该文件频繁访问,进而占用较多资源,可以考虑对 _source 进行适当删减,或将数据获取逻辑移至宽表数据库,如HBase等,让 ES 的资源更多的用于搜索本身;
  • doc 在 term 和全文搜索场景均有使用,这类文件的加载通常不可避免,可以从降低文件大小来入手,如在分词层面进行优化,对词的分布进行统计分析,来评估是否可以补充停用词等;
  • pos 用于需要位置信息的 phrase 查询,可从查询语句的拼装进行优化。

image-14.png
图13 观察内存资源占用来制定优化方向 ​

总结及未来展望

es-pcstat 从 ES 索引和 lucene 各类文件 page cache 占用的角度,提供了一种对 ES 进行监控的全新思路,基于这些监控数据我们可以进行资源的饱和度评估,异常查询请求的定位,或者为性能优化制定方向。 ​

当然异常请求的定位都只能限于事后分析,无法避免问题的产生,如何通过监控数据和查询请求去评估一个 query 可能对集群产生的影响,并拦截可能导致较大 page cache 争用的请求,这将能为集群的稳定性提供更大的保障。 ​

es-pcstat 采集细化到了 lucene 文件的粒度,需要具备一定基础知识和经验才能快速定位背后原因,因此在分析上具备一定门槛,如果能根据文件波动来为监控者提供一些 ES 层面的提示,将能服务更广大的 ES 用户。 ​

在 ES 中对一个查询的成本(涉及JVM中的缓存、系统内存缺页中断、IO、CPU等)进行评估本身是一件比较难的事,page cache 的监控可能能提供一定的帮助,当然还有更多的作用等待我们去探索。

参考链接



继续阅读 »

前言

对于广大 Elasticsearch 使用者而言,在面对系统资源分配、问题请求排查时是否曾遇到以下问题:

  • 只知道需要预留许多内存资源给 lucene(一般为系统资源的一半),但是分配的这些是否够用,以及这些内存资源被什么文件所占用,往往都不得而知;
  • 线上服务突然出现一波超时告警,告警波及的索引面积较广,但波动具体由哪个索引,甚至哪个查询导致的,在排查时容易陷入无从下手的困境。

通常在 Elasticsearch 的监控层面,我们会选择去查看 kibana 的监控报表,但 kibana 在内存方面的监控指标通常都基于 JVM 本身,无法追溯到 lucene 层面。而 lucene 的文件使用的是操作系统的 page cache,如何监控 page cache,并将之映射到 Elasticsearch 的索引维度,便是本文着手解决的问题。 ​

接下来本文将分为三个主要部分,第一部分介绍和 Elasticsearch 内存使用相关的基础知识,适合对 ES 内存资源占用有兴趣的同学,第二部分介绍 Elasticsearch 的 page cache 监控工具和使用说明,第三部分列举一些典型的使用案例。

基础知识

对搜索引擎而言,各级缓存的命中率和查询效率密切相关。ES 的缓存主要由 JVM 堆内存,以及 lucene 所依赖的堆外内存两部分组成。考虑到大多数查询场景的多样性,ES 的 query cache 覆盖能力有限,因此 ES 的查询性能和 lucene 各类文件的缓存状况息息相关,能否通过 page cache 尽量减少查询过程中产生的文件IO 将直接影响到查询效率。本节将从 Elasticsearch 内存分布,lucene 文件类型和使用场景,文件读取方式几个层面展开介绍。

Elasticsearch 内存相关

ES 进程的 JVM 堆内存主要包括以下几部分内容(不详细展开)

  • Indexing Buffer:索引缓冲区,用于存储新索引的文档,当其达到阈值时,会触发 ES flush 将段落到磁盘上;
  • Fielddata:用于 text 字段分词或排序时获取字段值,基于 lucene 的 segment 构建,伴随 segment 生命周期常驻在堆内存中。
  • Node Query Cache:负责缓存 filter 查询结果,基于 lucene 的 segment 构建,缓存在堆内存中,ES 节点默认的 cache 大小为堆内存的10%,采用LRU机制。
  • Shard Request Cache:针对 ES 的 query 请求,缓存各分片的查询结果,主要用于缓存聚合结果,采用LRU机制,当分片 refresh 后会失效。

对于 lucene 而言,其使用的是堆外内存

  • Page Cache:lucene 读写段文件时会依赖操作系统的 page cache 缓存,如果多次查询都涉及到读取某个段文件的同一部分内容,就直接使用 page cache 进行读取,无需再从磁盘获取数据。page cahce 由操作系统管理,淘汰策略类似LRU。

    lucene 文件类型

    ES 的一个分片就是一个 lucene 实例,实例由一个或多个 segment 构成。lucene 每次 flush 操作都会对一个 segment 进行持久化操作(会将内存中的 segment 写到文件,但不执行 FileChannel::force,即存在数据丢失的可能),其内容为期间有变更的文档,同一个段涉及到的文件前缀都是相同的 generation(36进制的一个数字,每次 flush 会加一),每个段可能涉及到的文件如下表所示。

文件后缀 存放信息 关联 ES 的查询场景
.tip 词典的fst,以及到.tim的索引 term查询、全文搜索等场景
.tim 存放term info以及指向.doc、.pos、.pay的指针 term查询、全文搜索等场景
.doc 倒排表及词频
.pos 记录term的位置信息 match_pharse等需要位置信息的查询
.pay payload信息
.fdt 存放原始文档,正向存储 获取source等字段值
.fdx fdt的索引
.dvd DocValues 列式存储 聚合、排序、脚本等场景
数值类型的range查询
.dvm .dvd的索引
.nvd Norms data 全文搜索的tfNorms计算
.nvm .nvd的索引
.dim 数值类型的索引,BKD树结构 数值类型的range查询
.dii .dim的索引
.liv 记录被删除的文档号
.cfs 复合文件 新写入数据生成的段文件,引入该文件主要用于减少文件句柄数
.cfe 复合文件,.cfs的索引
.si 记录段的元信息

lucene 文件功能说明备注

  • tip 和 fdx 类型的文件在 ES 7.3 以前都是常驻 JVM 堆内存的,ES 7.3 之后将 fst 移至堆外,交由系统的 page cache 管理,若某个索引的 fst cache 不幸被置换出去,理论上会给搜索带来较大的抖动,对于使用 7.x 版本的用户,建议多关注 tip 文件的 cache 情况;
  • 上述文件中占用存储空间较多的是 tim、doc、fdt、dvd 以及 cfs 这几类数据文件,除 cfs 以外的几类文件加载情况和查询条件密切相关;
  • range 查询即可能使用 dim BKD 索引,也可能使用 dvd DocValue,其背后是一个基于代价的优化器处理逻辑 ,如有兴趣,细节逻辑可自行参考 IndexOrDocValuesQuery。

    lucene 文件读取方式

    lucene 文件的读取方式将影响磁盘 IO 调用,以及 page cache 中缓存的内容,常用的主要是如下两种类型:

  • niofs:通过 NIO 的方式读取文件内容,基于 Java 提供的 FileChannel::read 方法读取数据,支持多线程读取同一个文件,按需读取,需要注意的是 niofs 模式下读取到的内容在系统层面也会进 page cache。
  • mmapfs:通过mmap读写文件,会比常规文件读写方式减少一次内存拷贝的过程,因此对于命中 page cache 的文件读取会非常快,该模式即零拷贝的一种实现(可减少内核态和用户态间的数据拷贝)。不过 mmap 系统调用在内核层面会产生预读,对于 .fdt 这类文件,预读读到的内容后续命中的概率极低,还容易引起page cache的争用,进而产生频繁的缺页中断,相关问题可参考

ES 支持通过 index.store.type 设定文件加载方式

  • ES 6.*版本默认为 mmapfs
  • ES 7.0开始默认为 hybridfs,该模式下每类文件会选择最优的读取方式,例如 .doc 由于倒排表的缓存命中率较高,被设定为 mmapfs,而 .fdt 只在获取 _source 时使用,访问较为稀疏,被设定为 niofs。

    工具使用说明

    综上所述,lucene 各类文件占用 page cache 的情况将极大的影响 Elasticsearch 的查询效率,如何系统的监控各类文件在 page cache 中的占用,以及换入换出的波动,将为 ES 的资源分析和性能监控提供一种新的角度。 ​

如果想采集系统的 page cache,可以借助 pcstat、vmtouch 等工具,其实现原理均是通过 mincore(2) 系统调用,mincore能确定一块虚拟内存区域中的分页是否驻留在物理内存中。其中 pcstat 是款基于Go的开源工具(),开发初衷是用于监控 Cassandra 中 ssTables 的占用情况。 ​

本工具 es-pcstat 基于 pcstat 进行二次开发,以 ES 索引为维度,细化到 lucene 文件的粒度来对 page cache 占用情况进行采集,可对cfs、fdt、doc、pos、tim、dvd等重要文件进行细粒度的采集和监控。支持数据输出到控制台、日志、ES,配套kibana仪表盘支持查看各索引、各类文件的时序变化曲线。

源码地址

功能点

采集目标:ES索引下各类 lucene 文件的 page cache 占用,单位MB,默认采集全部索引,支持配置采集的索引前缀。 ​

运行环境

  • 系统环境: 类unix、linux环境
  • ES 版本:6.x、7.x

功能项

  • 数据输出:控制台、日志和ES
    • 控制台:查看各索引 cache,支持排序
    • 日志和ES:采集维度从上到下依次为 节点->索引->主副分片->文件后缀
  • 可视化:数据输出为 ES 时,支持 kibana 仪表盘配置
    • 支持按节点、索引、主副分片类型筛选查看
    • 支持查看索引 page cache top10 波动曲线

获取可执行文件

linux_x64

linux 64位可通过如下命令获取可执行文件

curl -L -o es-pcstat https://gitee.com/verdant/es-pcstat/attach_files/835465/download/es-pcstat-linux-x64
chmod 755 es-pcstat

mac

mac 64位可通过如下命令获取可执行文件

curl -L -o es-pcstat https://gitee.com/verdant/es-pcstat/attach_files/835463/download/es-pcstat-darwin-x64
chmod 755 es-pcstat

运行

执行命令

./es-pcstat [parameters] <config_file>

例:./es-pcstat -collectIntervalFlag=30 -sortFlag=true ./es.conf

运行可选参数

  -collectIntervalFlag int
        采集间隔 (default 60)
  -outputTypeFlag string
        数据输出方式 [es, log, console] (default "console")
  -sortFlag
        仅对console类型生效,结果按page cache大小排序

配置文件

配置文件需填写es ip、端口、节点名、集群名和数据目录,其中path需要填写indices目录,一般为es的 data.path配置后增加"/nodes/0/indices"。

名称 描述 默认值
es.ip 采集的es节点ip
es.port 采集的es节点端口
es.indicesPath 采集的es节点indices目录,一般为"${data.path}/nodes/0/indices"
es.nodeName 采集的es节点名
es.clusterName 采集的es集群名
es.collection.indicesPrefix 需采集的索引名前缀,不填则采集全部;样例:pcstat
output.log.keepLogNum 针对日志形式输出生效,保留日志文件个数(按天拆分) 5
output.log.logPath 针对日志形式输出生效,日志全路径 /tmp/pcstat.log
output.es.keepIndexNum 针对es输出生效,保留索引个数(按天拆分) 5
output.es.pcIndexName 针对es输出生效,索引名(如需使用kibana仪表盘配置请勿修改) pc_stat
#es conf
es.ip=127.0.0.1
es.port=9200
es.indicesPath=/xxx/xxx/elasticsearch-6.7.1/data/nodes/0/indices
es.nodeName=node1
es.clusterName=es_local

#采集索引前缀,设置为空则采集全部
es.collection.indicesPrefix=

#该配置仅日志输出生效 output log,保留个数单位为天
output.log.keepLogNum=5
output.log.logPath=/tmp/pcstat.log

#该配置仅es输出生效 output es,保留个数单位为天
output.es.keepIndexNum=5
output.es.pcIndexName=pc_stat

输出模式

控制台输出

执行命令

./es-pcstat -collectIntervalFlag=30 -sortFlag=true ./es.conf

结果示例


| index_name                            | cache (MB) | pri cache  | rep cache  |
+---------------------------------------+------------+------------+------------+
| fusion-media.task.task                |  247       |  247       |  0         |
| total                                 |  247       |  247       |  0         |
+---------------------------------------+------------+------------+------------+

日志输出

执行命令

./es-pcstat -outputTypeFlag=log ./es.conf

对应日志文件得到的内容,日志可进一步通过日志服务采集分析(如阿里云sls等)

{"cache":{"cfs":0,"dim":0,"doc":0,"dvd":0,"fdt":0,"nvd":0,"other":0,"pos":0,"tim":0,"total":0},"cluster_name":"es_local","fields.time":"2021-05-06T15:16:30.525475+08:00","index_name":"total","level":"info","msg":"","node_name":"node1","primary":false,"time":"2021-05-06T15:16:30"}

ES 输出

执行命令

./es-pcstat -outputTypeFlag=es ./es.conf

运行后会将采集到的数据回写到被监控的 ES 集群 可导入kibana仪表盘配置文件,通过图表进行page cache分析。 ​

导入方式

image-2.png
图1 kibana导入仪表盘配置 ​

导入后打开dashboards菜单栏,page_cache仪表盘

image-3.png
图2 kibana仪表盘入口 ​

细节可查看如下图表 1)cache占用top10的索引波动图

image-4.png
图3 kibana仪表盘-cache top10

2)cache详细信息,可筛选节点、索引、主副分片,不选择展示合计数据。

image-5.png
图4 kibana仪表盘-cache占用详情

备注

  • 如需使用上述kibana仪表盘导入文件,请勿修改conf文件中的output.es.pcIndexName以及运行命令的collectIntervalFlag,修改output.es.pcIndexName会导致仪表盘读不到数据,修改collectIntervalFlag会导致仪表盘聚合数据异常;
  • kibana7.5后Date Histogram的interval有所调整,会导致时间拉长后interval成倍增大,统计值不准,建议选取时间范围在4-6小时内,https://www.ksh17j.com/question/11062

    使用案例

    通过 es-pcstat 采集得到的 page cache 时序图,可为性能监控、资源分析、异常请求定位等问题提供一定帮助,以下将从笔者团队使用中的几个案例进行展开。 ​

一个简单示例:每条横线代表一个索引的所有 lucene 文件资源占用,一小时内的采样可以发现两个转折点

  • 1 触发了副本清0操作,由于该集群副本不涉及搜索,所占用的内存比例较少
  • 2 触发了一些查询请求,部分索引所占资源上涨

image-6.png
图5 索引资源波动-基于阿里云sls仪表盘

案例一:资源分析

通过观察一段时间的资源波动可评估预留给 lucene 的 page cache 是否充裕,如下两张图展示了两个集群中单个节点一天的资源占用情况,图6资源较为充裕,整体趋势几乎无大的波动,图7资源较为紧张,频繁出现 page cache 的换入换出。

image-7.png
图6 索引内存资源评估-充足

image-8.png
图7 索引内存资源评估-不足

案例二:merge的影响

如图8所示,通过监控可以发现某个索引的 page cache 上涨非常明显,导致其他索引的资源被换出,这种抢占会导致搜索服务波动;通过kibana排查该时间段内该索引的监控,发现段的数量有所下降,查看段文件后发现在该时间段后生成了几个较大的段文件,判定是 merge 导致 page cache 上涨,通过图9可以看到 merge 过程中 fdt 文件的上涨尤其明显(主要因为 merge 需要 load 原始内容进行处理),merge 完成后 fdt 的 cache 会慢慢的换出。 ​

由于采用了存储计算分离的架构,后续可考虑将数据规模达到一定阈值的 merge 操作移到专属的 merge 节点处理,以此减少 merge 引起的 cache 换入换出对搜索服务节点带来的波动。

image-9.png
图8 整体资源波动,某个索引资源迅速上涨

image-10.png
图9 引起问题的索引波动,fdt上涨尤为明显

案例三:异常查询请求定位

有时集群的整体响应突然变慢,却不知道是由哪个索引、或哪个查询引起的? ​

例如某天一个 ES 集群突然出现大量超时请求,查看节点监控,ygc有所下降,cpu利用率一直在高位;再查看磁盘监控,发现磁盘读吞吐处于高负荷状态。

image-11.png
图10 异常请求引起的磁盘IO满负荷

通过这些常规的监控无法进一步定位到异常原因,再来看看 page cache 的监控。根据“索引cache top N”图表可以明显发现异常时间点有个索引的cache大幅度上涨,其他索引的 cache 都有所下降,在异常时间段内,曲线的毛刺极为明显,由此可以判断是堆外内存不够,导致各索引的 page cache 出现争用,进而需要从磁盘上获取数据。

image-12.png
图11 索引内存资源占用波动-top10 ​

再进一步查看 cache 上涨期间问题索引各类文件的 cache 情况,可看到 doc和pos 有明显上涨,doc文件存储倒排表及词频,由包含每个 term 以及频率的 docs 列表组成,pos 存储出现在索引中 term 的位置信息。二者在 phrase 查询中会被联合使用。当一个平时使用率不高的索引突然出现了大量的 phrase 查询,内存资源比较吃紧(该节点预留给堆外的只有7 GB),进而就产生了上述问题。

image-13.png
图12 索引内存资源占用波动-异常索引详情 ​

对于某些突发的,却给集群造成较大压力的请求,可以尝试通过 page cache 监控去排查定位。 ​

当然要把具体的 lucene 文件类型变化趋势和查询关联起来,需要对各类查询涉及的文件有一定了解,相关细节可查看“基础知识->lucene 文件类型”一节,典型的如

  • dvd 上涨可以猜测是有聚合、脚本、排序的请求
  • doc、pos上涨可以联想到是否有 phrase 查询请求
  • fdt 上涨可能涉及大量的源数据拉取或 merge 操作

案例四:为性能优化制定方向

随着系统的发展、数据量的增长,在某个业务场景 ES 相关的资源和效率可能逐渐成为瓶颈,这时候我们就需要从底层视角来推动上层的优化,如图13所示,根据监控曲线可发现 fdt、doc、pos 几类文件的常驻内存资源较多,便可从这3类文件的使用情况出发来制定优化方向:

  • fdt 常用于获取_source字段的内容,如果存储并在查询结果中获取大量字段很容易导致该文件频繁访问,进而占用较多资源,可以考虑对 _source 进行适当删减,或将数据获取逻辑移至宽表数据库,如HBase等,让 ES 的资源更多的用于搜索本身;
  • doc 在 term 和全文搜索场景均有使用,这类文件的加载通常不可避免,可以从降低文件大小来入手,如在分词层面进行优化,对词的分布进行统计分析,来评估是否可以补充停用词等;
  • pos 用于需要位置信息的 phrase 查询,可从查询语句的拼装进行优化。

image-14.png
图13 观察内存资源占用来制定优化方向 ​

总结及未来展望

es-pcstat 从 ES 索引和 lucene 各类文件 page cache 占用的角度,提供了一种对 ES 进行监控的全新思路,基于这些监控数据我们可以进行资源的饱和度评估,异常查询请求的定位,或者为性能优化制定方向。 ​

当然异常请求的定位都只能限于事后分析,无法避免问题的产生,如何通过监控数据和查询请求去评估一个 query 可能对集群产生的影响,并拦截可能导致较大 page cache 争用的请求,这将能为集群的稳定性提供更大的保障。 ​

es-pcstat 采集细化到了 lucene 文件的粒度,需要具备一定基础知识和经验才能快速定位背后原因,因此在分析上具备一定门槛,如果能根据文件波动来为监控者提供一些 ES 层面的提示,将能服务更广大的 ES 用户。 ​

在 ES 中对一个查询的成本(涉及JVM中的缓存、系统内存缺页中断、IO、CPU等)进行评估本身是一件比较难的事,page cache 的监控可能能提供一定的帮助,当然还有更多的作用等待我们去探索。

参考链接



收起阅读 »

发布一个免费的 Elasticsearch 多集群监控和管理平台 - 极限数据平台

随着单个 Elasticsearch 集群规模的越来越大,大家要么在拆集群的路上,要么是已经是多套集群了, 据路边社消息,一个公司超过5个集群的情况已经变得非常普遍,而管理多个集群着实是有点痛苦,比如常规的玩法可能是一套集群一个 Kibana,集群一多,切换来切换去就有点懵圈了有木有?

fansile.gif

作为一个优雅的程序员或者运维管理员,是可忍孰不可忍啊。

另外,多个集群的监控也是一个麻烦事,目前常见的几种监控如:

  • 使用 Kibana 自带的监控
  • 使用 Prometheus + Grafana
  • 使用 Zabbix

Kibana 自带的监控可以很好的满足单个集群的监控场景,不过集群规模大了之后,经常会出现指标丢失的问题,如果使用单独的监控集群,需要修改每个节点的配置,集群都需要重启,对于已经上了生产的集群,有点不方便,另外多集群监控需要商业授权。

e82a31225ca28ed8029e0681f9346ee2.gif

那 Prometheus 呢, 一个 Elasticsearch 集群如果要监控起来,首先需要部署一个 Exporter 来暴露集群指标,然后部署一套Prometheus 来采集 Elasticsearch 指标,采集完了之后再部署一套 Grafana 来进行报表分析,不同的集群要做好切换,简单的事情,搞复杂了,整个监控体系偏重,维护成本高。

Zabbix 和 Prometheus 的场景差不多,就不赘述了。

530a83558eabaa4ae4eb25501349a7a3_16590_250_187.jpeg

那么问题来了,有没有一个更加简单方便的多集群监控和管理方案呢,并且要支持不同版本的集群,最好是 v2、v5、v6、v7 以及最新的 v8 都能统统接管,哈哈,没错了,这里给大家介绍一个我们极限实验室团队最近开发出来的一款免费的多集群监控和管理工具-极限数据平台,目前版本 v0.1,新鲜出炉。

废话不多少,咱们直接看图说话:

Jietu20211122-183111.jpg

首先是多集群的纳管,目前从 1.0 到最新的 8.0 统统都可以接进来。

Jietu20211122-183020.jpg

然后就是集群的监控拉,要多简单有多简单,就是一个开关的事情,注册集群的时候,启用即开启监控,目标集群啥都不用动,费那劲干啥。

监控界面如图:

Jietu20211122-183309.jpg

集群概览,总体情况一目了然。

Jietu20211122-183438.jpg

各个节点信息,分门别类。

Jietu20211122-183504.jpg

各个索引级别的信息,挨个查看。

Jietu20211122-183558.jpg

多个集群之间的监控查看一键切换,非常方便。

查看监控的时候,发现不对劲,要操作一下集群,直接调出控制台,如下图:

Jietu20211122-183717.jpg

常用的操作命令,可以保存起来,方便下次使用。

Jietu20211122-183815.jpg

别再保存在记事本里面了,下次又找不到,直接加载执行就好了。

Jietu20211122-183924.jpg

好了,你要是用 Elasticsearch 不知道这个工具,那就 out 了,赶快耍起来吧。

下载地址:

https://release.www.ksh17j.com/console/snapshot/

安装巨简单,简直懒得说,一个二进制可执行文件,一个 yml 配置文件,里面修改 Elasticsearch 地址,结束。

可以在这里查看

最后,欢迎关注极限实验室,获取更多 Elasticsearch 免费工具及业界资讯的第一手消息。

WechatIMG700.jpeg

继续阅读 »

随着单个 Elasticsearch 集群规模的越来越大,大家要么在拆集群的路上,要么是已经是多套集群了, 据路边社消息,一个公司超过5个集群的情况已经变得非常普遍,而管理多个集群着实是有点痛苦,比如常规的玩法可能是一套集群一个 Kibana,集群一多,切换来切换去就有点懵圈了有木有?

fansile.gif

作为一个优雅的程序员或者运维管理员,是可忍孰不可忍啊。

另外,多个集群的监控也是一个麻烦事,目前常见的几种监控如:

  • 使用 Kibana 自带的监控
  • 使用 Prometheus + Grafana
  • 使用 Zabbix

Kibana 自带的监控可以很好的满足单个集群的监控场景,不过集群规模大了之后,经常会出现指标丢失的问题,如果使用单独的监控集群,需要修改每个节点的配置,集群都需要重启,对于已经上了生产的集群,有点不方便,另外多集群监控需要商业授权。

e82a31225ca28ed8029e0681f9346ee2.gif

那 Prometheus 呢, 一个 Elasticsearch 集群如果要监控起来,首先需要部署一个 Exporter 来暴露集群指标,然后部署一套Prometheus 来采集 Elasticsearch 指标,采集完了之后再部署一套 Grafana 来进行报表分析,不同的集群要做好切换,简单的事情,搞复杂了,整个监控体系偏重,维护成本高。

Zabbix 和 Prometheus 的场景差不多,就不赘述了。

530a83558eabaa4ae4eb25501349a7a3_16590_250_187.jpeg

那么问题来了,有没有一个更加简单方便的多集群监控和管理方案呢,并且要支持不同版本的集群,最好是 v2、v5、v6、v7 以及最新的 v8 都能统统接管,哈哈,没错了,这里给大家介绍一个我们极限实验室团队最近开发出来的一款免费的多集群监控和管理工具-极限数据平台,目前版本 v0.1,新鲜出炉。

废话不多少,咱们直接看图说话:

Jietu20211122-183111.jpg

首先是多集群的纳管,目前从 1.0 到最新的 8.0 统统都可以接进来。

Jietu20211122-183020.jpg

然后就是集群的监控拉,要多简单有多简单,就是一个开关的事情,注册集群的时候,启用即开启监控,目标集群啥都不用动,费那劲干啥。

监控界面如图:

Jietu20211122-183309.jpg

集群概览,总体情况一目了然。

Jietu20211122-183438.jpg

各个节点信息,分门别类。

Jietu20211122-183504.jpg

各个索引级别的信息,挨个查看。

Jietu20211122-183558.jpg

多个集群之间的监控查看一键切换,非常方便。

查看监控的时候,发现不对劲,要操作一下集群,直接调出控制台,如下图:

Jietu20211122-183717.jpg

常用的操作命令,可以保存起来,方便下次使用。

Jietu20211122-183815.jpg

别再保存在记事本里面了,下次又找不到,直接加载执行就好了。

Jietu20211122-183924.jpg

好了,你要是用 Elasticsearch 不知道这个工具,那就 out 了,赶快耍起来吧。

下载地址:

https://release.www.ksh17j.com/console/snapshot/

安装巨简单,简直懒得说,一个二进制可执行文件,一个 yml 配置文件,里面修改 Elasticsearch 地址,结束。

可以在这里查看

最后,欢迎关注极限实验室,获取更多 Elasticsearch 免费工具及业界资讯的第一手消息。

WechatIMG700.jpeg

收起阅读 »

极限网关入门视频教程已发布

录制了一系列视频教程,介绍极限网关的使用,不断更新中,第一次做 up 主,记得一键三连,支持一下。:) 

 
 
极限网关地址:
继续阅读 »
录制了一系列视频教程,介绍极限网关的使用,不断更新中,第一次做 up 主,记得一键三连,支持一下。:) 

 
 
极限网关地址: 收起阅读 »

ES容灾技术探讨和测试

ES灾备技术调研

早就听说极限网关了,最近有个ES要做灾备,就搜集了下技术方案:

  1. 应用双写两个集群

  2. 跨集群复制CCR

  3. 极限网关

三个方案的优缺点我也简单整理了下:

  1. 优点:自主研发,想怎样就怎样;缺点:难,水平、时间都是成本

  2. 优点:实施简单;缺点:需要license

  3. 优点:部署灵活,功能齐全;缺点:不熟悉,没用过

貌似方案 3,比较理想。不熟悉,那就多用用,测试测试找找感觉。

测试环境 笔记本

主集群:A 7.14.1 10.0.2.15:9214 Rbac+tls 节点数:1
备集群:B 7.13.2 10.0.2.15:9213 Rbac+tls 节点数:2
极限网关 1.3.0 0.0.0.0:8000 tls 实例数:1

wpsF088.tmp_.jpg

wpsF089.tmp_.jpg

网关下载

先下载极限网关:https://release.www.ksh17j.com/gateway/snapshot/

解压后,可看到有几个预定义的配置,方便大家快速上车。

wpsF08A.tmp_.jpg

网关配置

这次是做灾备,应该就是在 dc-replica.yml的基础上改比较妥当,配置还是比较多的 300多行,很多都是为了保证两个集群数据一致性,解耦啥的做的判断和写队列之类的设置。我只修改了 elasticsearch资源的定义信息,还有网关也可选择tls,不用手工生成证书,非常方便。

贴下我修改的地方

wpsF08B.tmp_.jpg

wpsF08C.tmp_.jpg

启动网关

wpsF08D.tmp_.jpg

两个集群都是 available ,说明连接应该ok

测试场景:围绕主备集群之间数据复制展开

1. 主备集群间复制创建、写入、删除索引操作

目的:对网关(A集群)创建索引test,对test索引写文档,能自动同步到B集群

初始情况A、B无test

wpsF09E.tmp_.jpg
wpsF09F.tmp_.jpg

手工put test索引到网关

wpsF0A0.tmp_.jpg
wpsF0A1.tmp_.jpg
wpsF0A2.tmp_.jpg
A,B集群都创建成功

用loadgen写点文档进去吧,loadgen直接写网关

wpsF0A3.tmp_.jpg

wpsF0A4.tmp_.jpg

wpsF0A5.tmp_.jpg

都10000条写入成功,如果查看是0的话,先refresh下索引

看下文档

wpsF0A6.tmp_.jpg

简单校验一下

wpsF0A7.tmp_.jpg

wpsF0A8.tmp_.jpg

感觉没问题,删点文档看看,把那23个删了吧

wpsF0A9.tmp_.jpg

再看看

wpsF0AA.tmp_.jpg

wpsF0BA.tmp_.jpg

更新524个文档看看

wpsF0BB.tmp_.jpg

wpsF0BC.tmp_.jpg

wpsF0BD.tmp_.jpg

增、删、改 完事

2. 主集群故障的处理和恢复

目的:主集群故障后,网关如何处理收到的请求:读、写

Kill 掉 A 集群,模拟主集群故障

网关直接有报错说连不上A集群

此时对网关查询、写入数据都会报错

wpsF0BE.tmp_.jpg

重新启动主集群后,一切正常

3. 备集群故障的处理和恢复

目的:备集群故障,读、写主集群不受影响,备集群恢复后,自动追数据直到两边数据一致

Kill 掉B集群,网关报错,B集群无法连接

wpsF0BF.tmp_.jpg

对A集群进行写入一个新文档,并查询下

wpsF0C0.tmp_.jpg

wpsF0C1.tmp_.jpg

启动B集群,查看,已自动添加了新的文档

wpsF0C2.tmp_.jpg

4. 主集群容灾切换

目的:主集群故障,短时间不可用,网关切换指向备集群作为主集群,A集群作为备集群;待A集群恢复后,自动追数据

KILL A 集群 模拟A集群故障

Kill 网关,切换配置:

wpsF0C3.tmp_.jpg

启动网关,B是主了,available

wpsF0C4.tmp_.jpg

写B集群,删除前面创建的 test 索引,新建test2索引,并插入文档

wpsF0C5.tmp_.jpg

wpsF0D6.tmp_.jpg

启动A集群,检查数据,有test2索引,且文档一致

wpsF0D7.tmp_.jpg

5. 主集群故障恢复后,网关回切

目的:假设A集群已经完全恢复,网关回切,A集群为主,B集群为备

Kill网关,恢复配置,再启动网关

再次测试写入test2 检查能否同步成功

写网关

wpsF0D8.tmp_.jpg

查看A集群

wpsF0D9.tmp_.jpg

查看B集群

wpsF0DA.tmp_.jpg

两个集群数据一致,主备角色也恢复到最初了

**测试环境变更

中间工作比较忙,中断了测试,也就十来天吧

不成想 网关更新了,我就下了新版本的gateway和ES-7.15.1 继续捣鼓

环境 笔记本

主集群:es-751primary 7.15.1 10.0.2.15:7151 No:Rbac、tls 节点数:1
备集群:es-751backup 7.15.1 10.0.2.15:7152 No:Rbac、tls 节点数:1
极限网关 场景6:1.4.0场景7:1.5.0 0.0.0.0:8000 No:tls 实例数:1

wpsF0DB.tmp_.jpg

网关不光版本升级了,配置文件也稍稍有些变化,新版本示例配置如下

wpsF0DC.tmp_.jpg

本着不会就猜的原则,我还是能做到见名之知意的

我仅仅对 cross-cluster-replication.yml 做了简单的修改,就是和前面一样

6. ES由代理暴露的能否正常工作

目的:检验,比如由nginx代理ES的时候,网关能否正常工作

使用 nginx 代理后端的ES

80-->primary

81-->backup

wpsF0DD.tmp_.jpg

测试下反向代理工作是否正常

wpsF0DE.tmp_.jpg

启动网关,网关里elasticsearch资源指向nginx,没错就改了下 url

wpsF0DF.tmp_.jpg

开始测试,增删改查 once more,还是对着网关操作

创建索引

wpsF0E0.tmp_.jpg

PUT 文档

wpsF0F0.tmp_.jpg

抄家伙

wpsF0F1.tmp_.jpg

看看数量

wpsF0F2.tmp_.jpg

简单对比下

wpsF0F3.tmp_.jpg
给 code为500的文档增加一个字段 new_field

wpsF0F4.tmp_.jpg

直接通过代理查询,检验数据

wpsF0F5.tmp_.jpg

没问题,测试删除

删除单条

wpsF0F6.tmp_.jpg

wpsF0F7.tmp_.jpg

wpsF0F8.tmp_.jpg

批量删除

wpsF0F9.tmp_.jpg

看看结果

wpsF0FA.tmp_.jpg

删除索引,并确认真的删除

wpsF10B.tmp_.jpg

关调backup集群,然后primary集群创建索引后,再启动backup集群,看能否自动追平

wpsF10C.tmp_.jpg

创建test2索引

wpsF10D.tmp_.jpg

顺手put个文档

wpsF10E.tmp_.jpg

Primary上查看

wpsF10F.tmp_.jpg

OK 启动backup

wpsF110.tmp_.jpg

妈的 奇迹

7. 请求压缩功能如何

目的:看看客户端和网关分别在不同的请求压缩配置下,是否工作正常

在网关的配置中,看到了 compress 压缩,也设计几个场景测试下

网关配置里面有个压缩的配置,意思是消费线程往ES发送请求的时候是否启用gzip压缩。

默认是 true

wpsF111.tmp_.jpg

7.1 用压缩的方式写网关,但网关不启用压缩

我们把网关配置中的true改成false

wpsF112.tmp_.jpg

启动网关

wpsF113.tmp_.jpg

开始写数据,写的过程中,随机停止backup集群,等待一会儿后再启动

wpsF114.tmp_.jpg

网关可看到 backup集群,从不可用到可用

wpsF115.tmp_.jpg

看看网关的队列情况,这时候backup队列应该堆积了不少请求

wpsF116.tmp_.jpg

等待队列被消费完后,我们对比数据。

wpsF117.tmp_.jpg

简单看看文档条数

wpsF128.tmp_.jpg

wpsF129.tmp_.jpg

用网关对比下数据看看

wpsF12A.tmp_.jpg

妥妥的一致

7.2 用压缩的方式写网关,网关也启用压缩

就把前面网关贴图的false改成true

启动网关

wpsF12B.tmp_.jpg

压缩写入

wpsF12C.tmp_.jpg

写入过程中,随机重启backup集群

网关日志

wpsF12D.tmp_.jpg

等待网关backup队列消费完毕,后对比数据

wpsF12E.tmp_.jpg

wpsF12F.tmp_.jpg

没得问题,下一场

7.3 用不压缩的方式写网关,网关也不启用压缩

网关配置compress: false,后启动网关

wpsF130.tmp_.jpg

不压缩请求

wpsF131.tmp_.jpg

中途随机重启backup集群

wpsF132.tmp_.jpg

队列消费完后对比数据

wpsF133.tmp_.jpg

数据一致

7.4 用不压缩的方式写网关,网关backup队列的消费线程使用压缩

wpsF134.tmp_.jpg

写入过程中,停止backup集群,稍等一会儿后启动backup集群

wpsF135.tmp_.jpg

观察网关的backup 队列情况

wpsF145.tmp_.jpg

等消费完之后,我们对比数据

数量一致

wpsF146.tmp_.jpg

wpsF147.tmp_.jpg

用网关来对比下两个集群的test索引的数据

wpsF148.tmp_.jpg

至此,关于跨集群复制的场景测试可以告一段落了,功能大家也看到了确实强大,部署也很灵活,对环境无侵入,直接把应用连接ES的地址、端口改下就行。或者网关直接监听9200端口,替换原有的协调节点,应用无感知。

此外,极限网关还有很多别的使用场景和激动人心的功能,像在线修改查询、请求限流、请求流量分析,这都是保障ES集群稳定运行的手段。

看到一款国产软件如此强大很欣慰,很激动。希望各位感兴趣的小伙伴也下载测试下自己的场景,我们ES圈(论坛)多交流交流。让我也看看你们的场景和测试是怎样的。

最后一个图,我也不知道咋回事,请忽略。

继续阅读 »

ES灾备技术调研

早就听说极限网关了,最近有个ES要做灾备,就搜集了下技术方案:

  1. 应用双写两个集群

  2. 跨集群复制CCR

  3. 极限网关

三个方案的优缺点我也简单整理了下:

  1. 优点:自主研发,想怎样就怎样;缺点:难,水平、时间都是成本

  2. 优点:实施简单;缺点:需要license

  3. 优点:部署灵活,功能齐全;缺点:不熟悉,没用过

貌似方案 3,比较理想。不熟悉,那就多用用,测试测试找找感觉。

测试环境 笔记本

主集群:A 7.14.1 10.0.2.15:9214 Rbac+tls 节点数:1
备集群:B 7.13.2 10.0.2.15:9213 Rbac+tls 节点数:2
极限网关 1.3.0 0.0.0.0:8000 tls 实例数:1

wpsF088.tmp_.jpg

wpsF089.tmp_.jpg

网关下载

先下载极限网关:https://release.www.ksh17j.com/gateway/snapshot/

解压后,可看到有几个预定义的配置,方便大家快速上车。

wpsF08A.tmp_.jpg

网关配置

这次是做灾备,应该就是在 dc-replica.yml的基础上改比较妥当,配置还是比较多的 300多行,很多都是为了保证两个集群数据一致性,解耦啥的做的判断和写队列之类的设置。我只修改了 elasticsearch资源的定义信息,还有网关也可选择tls,不用手工生成证书,非常方便。

贴下我修改的地方

wpsF08B.tmp_.jpg

wpsF08C.tmp_.jpg

启动网关

wpsF08D.tmp_.jpg

两个集群都是 available ,说明连接应该ok

测试场景:围绕主备集群之间数据复制展开

1. 主备集群间复制创建、写入、删除索引操作

目的:对网关(A集群)创建索引test,对test索引写文档,能自动同步到B集群

初始情况A、B无test

wpsF09E.tmp_.jpg
wpsF09F.tmp_.jpg

手工put test索引到网关

wpsF0A0.tmp_.jpg
wpsF0A1.tmp_.jpg
wpsF0A2.tmp_.jpg
A,B集群都创建成功

用loadgen写点文档进去吧,loadgen直接写网关

wpsF0A3.tmp_.jpg

wpsF0A4.tmp_.jpg

wpsF0A5.tmp_.jpg

都10000条写入成功,如果查看是0的话,先refresh下索引

看下文档

wpsF0A6.tmp_.jpg

简单校验一下

wpsF0A7.tmp_.jpg

wpsF0A8.tmp_.jpg

感觉没问题,删点文档看看,把那23个删了吧

wpsF0A9.tmp_.jpg

再看看

wpsF0AA.tmp_.jpg

wpsF0BA.tmp_.jpg

更新524个文档看看

wpsF0BB.tmp_.jpg

wpsF0BC.tmp_.jpg

wpsF0BD.tmp_.jpg

增、删、改 完事

2. 主集群故障的处理和恢复

目的:主集群故障后,网关如何处理收到的请求:读、写

Kill 掉 A 集群,模拟主集群故障

网关直接有报错说连不上A集群

此时对网关查询、写入数据都会报错

wpsF0BE.tmp_.jpg

重新启动主集群后,一切正常

3. 备集群故障的处理和恢复

目的:备集群故障,读、写主集群不受影响,备集群恢复后,自动追数据直到两边数据一致

Kill 掉B集群,网关报错,B集群无法连接

wpsF0BF.tmp_.jpg

对A集群进行写入一个新文档,并查询下

wpsF0C0.tmp_.jpg

wpsF0C1.tmp_.jpg

启动B集群,查看,已自动添加了新的文档

wpsF0C2.tmp_.jpg

4. 主集群容灾切换

目的:主集群故障,短时间不可用,网关切换指向备集群作为主集群,A集群作为备集群;待A集群恢复后,自动追数据

KILL A 集群 模拟A集群故障

Kill 网关,切换配置:

wpsF0C3.tmp_.jpg

启动网关,B是主了,available

wpsF0C4.tmp_.jpg

写B集群,删除前面创建的 test 索引,新建test2索引,并插入文档

wpsF0C5.tmp_.jpg

wpsF0D6.tmp_.jpg

启动A集群,检查数据,有test2索引,且文档一致

wpsF0D7.tmp_.jpg

5. 主集群故障恢复后,网关回切

目的:假设A集群已经完全恢复,网关回切,A集群为主,B集群为备

Kill网关,恢复配置,再启动网关

再次测试写入test2 检查能否同步成功

写网关

wpsF0D8.tmp_.jpg

查看A集群

wpsF0D9.tmp_.jpg

查看B集群

wpsF0DA.tmp_.jpg

两个集群数据一致,主备角色也恢复到最初了

**测试环境变更

中间工作比较忙,中断了测试,也就十来天吧

不成想 网关更新了,我就下了新版本的gateway和ES-7.15.1 继续捣鼓

环境 笔记本

主集群:es-751primary 7.15.1 10.0.2.15:7151 No:Rbac、tls 节点数:1
备集群:es-751backup 7.15.1 10.0.2.15:7152 No:Rbac、tls 节点数:1
极限网关 场景6:1.4.0场景7:1.5.0 0.0.0.0:8000 No:tls 实例数:1

wpsF0DB.tmp_.jpg

网关不光版本升级了,配置文件也稍稍有些变化,新版本示例配置如下

wpsF0DC.tmp_.jpg

本着不会就猜的原则,我还是能做到见名之知意的

我仅仅对 cross-cluster-replication.yml 做了简单的修改,就是和前面一样

6. ES由代理暴露的能否正常工作

目的:检验,比如由nginx代理ES的时候,网关能否正常工作

使用 nginx 代理后端的ES

80-->primary

81-->backup

wpsF0DD.tmp_.jpg

测试下反向代理工作是否正常

wpsF0DE.tmp_.jpg

启动网关,网关里elasticsearch资源指向nginx,没错就改了下 url

wpsF0DF.tmp_.jpg

开始测试,增删改查 once more,还是对着网关操作

创建索引

wpsF0E0.tmp_.jpg

PUT 文档

wpsF0F0.tmp_.jpg

抄家伙

wpsF0F1.tmp_.jpg

看看数量

wpsF0F2.tmp_.jpg

简单对比下

wpsF0F3.tmp_.jpg
给 code为500的文档增加一个字段 new_field

wpsF0F4.tmp_.jpg

直接通过代理查询,检验数据

wpsF0F5.tmp_.jpg

没问题,测试删除

删除单条

wpsF0F6.tmp_.jpg

wpsF0F7.tmp_.jpg

wpsF0F8.tmp_.jpg

批量删除

wpsF0F9.tmp_.jpg

看看结果

wpsF0FA.tmp_.jpg

删除索引,并确认真的删除

wpsF10B.tmp_.jpg

关调backup集群,然后primary集群创建索引后,再启动backup集群,看能否自动追平

wpsF10C.tmp_.jpg

创建test2索引

wpsF10D.tmp_.jpg

顺手put个文档

wpsF10E.tmp_.jpg

Primary上查看

wpsF10F.tmp_.jpg

OK 启动backup

wpsF110.tmp_.jpg

妈的 奇迹

7. 请求压缩功能如何

目的:看看客户端和网关分别在不同的请求压缩配置下,是否工作正常

在网关的配置中,看到了 compress 压缩,也设计几个场景测试下

网关配置里面有个压缩的配置,意思是消费线程往ES发送请求的时候是否启用gzip压缩。

默认是 true

wpsF111.tmp_.jpg

7.1 用压缩的方式写网关,但网关不启用压缩

我们把网关配置中的true改成false

wpsF112.tmp_.jpg

启动网关

wpsF113.tmp_.jpg

开始写数据,写的过程中,随机停止backup集群,等待一会儿后再启动

wpsF114.tmp_.jpg

网关可看到 backup集群,从不可用到可用

wpsF115.tmp_.jpg

看看网关的队列情况,这时候backup队列应该堆积了不少请求

wpsF116.tmp_.jpg

等待队列被消费完后,我们对比数据。

wpsF117.tmp_.jpg

简单看看文档条数

wpsF128.tmp_.jpg

wpsF129.tmp_.jpg

用网关对比下数据看看

wpsF12A.tmp_.jpg

妥妥的一致

7.2 用压缩的方式写网关,网关也启用压缩

就把前面网关贴图的false改成true

启动网关

wpsF12B.tmp_.jpg

压缩写入

wpsF12C.tmp_.jpg

写入过程中,随机重启backup集群

网关日志

wpsF12D.tmp_.jpg

等待网关backup队列消费完毕,后对比数据

wpsF12E.tmp_.jpg

wpsF12F.tmp_.jpg

没得问题,下一场

7.3 用不压缩的方式写网关,网关也不启用压缩

网关配置compress: false,后启动网关

wpsF130.tmp_.jpg

不压缩请求

wpsF131.tmp_.jpg

中途随机重启backup集群

wpsF132.tmp_.jpg

队列消费完后对比数据

wpsF133.tmp_.jpg

数据一致

7.4 用不压缩的方式写网关,网关backup队列的消费线程使用压缩

wpsF134.tmp_.jpg

写入过程中,停止backup集群,稍等一会儿后启动backup集群

wpsF135.tmp_.jpg

观察网关的backup 队列情况

wpsF145.tmp_.jpg

等消费完之后,我们对比数据

数量一致

wpsF146.tmp_.jpg

wpsF147.tmp_.jpg

用网关来对比下两个集群的test索引的数据

wpsF148.tmp_.jpg

至此,关于跨集群复制的场景测试可以告一段落了,功能大家也看到了确实强大,部署也很灵活,对环境无侵入,直接把应用连接ES的地址、端口改下就行。或者网关直接监听9200端口,替换原有的协调节点,应用无感知。

此外,极限网关还有很多别的使用场景和激动人心的功能,像在线修改查询、请求限流、请求流量分析,这都是保障ES集群稳定运行的手段。

看到一款国产软件如此强大很欣慰,很激动。希望各位感兴趣的小伙伴也下载测试下自己的场景,我们ES圈(论坛)多交流交流。让我也看看你们的场景和测试是怎样的。

最后一个图,我也不知道咋回事,请忽略。

收起阅读 »

Elasticsearch:从 Spring Boot 应用中连接 Elasticsearch

我将使用库 spring-boot-starter-data-elasticsearch  来和 Elasticsearch 进行连接。这种方法非常简单直接。 
继续阅读 »
我将使用库 spring-boot-starter-data-elasticsearch  来和 Elasticsearch 进行连接。这种方法非常简单直接。  收起阅读 »

使用极限网关来进行 Elasticsearch 跨集群跨版本查询及所有其它请求

使用场景

如果你的业务需要用到有多个集群,并且版本还不一样,是不是管理起来很麻烦,如果能够通过一个 API 来进行查询就方便了,聪明的你相信已经想到了 CCS,没错用 CCS 可以实现跨集群的查询,不过 Elasticsearch 提供的 CCS 对版本有一点的限制,并且需要提前做好 mTLS,也就是需要提前配置好两个集群之间的证书互信,这个免不了要重启维护,好像有点麻烦,那么问题来咯,有没有更好的方案呢?

😁 有办法,今天我就给大家介绍一个基于极限网关的方案,极限网关的网址:。

假设现在有两个集群,一个集群是 v2.4.6,有不少业务数据,舍不得删,里面有很多好东西 :)还有一个集群是 v7.14.0,版本还算比较新,业务正在做的一个新的试点,没什么好东西,但是也得用 :(,现在老板们的的需求是希望通过在一个统一的接口就能访问这些数据,程序员懒得很,懂得都懂。

集群信息

  • v2.4.6 集群的访问入口地址:192.168.3.188:9202
  • v7.14.0 集群的访问入口地址:192.168.3.188:9206

这两个集群都是 http 协议的。

实现步骤

今天用到的是极限网关的 switch 过滤器:

网关下载下来就两个文件,一个主程序,一个配置文件,记得下载对应操作系统的包。

定义两个集群资源

elasticsearch:
  - name: v2
    enabled: true
    endpoint: https://192.168.3.188:9202
  - name: v7
    enabled: true
    endpoint: https://192.168.3.188:9206

上面定义了两个集群,分别命名为 v2v7,待会会用到这些资源。

定义一个服务入口

entry:
  - name: my_es_entry
    enabled: true
    router: my_router
    max_concurrency: 1000
    network:
      binding: 0.0.0.0:8000
    tls:
      enabled: true

这里定义了一个名为 my_es_entry 的资源入口,并引用了一个名为 my_router 的请求转发路由,同时绑定了网卡的 0.0.0.0:8000 也就是所有本地网卡监听 IP 的 8000 端口,访问任意 IP 的 8000 端口就能访问到这个网关了。

另外老板也说了,Elasticsearch 用 HTTP 协议简直就是裸奔,通过这里开启 tls,可以让网关对外提供的是 HTTPS 协议,这样用户连接的 Elasticsearch 服务就自带 buffer 了,后端的 es 集群和网关直接可以做好网络流量隔离,集群不用动,简直完美。

为什么定义 TLS 不用指定证书,好用的软件不需要这么麻烦,就这样,不解释。

最后,通过设置 max_concurrency 为 1000,限制下并发数,避免野猴子把我们的后端的 Elasticsearch 给压挂了。

定义一个请求路由

router:
  - name: my_router
    default_flow: cross-cluster-search

这里的名称 my_router 就是表示上面的服务入口的router 参数指定的值。

另外设置一个 default_flow 来将所有的请求都转发给一个名为 cross-cluster-search 的请求处理流程,还没定义,别急,马上。

定义请求处理流程

来啦,来啦,先定义两个 flow,如下,分别名为 v2-flowv7-flow,每节配置的 filter 定义了一系列过滤器,用来对请求进行处理,这里就用了一个 elasticsearch 过滤器,也就是转发请求给指定的 Elasticsearch 后端服务器,了否?

flow:
  - name: v2-flow
    filter:
      - elasticsearch:
          elasticsearch: v2
  - name: v7-flow
    filter:
      - elasticsearch:
          elasticsearch: v7

然后,在定义额外一个名为 cross-cluster-search 的 flow,如下:

  - name: cross-cluster-search
    filter:
      - switch:
          path_rules:
            - prefix: "v2:"
              flow: v2-flow
            - prefix: "v7:"
              flow: v7-flow

这个 flow 就是通过请求的路径的前缀来进行路由的过滤器,如果是 v2:开头的请求,则转发给 v2-flow 继续处理,如果是 v7: 开头的请求,则转发给 v7-flow 来处理,使用的用法和 CCS 是一样的。so easy!

对了,那是不是每个请求都需要加前缀啊,费事啊,没事,在这个 cross-cluster-search 的 filter 最后再加上一个 elasticsearch filter,前面前缀匹配不上的都会走它,假设默认都走 v7,最后完整的 flow 配置如下:

flow:
  - name: v2-flow
    filter:
      - elasticsearch:
          elasticsearch: v2
  - name: v7-flow
    filter:
      - elasticsearch:
          elasticsearch: v7
  - name: cross-cluster-search
    filter:
      - switch:
          path_rules:
            - prefix: "v2:"
              flow: v2-flow
            - prefix: "v7:"
              flow: v7-flow
      - elasticsearch:
          elasticsearch: v7              

然后就没有然后了,因为就配置这些就行了。

启动网关

假设配置文件的路径为 sample-configs/cross-cluster-search.yml,运行如下命令:

➜  gateway git:(master) ✗ ./bin/gateway -config sample-configs/cross-cluster-search.yml
   ___   _   _____  __  __    __  _       
  / _ \ /_\ /__   \/__\/ / /\ \ \/_\ /\_/\
 / /_\///_\\  / /\/_\  \ \/  \/ //_\\\_ _/
/ /_\\/  _  \/ / //__   \  /\  /  _  \/ \ 
\____/\_/ \_/\/  \__/    \/  \/\_/ \_/\_/ 

[GATEWAY] A light-weight, powerful and high-performance elasticsearch gateway.
[GATEWAY] 1.0.0_SNAPSHOT, 2021-10-15 16:25:56, 3d0a1cd
[10-16 11:00:52] [INF] [app.go:228] initializing gateway.
[10-16 11:00:52] [INF] [instance.go:24] workspace: data/gateway/nodes/0
[10-16 11:00:52] [INF] [api.go:260] api listen at: https://0.0.0.0:2900
[10-16 11:00:52] [INF] [reverseproxy.go:257] elasticsearch [v7] hosts: [] => [192.168.3.188:9206]
[10-16 11:00:52] [INF] [entry.go:225] auto generating cert files
[10-16 11:00:52] [INF] [actions.go:223] elasticsearch [v2] is available
[10-16 11:00:52] [INF] [actions.go:223] elasticsearch [v7] is available
[10-16 11:00:53] [INF] [entry.go:296] entry [my_es_entry] listen at: https://0.0.0.0:8000
[10-16 11:00:53] [INF] [app.go:309] gateway is running now.

可以看到网关输出了启动成功的日志,网关服务监听在 https://0.0.0.0:8000

试试访问网关

直接访问网关的 8000 端口,因为是网关自签的证书,加上 -k 来跳过证书的校验,如下:

➜  loadgen git:(master) ✗ curl -k   https://localhost:8000  
{
  "name" : "LENOVO",
  "cluster_name" : "es-v7140",
  "cluster_uuid" : "npWjpIZmS8iP_p3GK01-xg",
  "version" : {
    "number" : "7.14.0",
    "build_flavor" : "default",
    "build_type" : "zip",
    "build_hash" : "dd5a0a2acaa2045ff9624f3729fc8a6f40835aa1",
    "build_date" : "2021-07-29T20:49:32.864135063Z",
    "build_snapshot" : false,
    "lucene_version" : "8.9.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

正如前面配置所配置的一样,默认请求访问的就是 v7 集群。

访问 v2 集群

➜  loadgen git:(master) ✗ curl -k   https://localhost:8000/v2:/    
{
  "name" : "Solomon O'Sullivan",
  "cluster_name" : "es-v246",
  "cluster_uuid" : "cqlpjByvQVWDAv6VvRwPAw",
  "version" : {
    "number" : "2.4.6",
    "build_hash" : "5376dca9f70f3abef96a77f4bb22720ace8240fd",
    "build_timestamp" : "2017-07-18T12:17:44Z",
    "build_snapshot" : false,
    "lucene_version" : "5.5.4"
  },
  "tagline" : "You Know, for Search"
}

查看集群信息:

➜  loadgen git:(master) ✗ curl -k   https://localhost:8000/v2:_cluster/health\?pretty
{
  "cluster_name" : "es-v246",
  "status" : "yellow",
  "timed_out" : false,
  "number_of_nodes" : 1,
  "number_of_data_nodes" : 1,
  "active_primary_shards" : 5,
  "active_shards" : 5,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 5,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 50.0
}

插入一条文档:

➜  loadgen git:(master) ✗ curl-json -k   https://localhost:8000/v2:medcl/doc/1 -d '{"name":"hello world"}'
{"_index":"medcl","_type":"doc","_id":"1","_version":1,"_shards":{"total":2,"successful":1,"failed":0},"created":true}%  

执行一个查询

➜  loadgen git:(master) ✗ curl -k   https://localhost:8000/v2:medcl/_search\?q\=name:hello                
{"took":78,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":0.19178301,"hits":[{"_index":"medcl","_type":"doc","_id":"1","_score":0.19178301,"_source":{"name":"hello world"}}]}}% 

可以看到,所有的请求,不管是集群的操作,还是索引的增删改查都可以,而 Elasticsearch 自带的 CCS 是只读的,只能进行查询。

访问 v7 集群

➜  loadgen git:(master) ✗ curl -k   https://localhost:8000/v7:/
{
  "name" : "LENOVO",
  "cluster_name" : "es-v7140",
  "cluster_uuid" : "npWjpIZmS8iP_p3GK01-xg",
  "version" : {
    "number" : "7.14.0",
    "build_flavor" : "default",
    "build_type" : "zip",
    "build_hash" : "dd5a0a2acaa2045ff9624f3729fc8a6f40835aa1",
    "build_date" : "2021-07-29T20:49:32.864135063Z",
    "build_snapshot" : false,
    "lucene_version" : "8.9.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

Kibana 里面访问

完全没问题,有图有真相:

Jietu20211016-114041.jpg

其他操作也类似,就不重复了。

完整的配置

path.data: data
path.logs: log

entry:
  - name: my_es_entry
    enabled: true
    router: my_router
    max_concurrency: 10000
    network:
      binding: 0.0.0.0:8000
    tls:
      enabled: true

flow:
  - name: v2-flow
    filter:
      - elasticsearch:
          elasticsearch: v2
  - name: v7-flow
    filter:
      - elasticsearch:
          elasticsearch: v7
  - name: cross-cluster-search
    filter:
      - switch:
          path_rules:
            - prefix: "v2:"
              flow: v2-flow
            - prefix: "v7:"
              flow: v7-flow
      - elasticsearch:
          elasticsearch: v7

router:
  - name: my_router
    default_flow: cross-cluster-search

elasticsearch:
  - name: v2
    enabled: true
    endpoint: https://192.168.3.188:9202
  - name: v7
    enabled: true
    endpoint: https://192.168.3.188:9206

小结

好了,今天给大家分享的如何使用极限网关来进行 Elasticsearch 跨集群跨版本的操作就到这里了,希望大家周末玩的开心。😁

继续阅读 »

使用场景

如果你的业务需要用到有多个集群,并且版本还不一样,是不是管理起来很麻烦,如果能够通过一个 API 来进行查询就方便了,聪明的你相信已经想到了 CCS,没错用 CCS 可以实现跨集群的查询,不过 Elasticsearch 提供的 CCS 对版本有一点的限制,并且需要提前做好 mTLS,也就是需要提前配置好两个集群之间的证书互信,这个免不了要重启维护,好像有点麻烦,那么问题来咯,有没有更好的方案呢?

😁 有办法,今天我就给大家介绍一个基于极限网关的方案,极限网关的网址:。

假设现在有两个集群,一个集群是 v2.4.6,有不少业务数据,舍不得删,里面有很多好东西 :)还有一个集群是 v7.14.0,版本还算比较新,业务正在做的一个新的试点,没什么好东西,但是也得用 :(,现在老板们的的需求是希望通过在一个统一的接口就能访问这些数据,程序员懒得很,懂得都懂。

集群信息

  • v2.4.6 集群的访问入口地址:192.168.3.188:9202
  • v7.14.0 集群的访问入口地址:192.168.3.188:9206

这两个集群都是 http 协议的。

实现步骤

今天用到的是极限网关的 switch 过滤器:

网关下载下来就两个文件,一个主程序,一个配置文件,记得下载对应操作系统的包。

定义两个集群资源

elasticsearch:
  - name: v2
    enabled: true
    endpoint: https://192.168.3.188:9202
  - name: v7
    enabled: true
    endpoint: https://192.168.3.188:9206

上面定义了两个集群,分别命名为 v2v7,待会会用到这些资源。

定义一个服务入口

entry:
  - name: my_es_entry
    enabled: true
    router: my_router
    max_concurrency: 1000
    network:
      binding: 0.0.0.0:8000
    tls:
      enabled: true

这里定义了一个名为 my_es_entry 的资源入口,并引用了一个名为 my_router 的请求转发路由,同时绑定了网卡的 0.0.0.0:8000 也就是所有本地网卡监听 IP 的 8000 端口,访问任意 IP 的 8000 端口就能访问到这个网关了。

另外老板也说了,Elasticsearch 用 HTTP 协议简直就是裸奔,通过这里开启 tls,可以让网关对外提供的是 HTTPS 协议,这样用户连接的 Elasticsearch 服务就自带 buffer 了,后端的 es 集群和网关直接可以做好网络流量隔离,集群不用动,简直完美。

为什么定义 TLS 不用指定证书,好用的软件不需要这么麻烦,就这样,不解释。

最后,通过设置 max_concurrency 为 1000,限制下并发数,避免野猴子把我们的后端的 Elasticsearch 给压挂了。

定义一个请求路由

router:
  - name: my_router
    default_flow: cross-cluster-search

这里的名称 my_router 就是表示上面的服务入口的router 参数指定的值。

另外设置一个 default_flow 来将所有的请求都转发给一个名为 cross-cluster-search 的请求处理流程,还没定义,别急,马上。

定义请求处理流程

来啦,来啦,先定义两个 flow,如下,分别名为 v2-flowv7-flow,每节配置的 filter 定义了一系列过滤器,用来对请求进行处理,这里就用了一个 elasticsearch 过滤器,也就是转发请求给指定的 Elasticsearch 后端服务器,了否?

flow:
  - name: v2-flow
    filter:
      - elasticsearch:
          elasticsearch: v2
  - name: v7-flow
    filter:
      - elasticsearch:
          elasticsearch: v7

然后,在定义额外一个名为 cross-cluster-search 的 flow,如下:

  - name: cross-cluster-search
    filter:
      - switch:
          path_rules:
            - prefix: "v2:"
              flow: v2-flow
            - prefix: "v7:"
              flow: v7-flow

这个 flow 就是通过请求的路径的前缀来进行路由的过滤器,如果是 v2:开头的请求,则转发给 v2-flow 继续处理,如果是 v7: 开头的请求,则转发给 v7-flow 来处理,使用的用法和 CCS 是一样的。so easy!

对了,那是不是每个请求都需要加前缀啊,费事啊,没事,在这个 cross-cluster-search 的 filter 最后再加上一个 elasticsearch filter,前面前缀匹配不上的都会走它,假设默认都走 v7,最后完整的 flow 配置如下:

flow:
  - name: v2-flow
    filter:
      - elasticsearch:
          elasticsearch: v2
  - name: v7-flow
    filter:
      - elasticsearch:
          elasticsearch: v7
  - name: cross-cluster-search
    filter:
      - switch:
          path_rules:
            - prefix: "v2:"
              flow: v2-flow
            - prefix: "v7:"
              flow: v7-flow
      - elasticsearch:
          elasticsearch: v7              

然后就没有然后了,因为就配置这些就行了。

启动网关

假设配置文件的路径为 sample-configs/cross-cluster-search.yml,运行如下命令:

➜  gateway git:(master) ✗ ./bin/gateway -config sample-configs/cross-cluster-search.yml
   ___   _   _____  __  __    __  _       
  / _ \ /_\ /__   \/__\/ / /\ \ \/_\ /\_/\
 / /_\///_\\  / /\/_\  \ \/  \/ //_\\\_ _/
/ /_\\/  _  \/ / //__   \  /\  /  _  \/ \ 
\____/\_/ \_/\/  \__/    \/  \/\_/ \_/\_/ 

[GATEWAY] A light-weight, powerful and high-performance elasticsearch gateway.
[GATEWAY] 1.0.0_SNAPSHOT, 2021-10-15 16:25:56, 3d0a1cd
[10-16 11:00:52] [INF] [app.go:228] initializing gateway.
[10-16 11:00:52] [INF] [instance.go:24] workspace: data/gateway/nodes/0
[10-16 11:00:52] [INF] [api.go:260] api listen at: https://0.0.0.0:2900
[10-16 11:00:52] [INF] [reverseproxy.go:257] elasticsearch [v7] hosts: [] => [192.168.3.188:9206]
[10-16 11:00:52] [INF] [entry.go:225] auto generating cert files
[10-16 11:00:52] [INF] [actions.go:223] elasticsearch [v2] is available
[10-16 11:00:52] [INF] [actions.go:223] elasticsearch [v7] is available
[10-16 11:00:53] [INF] [entry.go:296] entry [my_es_entry] listen at: https://0.0.0.0:8000
[10-16 11:00:53] [INF] [app.go:309] gateway is running now.

可以看到网关输出了启动成功的日志,网关服务监听在 https://0.0.0.0:8000

试试访问网关

直接访问网关的 8000 端口,因为是网关自签的证书,加上 -k 来跳过证书的校验,如下:

➜  loadgen git:(master) ✗ curl -k   https://localhost:8000  
{
  "name" : "LENOVO",
  "cluster_name" : "es-v7140",
  "cluster_uuid" : "npWjpIZmS8iP_p3GK01-xg",
  "version" : {
    "number" : "7.14.0",
    "build_flavor" : "default",
    "build_type" : "zip",
    "build_hash" : "dd5a0a2acaa2045ff9624f3729fc8a6f40835aa1",
    "build_date" : "2021-07-29T20:49:32.864135063Z",
    "build_snapshot" : false,
    "lucene_version" : "8.9.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

正如前面配置所配置的一样,默认请求访问的就是 v7 集群。

访问 v2 集群

➜  loadgen git:(master) ✗ curl -k   https://localhost:8000/v2:/    
{
  "name" : "Solomon O'Sullivan",
  "cluster_name" : "es-v246",
  "cluster_uuid" : "cqlpjByvQVWDAv6VvRwPAw",
  "version" : {
    "number" : "2.4.6",
    "build_hash" : "5376dca9f70f3abef96a77f4bb22720ace8240fd",
    "build_timestamp" : "2017-07-18T12:17:44Z",
    "build_snapshot" : false,
    "lucene_version" : "5.5.4"
  },
  "tagline" : "You Know, for Search"
}

查看集群信息:

➜  loadgen git:(master) ✗ curl -k   https://localhost:8000/v2:_cluster/health\?pretty
{
  "cluster_name" : "es-v246",
  "status" : "yellow",
  "timed_out" : false,
  "number_of_nodes" : 1,
  "number_of_data_nodes" : 1,
  "active_primary_shards" : 5,
  "active_shards" : 5,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 5,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 50.0
}

插入一条文档:

➜  loadgen git:(master) ✗ curl-json -k   https://localhost:8000/v2:medcl/doc/1 -d '{"name":"hello world"}'
{"_index":"medcl","_type":"doc","_id":"1","_version":1,"_shards":{"total":2,"successful":1,"failed":0},"created":true}%  

执行一个查询

➜  loadgen git:(master) ✗ curl -k   https://localhost:8000/v2:medcl/_search\?q\=name:hello                
{"took":78,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":0.19178301,"hits":[{"_index":"medcl","_type":"doc","_id":"1","_score":0.19178301,"_source":{"name":"hello world"}}]}}% 

可以看到,所有的请求,不管是集群的操作,还是索引的增删改查都可以,而 Elasticsearch 自带的 CCS 是只读的,只能进行查询。

访问 v7 集群

➜  loadgen git:(master) ✗ curl -k   https://localhost:8000/v7:/
{
  "name" : "LENOVO",
  "cluster_name" : "es-v7140",
  "cluster_uuid" : "npWjpIZmS8iP_p3GK01-xg",
  "version" : {
    "number" : "7.14.0",
    "build_flavor" : "default",
    "build_type" : "zip",
    "build_hash" : "dd5a0a2acaa2045ff9624f3729fc8a6f40835aa1",
    "build_date" : "2021-07-29T20:49:32.864135063Z",
    "build_snapshot" : false,
    "lucene_version" : "8.9.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

Kibana 里面访问

完全没问题,有图有真相:

Jietu20211016-114041.jpg

其他操作也类似,就不重复了。

完整的配置

path.data: data
path.logs: log

entry:
  - name: my_es_entry
    enabled: true
    router: my_router
    max_concurrency: 10000
    network:
      binding: 0.0.0.0:8000
    tls:
      enabled: true

flow:
  - name: v2-flow
    filter:
      - elasticsearch:
          elasticsearch: v2
  - name: v7-flow
    filter:
      - elasticsearch:
          elasticsearch: v7
  - name: cross-cluster-search
    filter:
      - switch:
          path_rules:
            - prefix: "v2:"
              flow: v2-flow
            - prefix: "v7:"
              flow: v7-flow
      - elasticsearch:
          elasticsearch: v7

router:
  - name: my_router
    default_flow: cross-cluster-search

elasticsearch:
  - name: v2
    enabled: true
    endpoint: https://192.168.3.188:9202
  - name: v7
    enabled: true
    endpoint: https://192.168.3.188:9206

小结

好了,今天给大家分享的如何使用极限网关来进行 Elasticsearch 跨集群跨版本的操作就到这里了,希望大家周末玩的开心。😁

收起阅读 »

给Zblogphp插上Elasticsearch的翅膀

# 给Zblogphp插上Elasticsearch的翅膀



找遍了zblog的应用中心,未发现有使用Elasticsearch搜索引擎的插件。国庆闲来无事,根据zblogphp的机制,开发了一个基于Elasticsearch的插件。

本插件使用简单,需要有一个Elasticsearch7.x的环境(基于7.x版本开发),Elasticsearch 安装[IK](k)、[pinyin](n),[足球简繁體转换](t) 插件。安装好该插件后,只需要配置好账号密码,点击创建索引模板即可。发布和编辑文章时,会自动根据索引模板,创建post索引,同步文章数据。搜索时,直接接管原有的搜索逻辑,无需调整程序和模板。

后台配置截图:


123.jpg



配置好连接,端口,账号和密码,点击“测试连接”,弹出连接成功,展示版本号,即可点击保存配置,如果这4项错误,连接不上Elasticsearch,获取不到ES的版本号,将无法保存配置。



Dingtalk_20211009115321.jpg




看到这个提示,便可以点击“保持配置”。这里有一项“切换搜索 Elasticsearch”,开启,前端搜索即切换到了Elastisearch搜索引擎。


234.jpg



在配置好了基本设置以后,点击索引模板,可以预览到索引模板,点击“创建索引模板”,即可在Elasticsearch服务器创建好索引模板,成功后,会在说明栏展示绿色的“已创建”,如果未创建,展示红色的“未创建”。发布和编辑文章时,会根据该索引模板,自动创建好索引,同步文章。



以下是搜索效果截图:

345.jpg

继续阅读 »
# 给Zblogphp插上Elasticsearch的翅膀



找遍了zblog的应用中心,未发现有使用Elasticsearch搜索引擎的插件。国庆闲来无事,根据zblogphp的机制,开发了一个基于Elasticsearch的插件。

本插件使用简单,需要有一个Elasticsearch7.x的环境(基于7.x版本开发),Elasticsearch 安装[IK](k)、[pinyin](n),[足球简繁體转换](t) 插件。安装好该插件后,只需要配置好账号密码,点击创建索引模板即可。发布和编辑文章时,会自动根据索引模板,创建post索引,同步文章数据。搜索时,直接接管原有的搜索逻辑,无需调整程序和模板。

后台配置截图:


123.jpg



配置好连接,端口,账号和密码,点击“测试连接”,弹出连接成功,展示版本号,即可点击保存配置,如果这4项错误,连接不上Elasticsearch,获取不到ES的版本号,将无法保存配置。



Dingtalk_20211009115321.jpg




看到这个提示,便可以点击“保持配置”。这里有一项“切换搜索 Elasticsearch”,开启,前端搜索即切换到了Elastisearch搜索引擎。


234.jpg



在配置好了基本设置以后,点击索引模板,可以预览到索引模板,点击“创建索引模板”,即可在Elasticsearch服务器创建好索引模板,成功后,会在说明栏展示绿色的“已创建”,如果未创建,展示红色的“未创建”。发布和编辑文章时,会根据该索引模板,自动创建好索引,同步文章。



以下是搜索效果截图:

345.jpg

收起阅读 »

通过python脚本迁移ES的template模板

通过python脚本迁移ES的template模板

通过python脚本迁移ES的template模板,从192.168.0.1 迁移到 192.168.0.2

import base64
import json

import requests

def putTemplate(templateName, templateDslJson):
    print("{0} 索引模板正在迁移中".format(templateName))

    res = requests.put("https://192.168.0.2:9200/_template/{0}".format(templateName), json=templateDslJson)
    print(res.status_code)
    print(res.content)

def getTemplateDslJson():
    username = "elastic"
    password = "123456"
    user_info_str = username + ":" + password
    user_info = base64.b64encode(user_info_str.encode())  # 这个得到是个字节类型的数据
    headers = {
        "Authorization": "Basic {0}".format(user_info.decode())  # 这个就是需要验证的信息
    }
    url = "https://192.168.0.1:9200/_template/*_template"
    res = requests.get(url, headers=headers)
    print(res.status_code)
    return json.loads(res.content)

if __name__ == '__main__':
    jsonTemplate = getTemplateDslJson()
    if isinstance(jsonTemplate, dict):
        for templateName in jsonTemplate:
            templateDslJson = jsonTemplate[templateName]
            putTemplate(templateName, templateDslJson)
继续阅读 »

通过python脚本迁移ES的template模板

通过python脚本迁移ES的template模板,从192.168.0.1 迁移到 192.168.0.2

import base64
import json

import requests

def putTemplate(templateName, templateDslJson):
    print("{0} 索引模板正在迁移中".format(templateName))

    res = requests.put("https://192.168.0.2:9200/_template/{0}".format(templateName), json=templateDslJson)
    print(res.status_code)
    print(res.content)

def getTemplateDslJson():
    username = "elastic"
    password = "123456"
    user_info_str = username + ":" + password
    user_info = base64.b64encode(user_info_str.encode())  # 这个得到是个字节类型的数据
    headers = {
        "Authorization": "Basic {0}".format(user_info.decode())  # 这个就是需要验证的信息
    }
    url = "https://192.168.0.1:9200/_template/*_template"
    res = requests.get(url, headers=headers)
    print(res.status_code)
    return json.loads(res.content)

if __name__ == '__main__':
    jsonTemplate = getTemplateDslJson()
    if isinstance(jsonTemplate, dict):
        for templateName in jsonTemplate:
            templateDslJson = jsonTemplate[templateName]
            putTemplate(templateName, templateDslJson)
收起阅读 »

Elastic:使用 docker 来安装 Elastic Stack 8.0-alpha2

Elastic Stack 8.0.0-alpha2 刚刚发布,这是一个快速(非官方)的启动和运行指南。 更多功能、文档和公告即将发布,但冒险者已经开始:在几分钟内启动并运行 Docker 上的 Elasticsearch、Kibana 和 Agent。

请注意:

这是一个 alpha 发布版。 仅将其用于测试,不要指望最终能够升级到 8.0.0 版本最终版本。
期待将会有一些这样或者那样的 bug。 这就是我们再次运行 Elastic Pioneer Program  的原因,以便我们可以解决尽可能多的问题。
这是保持简单的最小示例,例如跳过 TLS 证书(尽管这可能会改变)。 请不要将其用作生产环境。
在今天的文章中,我将详细地介绍如何安装 Elastic Stack 8.0-alpha2 版本。

原文链接:
继续阅读 »
Elastic Stack 8.0.0-alpha2 刚刚发布,这是一个快速(非官方)的启动和运行指南。 更多功能、文档和公告即将发布,但冒险者已经开始:在几分钟内启动并运行 Docker 上的 Elasticsearch、Kibana 和 Agent。

请注意:

这是一个 alpha 发布版。 仅将其用于测试,不要指望最终能够升级到 8.0.0 版本最终版本。
期待将会有一些这样或者那样的 bug。 这就是我们再次运行 Elastic Pioneer Program  的原因,以便我们可以解决尽可能多的问题。
这是保持简单的最小示例,例如跳过 TLS 证书(尽管这可能会改变)。 请不要将其用作生产环境。
在今天的文章中,我将详细地介绍如何安装 Elastic Stack 8.0-alpha2 版本。

原文链接: 收起阅读 »

Elastic 7.15 版:数秒之内打造强大的个性化搜索体验

我们很高兴地宣布 Elastic 7.15 版正式发布,这个版本为 Elastic Search Platform(包括 Elasticsearch 和 Kibana)及其三个内置解决方案(Elastic Enterprise Search、Elastic 可观测性和 Elastic 安全)带来一系列广泛的全新功能。

在 Elastic 7.15 版中,正式推出了 Elastic App Search 网络爬虫,并与 Google Cloud 实现了更加紧密的集成 — 这让我们的客户和社区能够更快地打造强大的新网络搜索体验,更快速、更安全地采集数据,并更轻松地利用搜索的力量让数据发挥作用。

此外,借助 Elastic 可观测性中新增的 APM 关联功能,DevOps 团队可以通过自动显现与高延迟或错误事务关联的属性,加快根本原因分析的速度并缩短平均解决时间 (MTTR)。

而且,俗话说得好,一不做二不休,如果打算要观测……何不(同时)保护呢?

为此,在 Elastic 7.15 版中,Elastic 安全对 Limitless XDR(扩展检测与响应)进行了增强,既能够为几乎所有的操作系统提供恶意行为保护功能,又能够为云原生 Linux 环境提供一键式主机隔离功能。
 
继续阅读 »
我们很高兴地宣布 Elastic 7.15 版正式发布,这个版本为 Elastic Search Platform(包括 Elasticsearch 和 Kibana)及其三个内置解决方案(Elastic Enterprise Search、Elastic 可观测性和 Elastic 安全)带来一系列广泛的全新功能。

在 Elastic 7.15 版中,正式推出了 Elastic App Search 网络爬虫,并与 Google Cloud 实现了更加紧密的集成 — 这让我们的客户和社区能够更快地打造强大的新网络搜索体验,更快速、更安全地采集数据,并更轻松地利用搜索的力量让数据发挥作用。

此外,借助 Elastic 可观测性中新增的 APM 关联功能,DevOps 团队可以通过自动显现与高延迟或错误事务关联的属性,加快根本原因分析的速度并缩短平均解决时间 (MTTR)。

而且,俗话说得好,一不做二不休,如果打算要观测……何不(同时)保护呢?

为此,在 Elastic 7.15 版中,Elastic 安全对 Limitless XDR(扩展检测与响应)进行了增强,既能够为几乎所有的操作系统提供恶意行为保护功能,又能够为云原生 Linux 环境提供一键式主机隔离功能。
 
收起阅读 »

Elasticsearch:分页搜索结果

随着时间点 API(Point in time API)的推出,根据 Elastic 的官方博客 “使用 Elasticsearch 时间点读取器获得随时间推移而保持一致的数据视图”,Scroll 接口将不被推荐作为对搜索结果的分页。

默认情况下,搜索会返回前 10 个匹配的匹配项。 要翻阅更大的结果集,你可以使用搜索 API 的 from 和 size 参数。 from 参数定义要跳过的命中数,默认为 0。 size 参数是要返回的最大命中数。 这两个参数共同定义了一页结果。比如:

GET /twitter/_search
{
  "from": 5,
  "size": 20,
  "query": {
    "match": {
      "city": "北京"
    }
  }
}

避免使用 from 和 size 来分页太深或一次请求太多结果。 搜索请求通常跨越多个分片。 每个分片必须将其请求的命中和任何先前页面的命中加载到内存中。 对于深页面或大型结果集,这些操作会显着增加内存和 CPU 使用率,从而导致性能下降或节点故障。这里的原因是 index.max_result_window 的默认值是 10K,也就是说 from+size 的最大值是1万。搜索请求占用堆内存和时间与 from+size 成比例,这限制了内存。假如你想 hit 从 990 到 1000,那么每个 shard 至少需要 1000 个文档:

原文链接:
继续阅读 »
随着时间点 API(Point in time API)的推出,根据 Elastic 的官方博客 “使用 Elasticsearch 时间点读取器获得随时间推移而保持一致的数据视图”,Scroll 接口将不被推荐作为对搜索结果的分页。

默认情况下,搜索会返回前 10 个匹配的匹配项。 要翻阅更大的结果集,你可以使用搜索 API 的 from 和 size 参数。 from 参数定义要跳过的命中数,默认为 0。 size 参数是要返回的最大命中数。 这两个参数共同定义了一页结果。比如:

GET /twitter/_search
{
  "from": 5,
  "size": 20,
  "query": {
    "match": {
      "city": "北京"
    }
  }
}

避免使用 from 和 size 来分页太深或一次请求太多结果。 搜索请求通常跨越多个分片。 每个分片必须将其请求的命中和任何先前页面的命中加载到内存中。 对于深页面或大型结果集,这些操作会显着增加内存和 CPU 使用率,从而导致性能下降或节点故障。这里的原因是 index.max_result_window 的默认值是 10K,也就是说 from+size 的最大值是1万。搜索请求占用堆内存和时间与 from+size 成比例,这限制了内存。假如你想 hit 从 990 到 1000,那么每个 shard 至少需要 1000 个文档:

原文链接: 收起阅读 »