Cкорость индексации


(Alexey) #1

Добрый день.
Недавно обновил версию ES (c 1.4 до 2.0) и имею ситуацию когда значительно увеличилось время REST запроса при добавлении документа. Добавление идет через

es.update(index=index_name, doc_type='product', id=a.pid, body={'doc': a.to_product(), 'doc_as_upsert': True}, fields=['f1', 'f2'], retry_on_conflict=3, refresh=False)

В добавлении участвует 20 воркеров (celery, elasticsearch-py) , и я получаю что то подобное, вплоть до 3-4 секунд на одну операцию:

POST http://localhost:9200/index_name/doc_type/string_id/_update?retry_on_conflict=3&refresh=false [status:200 request:1.905s]

На предыдущей версии ES скорость обработки сообщений брокера доходила до полутора тысяч в секунду, сейчас же имею: ~6/сек. , т.е. ранее скорость выполнения аналогичного запроса была на уровне:

[status:200 request:0.009s]

С чего начать профилирование, где может быть зарыта проблема? При переходе на ES 2.0 индекс не пересоздавался, имеет немногим более 5М документов и 4Gb размера. Максимум что я сделал это внес следующие настройки в индекс:

{
  "index": {
    "refresh_interval": "30s",
    "store.throttle.type": "none",
    "translog.flush_threshold_size": "4g",
    "translog.flush_threshold_ops": 500000
  },
  "indices": {
    "store.throttle.type": "none"
  }
}

... и прочитал статью о том что ES в версии 2.0 сам определит как ему работать, все что нужно это использовать настройки по умолчанию :slight_smile:

P.S. Пока искал ответы на этот вопрос, вероятно нашел решение проблемы которая имела место: правильно ли я понимаю, что при

        "brand": {
            "properties": {
                "alias": {
                    "type": "string",
                    "index": "not_analyzed"
                },
                "active": {
                    "type": "boolean"
                },
                "title": {
                    "type": "completion",
                    "payloads": true,
                    "context": {
                        "type": {
                            "type": "category",
                            "path": "_type"
                        },
                        "status": {
                            "type": "category",
                            "path": "active"
                        }
                    }
                }
            }
        } 

я должен был использовать для suggest запроса в контексте по полю status не true или false, а 1 или 0

Заранее спасибо.


(Igor Motov) #2

Я бы начал с временной установкой index.translog.durability в async. В 2.0 elasticsearch выполняет fsync транслога после каждой операции (до этого fsync выполнялся каждые 5 секунд). Если пользоваться bulk запросами - это обычно не вызывает значительных проблем. Но если выполняется большое количество индивидуальных запросов, то может сильно упасть производительность. Если это не поможет - будем смотреть.


(Alexey) #3

Bingo! И солнце снова в небе!

Спасибо за решение вопроса и за то что ваша команда создает такой замечательный инструмент.


(Alexey) #4

А решение временное, потому что идеологически лучше все же перейти на bulk'и?

Изначально просто использую метод одиночных запросов. Не помню почему так, наверное не нашел как забирать из брокера сразу несколько сообщений для воркера в используемых инструментах (celery). Есть смысл вернуться к поиску?


(Igor Motov) #5

Да никакой идеологии тут нет - все очень прагматично :slight_smile: Я рассматривал переход на асинхронный fsync как средство диагностики, а не решение проблемы. То есть я просто хотел убедиться, что проблема именно в этом, прежде чем порекомендовать переходить на bulk. Запрос bulk оптимизирован для выполнения большого количества запросов на всех уровнях, начиная с сети и вплоть до синхронизации с диском. То есть кроме диска, вы улучшите производительность как на уровне CPU так и сети.


(Alexey) #6

Игорь, что скажете по поводу такого подхода: сейчас у меня все документы собраны в одном индексе, если я их разнесу по определенному признаку, например ритейлеру, в разные индексы (для чего? ну например исключать из поиска не через query/filter, для подмены индексов (разные версии), для разграничения доступа разных проектов к документам, для уменьшения общего числа документов в каждом из индексов), т.о. у меня получится на данный момент пусть X0 индексов, затем их число возрастет до X00 и я буду передавать эту длинную строку ','.join() в index_name каждого запроса.
Криво?

Сейчас сталкиваюсь с тем что у меня увеличивается время обработки _search по мере увеличения товаров в индексе. Например корневая категория, около 3М товаров, запрос без фильтров, с двумя function_score, вычислимым полем script_fields.script_file, двумя сортировками, 5 агрегациями по параметрам приближается к х (не могу пока посмотреть на prod, там нет es.trace, по newrelic avg 662ms). Изменять подход или попробовать создать кластер?


(Igor Motov) #7

Сложно что-то конкретно рекомендовать, не зная деталей. Разделение по определенному признаку - это популярный подход, когда поиск или крупномасштабные изменения происходят по этому признаку. Разделять можно либо по шардам, либо по индексам, либо и по шардам и индексам одновременно с использование алиасов. В Elasticsearch: The Definitive Guide есть подробное описание данного подхода, так что я его здесь повторять не буду.

Что касается оптимизации запросов - то надо смотреть, что работает медленно. Самый простой способ - это создать нагрузку на тестовый кластер, так чтобы в любой момент несколько реальных запросов работало параллельно и запустить hot_threads несколько раз подряд. По результатам hot_threads часто можно понять, какая часть запроса вызывает наибольшую нагрузку.


(system) #8