Elasticsearch 查询的响应需要占用 CPU、内存资源,在复杂业务场景,会出现慢查询,需要花费大量的时间。
如何破局呢?增加集群硬件配置会有高昂硬件开销。还有没有其他方案呢?这时候会想到:缓存。
Elasticsearch 有哪些缓存,不同缓存的应用场景是什么呢?本文给出答案。
以上问题都是实战业务场景的问题。
filter 过滤查询的结果缓存在节点查询缓存中,以便快速查找。
每个节点都有一个所有分片共享的查询缓存。缓存使用 LRU ( Least Recently Used 缓存淘汰策略)策略,当缓存已满时,优先清理最近最少使用的查询结果,以腾出空间存放新结果数据。
用户无法查看节点查询缓存的内容。
默认情况下,节点查询缓存最多可容纳10000个查询,最多占总堆空间的10%。
为了确定查询是否符合缓存条件,Elasticsearch 维护查询历史记录以跟踪事件的发生。
如果一个段至少包含 10000 个文档,并且该段具有超过一个分片的文档总数的 3% 的文档数,则按每个段进行缓存。由于缓存是按段划分的,因此合并段可使缓存的查询无效。
说一下静态配置(static)和 动态配置 (dynamic)配置的本质区别:
配置1:indices.queries.cache.size
配置2:index.queries.cache.enabled
PUT my_index_0003
{
"settings": {
"index.queries.cache.enabled": false
}
}
3.2 分片请求缓存(Shard request cache)
当对一个索引或多个索引运行搜索请求时,每个涉及的分片都会在本地执行搜索并将其本地结果返回到协调节点,协调节点将这些分片级结果合并为一个“全局”结果集。
分片级请求缓存在每个分片上缓存本地结果,这使得频繁使用的搜索请求几乎立即返回结果。分片请求缓存非常适合日志用例场景,在这种情况下,数据不会在旧索引上更新,并且可以将常规聚合保留在高速缓存中以供重用。
默认情况下:
刷新间隔(refresh_interval)越长,缓存的条目将保持有效的时间越长。如果缓存已满,将驱逐最近最少使用的缓存。
可以使用 clear_cache API手动使缓存过期,举例如下:
POST /kimchy,elasticsearch/_cache/clear?request=true
PUT my_index
{
"settings": {
"index.requests.cache.enable": false
}
}
PUT /my_index/_settings
{
"index.requests.cache.enable": true
}
如下的设置会覆盖索引级别的缓存设置。
GET /my_index/_search?request_cache=true
{
"size": 0,
"aggs": {
"popular_colors": {
"terms": {
"field": "colors"
}
}
}
}
注意:
第一:如果你的查询使用结果有不确定的脚本(例如,使用随机函数或引用当前时间),则应将request_cache标志设置为false以禁用该请求的缓存。
第二:即使在索引设置中启用了请求缓存,也不会缓存大小大于0(size > 0)的请求。要缓存这些请求,您将需要使用 query-string 参数(详见官方文档)。
缓存是在节点级别进行管理的,默认最大大小为堆的1%。可以使用以下命令在config / elasticsearch.yml 文件中进行更改:
indices.requests.cache.size: 2%
此外,您可以使用 index.requests.cache.expire 设置为缓存的结果指定TTL,但是没有理由这样做(提供此设置仅出于完整性考虑)。
请记住,刷新索引后(refreshed),旧的结果将自动失效。
GET /_stats/request_cache?human
GET /_nodes/stats/indices/request_cache?human
Field data 缓存包含 field data 和 global ordinals,它们均用于支持某些字段类型上的聚合。由于这些都是堆上的数据结构,因此监视缓存的使用非常重要。
Field data 缓存的构建成本很高,因此默认行为是将缓存加载到内存中。默认的缓存大小是无限的,这将导致缓存高速增长直到达到field data断路器设置的限制。
如果设置了 field data 缓存大小限制,同样的,缓存将开始清除缓存中最新最少更新的数据。此设置可以自动避开断路器限制,但需要根据需要重建缓存。
如果达到 field data 断路器限制,Elasticsearch 底层将阻止进一步增加缓存大小的请求。在这种情况下,你应该手动清除缓存。
这里要扩展两个Field data 断路器 配置:
参数1:indices.breaker.fielddata.limit
参数2:indices.breaker.fielddata.overhead
1)百分比,如:38%,代表:堆内存38%。 2)固定值,如:12 GB。
以下两种方法可用于监控:Field data 缓存及 断路器使用情况。
GET /_nodes/stats
GET /_cat/fielddata
全局查看缓存方法
GET _cat/nodes?v&h=id,queryCacheMemory,queryCacheEvictions,requestCacheMemory,requestCacheHitCount,requestCacheMissCount,flushTotal,flushTotalTime
POST /twitter/_cache/clear?query=true
POST /twitter/_cache/clear?request=true
POST /twitter/_cache/clear?fielddata=true
POST /kimchy,elasticsearch/_cache/clear
POST /_cache/clear
缓存类型 | 缓存内容 |
---|---|
节点请求缓存 | 缓存可维护在 filter 上下文中使用的查询结果。 |
分片请求缓存 | 缓存 size = 0 时频繁使用的查询的结果,尤其是聚合的结果。 |
字段请求缓存 (Field data) | 用于排序和支持某些字段类型上的聚合。 |
读到这里,开头的问题的答案自然得出。
特将缓存使用注意事项说明如下:
原因:避免聚合随着用户的翻页(查询)重新计算。
第一:通用 filter 过滤器具有很高的可缓存性,并且计算迅速;
第二:基于评分的 query 是相比 filter 更为昂贵的查询,并且难以缓存。
参考:
1、官方文档
2、https://opster.com/elasticsearch-glossary/elasticsearch-cache/
3、https://opensourceconnections.com
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8