Для ответа на запросы требуется процессорное время, память, а в неудачных случаях и время стены. Увеличение мощности кластера помогает, но чрезмерное выделение ресурсов может быть очень дорогим. Кэширование - один из первых инструментов, вытаскиваемых из коробки оптимизации. Если старые версии Elastisearch кэшировали все, что можно было кэшировать, то новые версии по умолчанию могут быть довольно избирательными. Итак, какое кэширование поддерживает Elasticsearch и как лучше всего им воспользоваться?
Elasticsearch поддерживает три вида кэшей: кэш запросов узлов, кэш запросов шардов и кэш данных полей.
Кэш запросов узла
Кэш узла - это LRU-кэш, общий для всех шардов на узле. Он кэширует результаты запросов, используемых в контексте фильтра, и в предыдущих версиях Elasticsearch по этой причине назывался кэшем фильтра. Положения в контексте фильтра используются для включения (или исключения) документов из набора результатов, но не участвуют в подсчете баллов. Кроме того, Elasticsearch заметил, что многие фильтры вычисляются довольно быстро, особенно для небольших сегментов, а другие - редко. Чтобы уменьшить отток, в кэш узлов будут включены только те фильтры, которые:использовались несколько раз в последних 256 запросах. Принадлежат сегментам, содержащим более 10 000 документов (или 3% от общего количества документов, в зависимости от того, что больше).
Кэш запросов на уровне шардов
Кэш запросов уровня шарда кэширует результаты запросов независимо для каждого шарда, также используя LRU-вытеснение. По умолчанию кэш запросов также ограничивает пункты: По умолчанию кэшируются только запросы размером 0, такие как агрегации, подсчеты и предложения. Если вы считаете, что запрос должен быть кэширован, добавьте к запросу флаг "request_cache=true".
- Кэширование не будет осуществляться в пунктах DateTime, содержащих "now";
- Кэш запросов на шарде аннулируется при каждом обновлении шарда.
Это может привести к низкой производительности в часто обновляемом индексе.
Кэш данных полей
Когда Elasticsearch вычисляет агрегаты по полю, он загружает все значения поля в память. По этой причине вычисление агрегатов в Elastisearch может быть одной из самых дорогих операций в запросе. Кэш данных полей хранит значения полей при вычислении агрегаций. Хотя Elasticsearch не отслеживает количество попаданий/промахов, рекомендуется установить это значение достаточно большим, чтобы хранить в памяти все значения для поля.
Мониторинг кэширования
Для мониторинга Elasticsearch существует ряд интеграций. Sematext и Datadog - одни из самых распространенных. Но что, если вам нужно просто провести выборочную проверку во время разработки?
Elasticsearch предоставляет несколько способов проверки использования кэша, но мне больше нравится API _cat nodes, потому что он дает все вышеперечисленное за один вызов:
1 | GET _cat/nodes?v&h=id,queryCacheMemory,queryCacheEvictions,requestCacheMemory,requestCacheHitCount,requestCacheMissCount,flushTotal,flushTotalTime |
Последствия
- Отделите агрегации от "обычной" обработки запросов. Это кажется неинтуитивным: зачем вычислять что-то дважды или делать два обходных вызова для чего-то, что вытекает из одних и тех же пунктов? На практике агрегации будут более пригодны для кэширования. Кроме того, это позволит не пересчитывать агрегаты по мере того, как пользователи просматривают данные.
- Отличайте фильтры от пунктов соответствия. Общие фильтры хорошо кэшируются и быстро вычисляются; скоринг более дорог и его трудно кэшировать. Поэтому кэширование более общего фильтра, а затем подсчет более точного подмножества является избыточным, но полезным.
- Используйте многократно используемые фильтры для сужения набора результатов перед подсчетом. Аналогично, используйте поля со сценариями для скоринга, но не фильтры.
- Фильтры выполняются более или менее по порядку. ES немного переписывает запросы, но в целом дешевые фильтры ставятся первыми, а более дорогие - вторыми.
- Если вы должны фильтровать по метке времени, используйте грубую детализацию, чтобы значение запроса менялось нечасто.