Помещаем 2 миллиона объектов в кластер Hazelcast из 5 узлов — какую оптимизацию делать

У нас есть 2 миллиона объектов, поступающих из REST API кусками по 500 объектов в каждом вызове API (всего около 750 МБ данных).

  • Когда мы помещаем эти объекты в кеш Hazelcast, как показано ниже, это занимает около 10 минут — ЦП составляет 5-6% — это имеет смысл, поскольку есть 2 миллиона блокирующих вызовов n/w.

    vertx.executeBlocking {
        for(2 million times) {
            hazelcast.put(mapName, key, value)
        }
    }
    
  • Когда мы не используем «блокировку выполнения» vertx, а делаем следующее, весь процесс завершается за 10-15 секунд, но ЦП достигает 80%. Я использую Hazelcast mancenter, поэтому я мог видеть, что все 2 миллиона объектов отражаются в кеше в течение 10-15 секунд.

    for(2 million times) {
        hazelcast.putAsync(mapName, key, value)
    }
    
  • Когда мы использовали #putAll следующим образом, ЦП достигает 60%, что лучше, чем второй подход. Этот подход также заканчивается примерно за 10 секунд.

    for(2 million objects in chunks of 500) {
        hazelcast.putAll(mapName, collection-of-500-objects)
    }
    

Любая оптимизация, которую вы, ребята, рекомендуете? Интересно, почему Hazelcast так сильно нагружает процессор?

К вашему сведению: считайте vertx.executeBlocking асинхронным выполнением фрагмента кода. Мы используем процессор Intel Xeon 8 Core с 12 ГБ оперативной памяти.


person manish    schedule 14.08.2017    source источник
comment
Извините за плохое форматирование, я не мог понять, как отформатировать код.   -  person manish    schedule 14.08.2017
comment
vertx.executeBlocking технически не работает асинхронно, а позволяет безопасно выполнять синхронный код в vert.x, возвращая результаты асинхронному коду (работающему в вертикулах) по завершении.   -  person Arnold Schrijver    schedule 14.08.2017
comment
Код форматирования PS в маркерах требует 4 дополнительных пробела. я отредактировал это   -  person Arnold Schrijver    schedule 14.08.2017
comment
@Arnold Schrijver - я хотел упростить это. Vertx выполняет лямбду, используя рабочий поток из пула, и вы можете прикрепить обработчики результатов, которые будут вызываться, когда рабочий поток завершит выполнение. Я не пытаюсь обосновать свое утверждение, но в то же время хочу убедиться, что сформулировал его правильно. Поэтому я все еще думаю, что код выполняется асинхронно с вершинами. Не стесняйтесь поправлять меня, если я все еще ошибаюсь. Я ценю ваше время, чтобы отформатировать мой код!!!   -  person manish    schedule 14.08.2017
comment
Нет, ты не ошибся, я просто уточнил. Оба метода могут быть действительными в зависимости от ваших потребностей. Второй подход по-прежнему блокирует цикл событий на 10-15 секунд, не используя мощность vert.x. Может быть, вы могли бы обернуть это в executeBlocking или worker verticle, или сделать так, чтобы обычные verticles выполняли отдельные размещения. Чувствуется немного странно. Я не знаю, много ли вы выиграете, так как вы выполняете только одну операцию hazelcast. Но блокировка цикла событий дольше, чем нужно, — самый большой грех в vert.x :)   -  person Arnold Schrijver    schedule 15.08.2017
comment
@ArnoldSchrijver - я согласен с тем, что цикл событий будет заблокирован на 10-15 секунд при втором подходе, но я делаю это только для целей тестирования. Меня больше всего интересует, почему процессор загружается на 80%, когда я использую hazelcast.putAsync.   -  person manish    schedule 16.08.2017


Ответы (2)


Взгляните на IMap.putAll. Это позволяет помещать данные в куски. Вы сказали, что 2 миллиона, разделенные на 500 объектов, порция = 4 000 порций.

/**
 * {@inheritDoc}
 * <p>
 *      No atomicity guarantees are given. It could be that in case of failure
 *      some of the key/value-pairs get written, while others are not.
 * </p>
 * <p>
 *      <p><b>Warning:</b></p>
 *      If you have previously set a TTL for the key, the TTL remains unchanged and the entry will
 *      expire when the initial TTL has elapsed.
 * </p>
 */
void putAll(Map<? extends K, ? extends V> m);
person tom.bujok    schedule 14.08.2017
comment
Для нас важна атомарность. Этот метод, по-видимому, не обеспечивает никакой гарантии атомарности. Мы не знали бы, если бы некоторые из наших данных были потеряны. Кроме того, мне интересно, повлияет ли это на использование ЦП так же, как #putAsync (вызвало скачок ЦП на 80%). - person manish; 14.08.2017
comment
Я провел тест с hazelcast.putAll(коллекция), и он показал некоторое улучшение ЦП (60%) по сравнению с размещением объектов один за другим в кеше с использованием hazelcast.put(ключ, значение), где ЦП составляет 80%. Все, что ниже 40%, было бы приемлемо для меня. Кстати, мы используем 8-ядерный процессор Intel Xeon. - person manish; 17.08.2017

Любая оптимизация, которую вы, ребята, рекомендуете?

Вы можете попробовать использовать IMap. setAsync вместо IMap.putAsync, согласно документации это должно быть более эффективно:

Аналогичен операции put, за исключением того, что set не возвращает старое значение, что более эффективно.

person Mikhail Baksheev    schedule 17.08.2017
comment
Используемая нами версия Hazelcast (3.6.2) не имеет этого метода. Мы обновим версию и посмотрим, как она работает. - person manish; 18.08.2017