저는 기본적으로 API 단에서 Elasticsearch 로 질의한 결과를 Cache 하도록 구현해서 사용하고 있습니다.
하지만 Elasticsearch 에서도 기본적으로 두 가지의 Cache 기능을 제공 하고 있으니 잘 활용 하시면 좋을 것 같아 기록해 봅니다.
한 줄로 정리 하면)
검색 결과 리스팅은 Query Cache에, 검색 결과에 대한 집계 는 Request Cache 에 저장 된다고 이해 하시면 됩니다.
1. Node Query Cache
공식문서)
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-cache.html
- 이 기능은 Query 에 따른 결과를 Cache하게 되며, LRU 정책으로 동작 합니다.
- 이 기능은 Node 레벨로 동작 합니다.
- 이 기능은 Filter Context 를 사용 했을 경우에만 동작 합니다.
- 아래 설정은 Cluster 내 모든 Data Node 에 설정을 반드시 해야 합니다.
indices.queries.cache.size
- 아래 설정은 Index 별로 설정을 해야 합니다.
index.queries.cache.enabled
2. Shard Request Cache
공식문서)
https://www.elastic.co/guide/en/elasticsearch/reference/current/shard-request-cache.html
- 이 기능은 개별 Local Shard 의 결과를 Cache 합니다.
- 이 기능은 size=0 인 Request 의 결과만 Cache 합니다.
- 즉, Aggregations 와 Suggestions 결과를 Cache 하게 되며, hits 결과는 Cache 하지 않지만 hits.total 은 Cache 합니다.
- Date Range 또는 Histogram 질의 시 now 를 사용하게 되면 Cache 하지 않습니다.
- 이 기능은 Index 레벨로 설정을 합니다.
PUT /my_index
{
"settings": {
"index.requests.cache.enable": true
}
}
- 아래 설정은 Node 레벨로 설정을 하는 것입니다.
indices.requests.cache.size
- 아래 설정은 Cache TTL 설정을 하는 것입니다.
indices.requests.cache.expire
Code Sniff)
// IndicesRequestCache.java
/**
* A setting to enable or disable request caching on an index level. Its dynamic by default
* since we are checking on the cluster state IndexMetaData always.
*/
public static final Setting<Boolean> INDEX_CACHE_REQUEST_ENABLED_SETTING =
Setting.boolSetting("index.requests.cache.enable", true, Property.Dynamic, Property.IndexScope);
public static final Setting<ByteSizeValue> INDICES_CACHE_QUERY_SIZE =
Setting.memorySizeSetting("indices.requests.cache.size", "1%", Property.NodeScope);
public static final Setting<TimeValue> INDICES_CACHE_QUERY_EXPIRE =
Setting.positiveTimeSetting("indices.requests.cache.expire", new TimeValue(0), Property.NodeScope);
// TimeValue.java
public static TimeValue parseTimeValue(String sValue, TimeValue defaultValue, String settingName) {
settingName = Objects.requireNonNull(settingName);
if (sValue == null) {
return defaultValue;
}
final String normalized = sValue.toLowerCase(Locale.ROOT).trim();
if (normalized.endsWith("nanos")) {
return new TimeValue(parse(sValue, normalized, "nanos"), TimeUnit.NANOSECONDS);
} else if (normalized.endsWith("micros")) {
return new TimeValue(parse(sValue, normalized, "micros"), TimeUnit.MICROSECONDS);
} else if (normalized.endsWith("ms")) {
return new TimeValue(parse(sValue, normalized, "ms"), TimeUnit.MILLISECONDS);
} else if (normalized.endsWith("s")) {
return new TimeValue(parse(sValue, normalized, "s"), TimeUnit.SECONDS);
} else if (sValue.endsWith("m")) {
// parsing minutes should be case-sensitive as 'M' means "months", not "minutes"; this is the only special case.
return new TimeValue(parse(sValue, normalized, "m"), TimeUnit.MINUTES);
} else if (normalized.endsWith("h")) {
return new TimeValue(parse(sValue, normalized, "h"), TimeUnit.HOURS);
} else if (normalized.endsWith("d")) {
return new TimeValue(parse(sValue, normalized, "d"), TimeUnit.DAYS);
} else if (normalized.matches("-0*1")) {
return TimeValue.MINUS_ONE;
} else if (normalized.matches("0+")) {
return TimeValue.ZERO;
} else {
// Missing units:
throw new IllegalArgumentException("failed to parse setting [" + settingName + "] with value [" + sValue +
"] as a time value: unit is missing or unrecognized");
}
}
각 설정 값들에 대한 최적화는
- 장비 스펙
- 질의 특성
- 문서 크기
등에 맞춰서 구성을 하셔야 합니다.
잘 모를 경우는 그냥 Elasticsearch 의 default 값을 사용하시면서 최적값을 찾으셔야 합니다.
Monitoring Cache Usage)
공식문서)
https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-stats.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-nodes-stats.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-stats.html
GET /_stats/request_cache?human
GET /_nodes/stats/indices/request_cache?human
함께 알아 두면 좋은것)
https://www.elastic.co/guide/en/elasticsearch/reference/current/fielddata.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/doc-values.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-store.html