查看缓存占用的内存数量

基于一个 8 节点集群,查询 QPS 大概 30 左右。通过 node 信息查看请求缓存

curl localhost:9200/_nodes/stats/indices/request_cache?pretty

执行结果:


{
"_nodes" : {
"total" : 8,
"successful" : 8,
"failed" : 0
},
"cluster_name" : "moka-es",
"nodes" : {
"4FbqP65LTf-uwF1sGZAnQQ" : {
"timestamp" : 1597291580728,
"name" : "es-node-3",
"transport_address" : "172.17.240.18:9300",
"host" : "172.17.240.18",
"ip" : "172.17.240.18:9300",
"roles" : [
"master",
"data",
"ingest"
],
"attributes" : {
"ml.machine_memory" : "33738051584",
"ml.max_open_jobs" : "20",
"xpack.installed" : "true",
"ml.enabled" : "true"
},
"indices" : {
"request_cache" : {
"memory_size_in_bytes" : 53328,
"evictions" : 0,
"hit_count" : 1395,
"miss_count" : 10267
}
}
},
"q0_ZkHoASzqRsGrCVUlQPA" : {
"timestamp" : 1597291580729,
"name" : "es-node-8",
"transport_address" : "172.17.47.73:9300",
"host" : "172.17.47.73",
"ip" : "172.17.47.73:9300",
"roles" : [
"master",
"data",
"ingest"
],
"attributes" : {
"ml.machine_memory" : "32300605440",
"ml.max_open_jobs" : "20",
"xpack.installed" : "true",
"ml.enabled" : "true"
},
"indices" : {
"request_cache" : {
"memory_size_in_bytes" : 16287,
"evictions" : 0,
"hit_count" : 23,
"miss_count" : 74
}
}
},

....

结果比较奇怪,相较于每个节点 32GB 的内存,几百 kb 的换存量几乎相当于没有缓存任何请求结果。

而随便找一台测试用的单机 es ,缓存量反而比上面集群的缓存总和还要多:

{
"_nodes" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"cluster_name" : "elasticsearch",
"nodes" : {
"ccC4H-1mR4apSB5pgR6yXw" : {
"timestamp" : 1597292348183,
"name" : "ccC4H-1",
"transport_address" : "172.17.46.126:9300",
"host" : "172.17.46.126",
"ip" : "172.17.46.126:9300",
"roles" : [
"master",
"data",
"ingest"
],
"attributes" : {
"ml.machine_memory" : "33191542784",
"xpack.installed" : "true",
"ml.max_open_jobs" : "20",
"ml.enabled" : "true"
},
"indices" : {
"request_cache" : {
"memory_size_in_bytes" : 2653163,
"evictions" : 0,
"hit_count" : 1353,
"miss_count" : 2439
}
}
}
}
}

什么样的 query 会被 cache ?

It is not possible to look at the contents being cached.

而且除非自己 log,es 也没办法看到 query history(?)我们只能通过 node API,index 级别的配置和 query type 去判断缓存的使用情况。

这里不同的 doc 、书、网上的文章说的有点出入。在我的理解里,只有两种 query cache, node query cache 和 shards query cache。

node query cache

node query cache 只保留 filter 类型的 query result。

es 的 node query cache 默认是开启的,基于 LRU(least recently use),当缓存达到上限,一条新缓存出现的同时会驱逐(evict)最近最少使用的那一条。

从 query 类型来看,除了 filter 类型的 query ,其他任何类型的 query 结果都不会被缓存。从数量和大小来看,默认会保存最多一万条或最多 10% 的 heap size 的 query。因 cache 基于 segment, 当 segment(一个真实的倒排索引文件)的 doc 数量小于一万条或小于当前 shards 的 3% 或者总的请求数量过小时,都不会触发 cache。

shard request cache

shard request cache 就是把在各个 shard 上执行的 query 本地结果缓存下来。 一样也是 LRU 机制。他会缓存频繁请求的结果或者通过对每一个 query 手动添加 request_cache=true 来决定一个请求是否触发缓存。

注意,这里默认只会缓存 size = 0 的 query 结果,也就是一些可以不在意 hits 的 query,比如 aggregation,suggestion。这意味着如果不手动标识,日常针对普通 field 的搜索想要召回具体命中 doc 的 query 全部不会被缓存。这也解释了为什么上述的集群几乎没有 request cache。

其他方案

其他的缓存方案大同小异,就是在得到结果后,配合 query 做一个 k-v 形式的缓存,区别只是缓存选型、数据更新、缓存过期时间上的处理。例如这个 利用 Redis 做缓存

参考

Mastering Elasticsearch
ElasticSearch Cache Usage
Query Cache