Процесс Elasticsearch очень требователен к памяти. Elasticsearch использует JVM (Java Virtual Machine), и около 50% памяти, доступной на узле, должно быть выделено под JVM. Машина JVM использует память, поскольку процесс Lucene должен знать, где искать значения индексов на диске. Остальные 50% требуются для кэша файловой системы, который хранит в памяти данные, к которым регулярно обращаются.
Требования к памяти Elasticsearch
jvm.mem
Наиболее важной секцией памяти является куча JVM.
1 | GET _nodes/stats/jvm |
Вывод может выглядеть следующим образом:
1 2 3 4 5 6 7 8 9 10 11 | "jvm" : { "timestamp" : 1603351829573, "uptime_in_millis" : 150932107, "mem" : { "heap_used_in_bytes" : 258714272, "heap_used_percent" : 24, "heap_committed_in_bytes" : 1073741824, "heap_max_in_bytes" : 1073741824, "non_heap_used_in_bytes" : 192365488, "non_heap_committed_in_bytes" : 209186816, |
Обратите внимание, что значение heap_used_in_bytes в здоровой JVM будет иметь пилообразный характер из-за процесса сборки мусора: оно постоянно увеличивается примерно до 70%, а затем резко уменьшается до 30%, когда происходит сборка мусора.
Значение heap_max JVM зависит от значения, заданного в файле jvm.options, и его следует установить на уровне 50% от объема оперативной памяти, доступной для вашего контейнера или сервера.
Объяснение различных типов статистики памяти
Рассматривая статистику памяти, мы должны учитывать, что многие приложения Elasticsearch выполняются внутри контейнеров на гораздо больших машинах. Это типично, если вы используете хостинговый сервис, например AWS Elasticsearch или облако Elastic, или если вы запускаете Elasticsearch на Docker или Kubernetes. В таких случаях важно внимательно относиться к интерпретации доступной нам статистики памяти.
В API-интерфейсах мониторинга Elasticsearch доступны различные статистические данные о памяти, которые описаны ниже:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | GET _nodes/stats/os "os" : { "timestamp" : 1603350306857, "cpu" : { "percent" : 13, "load_average" : { "1m" : 3.37, "5m" : 3.18, "15m" : 2.8 } }, "mem" : { "total_in_bytes" : 16703369216, "free_in_bytes" : 361205760, "used_in_bytes" : 16342163456, "free_percent" : 2, "used_percent" : 98 }, "swap" : { "total_in_bytes" : 1023406080, "free_in_bytes" : 1302528, "used_in_bytes" : 1022103552 }, "cgroup" : { "cpuacct" : { "control_group" : "/", "usage_nanos" : 2669636420088 }, "cpu" : { "control_group" : "/", "cfs_period_micros" : 100000, "cfs_quota_micros" : -1, "stat" : { "number_of_elapsed_periods" : 0, "number_of_times_throttled" : 0, "time_throttled_nanos" : 0 } }, "memory" : { "control_group" : "/", "limit_in_bytes" : "9223372036854771712", "usage_in_bytes" : "4525641728" } } } |
Приведенная статистика относится к узлу разработки, работающему на docker. Проинтерпретируем полученные здесь участки:
os.mem
Первая секция "mem" относится к хост-серверу, на котором запущена машина. В данном случае мы работаем с docker, поэтому 16 ГБ относится к памяти хост-машины, на которой запущен контейнер. Обратите внимание, что использование машиной почти 100% памяти является вполне нормальным явлением, и это не свидетельствует о наличии проблемы.
os.swap
Секция swap снова относится к хост-машине. В данном случае мы видим, что хост-машина разрешает свопинг. Это вполне нормально, если мы запускаем контейнер на хосте с включенной свопингом. Мы можем дважды проверить, что внутри контейнера docker свопинг не разрешен, выполнив команду:
1 | GET _nodes?filter_path=**.mlockall |
os.cgroup
Наконец, мы видим раздел cgroup, который относится к самому контейнеру. В данном случае контейнер использует 4 Гбайт памяти.
process.mem
Мы также имеем доступ к статистике виртуальной памяти:
1 2 3 4 5 6 7 8 9 10 11 12 | GET _nodes/stats/process "process" : { "timestamp" : 1603352751181, "open_file_descriptors" : 436, "max_file_descriptors" : 1048576, "cpu" : { "percent" : 0, "total_in_millis" : 1964850 }, "mem" : { "total_virtual_in_bytes" : 5035376640 } |
Заметим, что "total_virtual_in_bytes" включает всю память, доступную процессу, в том числе и виртуальную память, доступную через mmap.