分词匹对,分值问题,如何提高精确度

xiaowuge 回复了问题 • 3 人关注 • 2 个回复 • 175 次浏览 • 2021-12-18 08:25 • 来自相关话题

elasticsearch7.x关闭大索引出现集群状态为red

medcl 回复了问题 • 2 人关注 • 1 个回复 • 297 次浏览 • 2021-12-20 09:36 • 来自相关话题

circuit_breaking_exception 自动恢复

回复

liujiacheng 回复了问题 • 2 人关注 • 2 个回复 • 187 次浏览 • 2021-12-23 09:39 • 来自相关话题

CVE-2021-44228对ElasticSearch的影响

laoyang360 回复了问题 • 4 人关注 • 3 个回复 • 549 次浏览 • 2021-12-17 14:34 • 来自相关话题

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

medcl 发表了文章 • 2 个评论 • 2665 次浏览 • 2021-12-11 03:57 • 来自相关话题

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

【CVE 地址】

[https://github.com/advisories/GHSA-jfh8-c2jp-5v3q](https://github.com/advisories/GHSA-jfh8-c2jp-5v3q)

【漏洞描述】

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,新增以下参数,重启集群所有节点即可。
<br /> -Dlog4j2.formatMsgNoLookups=true<br />

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

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

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

参考配置


下载最新的 1.5.0-SNAPSHOT 版本[http://release.elasticsearch.cn/gateway/snapshot/](http://release.elasticsearch.cn/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:
    • http://localhost:9200
      <br /> <br /> 启动网关:<br /> ````<br /> ➜ ./bin/gateway -config /tmp/gateway.yml<br /> ___ _ _____ __ __ __ _ <br /> / _ \ /_\ /__ \/__\/ / /\ \ \/_\ /\_/\<br /> / /_\///_\\ / /\/_\ \ \/ \/ //_\\\_ _/<br /> / /_\\/ _ \/ / //__ \ /\ / _ \/ \ <br /> \____/\_/ \_/\/ \__/ \/ \/\_/ \_/\_/ <br /> <br /> [GATEWAY] A light-weight, powerful and high-performance elasticsearch gateway.<br /> [GATEWAY] 1.0.0_SNAPSHOT, 2021-12-10 23:55:34, 2212aff<br /> [12-11 01:55:49] [INF] [app.go:250] initializing gateway.<br /> [12-11 01:55:49] [INF] [instance.go:26] workspace: /Users/medcl/go/src/infini.sh/gateway/data/gateway/nodes/0<br /> [12-11 01:55:49] [INF] [api.go:261] api listen at: <a href="http://0.0.0.0:2900" rel="nofollow" target="_blank">http://0.0.0.0:2900</a><br /> [12-11 01:55:49] [INF] [reverseproxy.go:253] elasticsearch [es-server] hosts: [] => [localhost:9200]<br /> [12-11 01:55:49] [INF] [entry.go:296] entry [es_entrypoint] listen at: <a href="http://0.0.0.0:8000" rel="nofollow" target="_blank">http://0.0.0.0:8000</a><br /> [12-11 01:55:49] [INF] [module.go:116] all modules started<br /> [12-11 01:55:49] [INF] [app.go:357] gateway is running now.<br /> [12-11 01:55:49] [INF] [actions.go:236] elasticsearch [es-server] is available<br />

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

      不走网关:
      <br /> ~% curl 'http://localhost:9200/index1/_search?q=%24%7Bjava%3Aos%7D' <br /> {"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}% <br />
      查看 Elasticsearch 端日志为:
      <br /> [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}<br /> org.elasticsearch.index.IndexNotFoundException: no such index<br /> at org.elasticsearch.cluster.metadata.IndexNameExpressionResolver$WildcardExpressionResolver.infe(IndexNameExpressionResolver.java:678) ~[elasticsearch-5.6.15.jar:5.6.15]<br /> at org.elasticsearch.cluster.metadata.IndexNameExpressionResolver$WildcardExpressionResolver.innerResolve(IndexNameExpressionResolver.java:632) ~[elasticsearch-5.6.15.jar:5.6.15]<br /> at org.elasticsearch.cluster.metadata.IndexNameExpressionResolver$WildcardExpressionResolver.resolve(IndexNameExpressionResolver.java:580) ~[elasticsearch-5.6.15.jar:5.6.15]<br /> <br />
      可以看到查询条件里面的 q=${java:os} 被执行了,变成了 q=Mac OS X 10.13.4 unknown, architecture: x86_64-64, index=index1,说明变量被解析且执行,存在漏洞利用的风险。

      那走网关之后呢:
      <br /> ~% curl 'http://localhost:8000/index1/_search?q=%24%7Bjava%3Aos%7D' <br /> <br /> Apache Log4j 2, Boom!% <br />
      可以看到请求被过滤掉了,返回了自定义的信息。

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

      ```

      {java:vm}

      ~% curl 'http://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 'http://localhost:8000/index/_search?q=%24%7Bjava%3Avm%7D'
      Apache Log4j 2, Boom!%

      {jndi:rmi://localhost:1099/api}

      ~% curl 'http://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 'http://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 服务器不用做任何变动,尤其是大规模集群的场景,可以节省大量的工作,提升效率,非常灵活,缩短安全处置的时间,降低企业风险。

分组后获取指定的分组字段值的排名

caster_QL 回复了问题 • 3 人关注 • 1 个回复 • 161 次浏览 • 2021-12-13 10:14 • 来自相关话题

geohash_cell替代方案是啥

回复

xxw 发起了问题 • 1 人关注 • 0 个回复 • 165 次浏览 • 2021-12-09 15:51 • 来自相关话题

match_phrase_prefix返回结果如何使越靠前的单词占有的权重越高,排序更靠前

xiaowuge 回复了问题 • 4 人关注 • 2 个回复 • 292 次浏览 • 2021-12-10 09:17 • 来自相关话题

dis_max查询速度慢的问题

Freeflying 回复了问题 • 4 人关注 • 4 个回复 • 236 次浏览 • 2021-12-20 17:25 • 来自相关话题

如何定位慢查询请求或错误查询请求的访问Ip

caster_QL 回复了问题 • 3 人关注 • 2 个回复 • 264 次浏览 • 2021-12-10 11:35 • 来自相关话题

es进程占用内存持续增加,快爆了

cap_ljf 回复了问题 • 5 人关注 • 3 个回复 • 380 次浏览 • 2021-12-07 20:02 • 来自相关话题

7.9.1使用bulkprocessor 产生死锁

回复

wanghaiyu1997 发起了问题 • 1 人关注 • 0 个回复 • 213 次浏览 • 2021-12-02 22:07 • 来自相关话题

es的统计监控里观察到 index的次数和get的次数对不上

回复

code4j 发起了问题 • 1 人关注 • 0 个回复 • 242 次浏览 • 2021-12-02 15:02 • 来自相关话题

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

verdantyang 发表了文章 • 1 个评论 • 933 次浏览 • 2021-12-01 14:07 • 来自相关话题

前言

对于广大 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的争用,进而产生频繁的缺页中断,相关问题可参考[https://github.com/elastic/ela ... 27748](https://github.com/elastic/ela ... /27748)



    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的开源工具([https://github.com/tobert/pcstat](https://github.com/tobert/pcstat)),开发初衷是用于监控 Cassandra 中 ssTables 的占用情况。


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

    源码地址

    [https://github.com/zhangdapao995/es-pcstat](https://github.com/zhangdapao995/es-pcstat)

    功能点

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


    运行环境

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



    功能项

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



      获取可执行文件

      linux_x64

      linux 64位可通过如下命令获取可执行文件
      json<br /> curl -L -o es-pcstat <a href="https://gitee.com/verdant/es-pcstat/attach_files/835465/download/es-pcstat-linux-x64" rel="nofollow" target="_blank">https://gitee.com/verdant/es-p ... x-x64</a><br /> chmod 755 es-pcstat<br />

      mac

      mac 64位可通过如下命令获取可执行文件
      json<br /> curl -L -o es-pcstat <a href="https://gitee.com/verdant/es-pcstat/attach_files/835463/download/es-pcstat-darwin-x64" rel="nofollow" target="_blank">https://gitee.com/verdant/es-p ... n-x64</a><br /> chmod 755 es-pcstat<br />


      运行

      执行命令
      shell<br /> ./es-pcstat [parameters] <config_file><br /> <br /> 例:./es-pcstat -collectIntervalFlag=30 -sortFlag=true ./es.conf<br />


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


      配置文件

      配置文件需填写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 |



      ```json

      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
      ```


      输出模式

      控制台输出

      执行命令
      shell<br /> ./es-pcstat -collectIntervalFlag=30 -sortFlag=true ./es.conf<br />
      结果示例
      json<br /> <br /> <br /> | index_name | cache (MB) | pri cache | rep cache |<br /> +---------------------------------------+------------+------------+------------+<br /> | fusion-media.task.task | 247 | 247 | 0 |<br /> | total | 247 | 247 | 0 |<br /> +---------------------------------------+------------+------------+------------+<br /> <br />

      日志输出

      执行命令
      shell<br /> ./es-pcstat -outputTypeFlag=log ./es.conf<br />
      对应日志文件得到的内容,日志可进一步通过日志服务采集分析(如阿里云sls等)
      json<br /> {"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"}<br />


      ES 输出

      执行命令
      json<br /> ./es-pcstat -outputTypeFlag=es ./es.conf<br />
      运行后会将采集到的数据回写到被监控的 ES 集群
      可导入kibana仪表盘配置文件[es-pcstat-kibana.json](https://xhzy.yuque.com/attachm ... 2%257D),通过图表进行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://elasticsearch.cn/question/11062](https://elasticsearch.cn/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 的监控可能能提供一定的帮助,当然还有更多的作用等待我们去探索。


    参考链接

    [https://github.com/tobert/pcstat](https://github.com/tobert/pcstat)
    [https://www.amazingkoala.com.c ... .html](https://www.amazingkoala.com.c ... 5.html)
    [https://www.elastic.co/guide/e ... .html](https://www.elastic.co/guide/e ... e.html)

请教大家一个集群机器配置问题,求解答,万分感谢

caster_QL 回复了问题 • 2 人关注 • 1 个回复 • 244 次浏览 • 2021-12-03 15:34 • 来自相关话题