Оптимизация кеша для широкого использования безболезненного скрипта ES 6.4.2
tl;dr: Как мне лучше использовать кеш файловой системы для миллионов скриптовых запросов? Каждый вывод Logstash в ES запускает безболезненный скрипт, который вызывает запрос. Если запрос не кэшируется файловой системой (из-за отсутствия доступной оперативной памяти), считывание дискового ввода-вывода увеличивается. Как мне лучше оптимизировать?
- Версия Elasticsearch: 6.4.2
- JVM: openjdk 1.8.0_181
- Доступны два узла, общая системная память 84 ГБ
- Ввод 250 ГБ JSON три раза в месяц
- Диски представляют собой комбинацию SATA SSD (в рейде 0) и NVMe
Я обрабатываю 250 ГБ журналов JSON через Logstash и выводю их Elasticsearch. Журналы ввода содержат ВЕСЬ множество дубликатов, поэтому безболезненный сценарий используется для проверки метки времени в журнале ввода по сравнению с тем, что уже есть в Elasticsearch. Если это новая отметка времени, то она добавляет отметку времени в массив. В противном случае ничего не происходит.
Проблема в том, что чем дальше идет процесс обработки, тем медленнее идет индексация. И это НЕ медленное и постепенное снижение (см. Изображение ниже). В течение часа скорость возрастает с 18000 ep/s до 2000 ep/s.
Скорость индексирования огромна, пока не израсходован весь кэш файловой системы. Я на самом деле сильно сократил JVM, чтобы дать кешу как можно больше памяти. Независимо от этого, в конечном итоге скорость индексации сильно падает, а затем IO диска заявляет, что оно очень высокое; посмотрите, как sdb (nvme SSD) тратит все свое время на чтение, а не на запись.
# iostat -m -x 5
avg-cpu: %user %nice %system %iowait %steal %idle
1.16 0.00 7.31 47.55 0.00 43.98
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sdb 1.20 64.87 12333.93 20.96 1275.55 0.43 211.51 144.78 11.73 11.71 18.40 0.08 100.10
Это пример входных данных:
{"timestamp":"1534023333", "hash":"1", "value":"something1"}
{"timestamp":"1534022222", "hash":"1", "value":"something1"}
{"timestamp":"1534011111", "hash":"1", "value":"something1"}
{"timestamp":"1534023333", "hash":"2", "value":"something2"}
{"timestamp":"1534022222", "hash":"2", "value":"something2"}
{"timestamp":"1534011111", "hash":"2", "value":"something2"}
Это пример вывода Logstash и безболезненного сценария:
output {
elasticsearch {
hosts => ["http://127.0.0.1:9200"]
index => "testing"
document_id => "%{[hash]}"
doc_as_upsert => true
script => 'if(ctx._source.timestamp.contains(params.event.get("timestamp")[0])) return true; else (ctx._source.timestamp.add(params.event.get("timestamp")[0]))'
action => "update"
retry_on_conflict=>5
}
}
Вопросы:
- Как мне лучше оптимизировать мой вариант использования? Каждый вывод Logstash в ES запускает безболезненный скрипт, который вызывает запрос. Если запрос не кэшируется файловой системой, то чтение диска IO увеличивается. Я понимаю, что мог бы просто добавить больше памяти, но в итоге мой набор данных будет больше 250 ГБ, и я не хочу использовать 200+ ГБ памяти каждый раз, когда я хочу выполнить большое количество индексации.
- Есть ли другой способ сделать то, что я хочу сделать? Могу ли я проиндексировать все данные, а затем Elasticsearch объединить документы, имеющие одинаковый идентификатор документа, но разные временные метки. Например, взять два документа с одинаковым идентификатором, которые имеют две разные версии, но разные значения меток времени (в массиве) и объединить их вместе?