Тест Hazelcast против Ignite

Я использую сетки данных как свою основную "базу данных". Я заметил резкую разницу между производительностью запросов Hazelcast и Ignite. Я оптимизировал использование своей сетки данных с помощью собственной пользовательской сериализации и индексов, но разница по-прежнему заметна.

Поскольку никто не спросил об этом здесь, я собираюсь ответить на свой вопрос на все будущие ссылки. Это не абстрактное (учебное) упражнение, а реальный тест, который моделирует использование моей сетки данных в больших системах SaaS - в первую очередь для отображения отсортированных и фильтрованных разбитых на страницы списков. Я прежде всего хотел знать, сколько накладных расходов мой универсальный уровень доступа к сетям данных JDBC-ish добавляется по сравнению с необработанными без рамки использования Hazelcast и Ignite. Но поскольку я сравниваю яблоки с яблоками, здесь идет эталон.

Ответ 1

Я просмотрел предоставленный код на GitHub и получил много комментариев:

Индексирование и объединение

  • Вероятно, самый важный момент заключается в том, что индексирование Apache Ignite намного сложнее, чем Hazelcast. В отличие от Hazelcast, Ignite поддерживает ANSI 99 SQL, поэтому вы можете писать свои запросы по своему усмотрению.
  • Самое главное, в отличие от Hazelcast, Ignite поддерживает групповые индексы и SQL JOINs в разных кешах или типах данных. Представьте, что у вас есть персональные и организационные таблицы, и вам нужно выбрать всех лиц, работающих в той же Организации. Это невозможно сделать в 1 шаг в Hazelcast (исправьте меня, если я ошибаюсь), но в Ignite это простой запрос SQL JOIN.

Учитывая вышеизложенное, индексы Ignite займут немного больше времени, особенно в вашем тесте, где у вас есть 7 из них.

Исправления в классе TestEntity

В вашем коде объект, который вы храните в кеше, TestEntity, пересчитывает значение idSort, createdAtSort и modifiedAtSort каждый раз, когда вызывается получатель. Ignite вызывает эти геттеры несколько раз, пока объект хранится в дереве индексов. Простое исправление класса TestEntity обеспечивает улучшение производительности 4 раза: https://gist.github.com/dsetrakyan/6bfe089d53f888448503

Измерение кучи неточно

То, как вы измеряете кучу, неверно. Вы должны хотя бы позвонить System.gc(), прежде чем принимать измерение кучи, и даже это будет неточно. Например, в приведенных ниже результатах я получаю отрицательный размер кучи, используя ваш метод.

Разминка

Каждый тест требует разминки. Например, когда я применяю исправление TestEntity, как было предложено выше, и количество пользователей и запросов кэша 2 раза, я получаю лучшие результаты.

Сравнение MySQL

Я не думаю, что сравнение простого теста Data Grid с MySQL справедливо, ни для Ignite, ни для Hazelcast. Базы данных имеют собственное кэширование и при работе с такими небольшими размерами памяти обычно вы проверяете кеш-память в кэш-памяти базы данных и кэширование данных в сетке данных.

Преимущество производительности обычно возникает при выполнении распределенного теста по секционированному кешу. Таким образом, Data Grid будет выполнять запрос в каждом кластере node параллельно, и результаты должны возвращаться намного быстрее.

Результаты

Вот результаты, которые я получил для Apache Ignite. Они выглядят намного лучше после того, как я сделал вышеупомянутые исправления.

Обратите внимание, что во второй раз, когда мы выполняем запросы кэша и кеш-запросы, мы получаем лучшие результаты, потому что JVM HotSpot разогревается.

Следует отметить, что Ignite не кэширует результаты запроса. Каждый раз, когда вы запускаете запрос, вы выполняете его с нуля.

[00:45:15] Ignite node started OK (id=0960e091, grid=Benchmark)
[00:45:15] Topology snapshot [ver=1, servers=1, clients=0, CPUs=4, heap=8.0GB]
Starting - used heap: 225847216 bytes
Inserting 100000 records: ....................................................................................................
Inserted all records - used heap: 1001824120 bytes
Cache: 100000 entries, heap size: 775976904 bytes, inserts took 14819 ms
------------------------------------
Starting - used heap: 1139467848 bytes
Inserting 100000 records: ....................................................................................................
Inserted all records - used heap: 978473664 bytes
Cache: 100000 entries, heap size: **-160994184** bytes, inserts took 11082 ms
------------------------------------
Query 1 count: 100, time: 110 ms, heap size: 1037116472 bytes
Query 2 count: 100, time: 285 ms, heap size: 1037116472 bytes
Query 3 count: 100, time: 19 ms, heap size: 1037116472 bytes
Query 4 count: 100, time: 123 ms, heap size: 1037116472 bytes
------------------------------------
Query 1 count: 100, time: 10 ms, heap size: 1037116472 bytes
Query 2 count: 100, time: 116 ms, heap size: 1056692952 bytes
Query 3 count: 100, time: 6 ms, heap size: 1056692952 bytes
Query 4 count: 100, time: 119 ms, heap size: 1056692952 bytes
------------------------------------
[00:45:52] Ignite node stopped OK [uptime=00:00:36:515]

Я создам другое репо GitHub с исправленным кодом и опубликую его здесь, когда я буду бодрствовать (кофе больше не помогает).

Ответ 2

Вот исходный код эталона: https://github.com/a-rog/px100data/tree/master/examples/HazelcastVsIgnite

Это часть структуры JDBC-ish NoSQL, о которой я упоминал ранее: Данные Px100

Построение и запуск:

cd <project-dir>
mvn clean package
cd target
java -cp "grid-benchmark.jar:lib/*" -Xms512m -Xmx3000m -Xss4m com.px100systems.platform.benchmark.HazelcastTest 100000
java -cp "grid-benchmark.jar:lib/*" -Xms512m -Xmx3000m -Xss4m com.px100systems.platform.benchmark.IgniteTest 100000

Как вы можете видеть, я установил максимальные пределы памяти, чтобы избежать сбора мусора. Вы также можете запустить мой собственный тест фреймворка (см. Px100DataTest.java) и сравнить его с двумя выше, но пусть сосредоточиться на чистой производительности. Ни один из тестов не использует Spring или что-либо еще, кроме Hazelcast 3.5.1 и Ignite 1.3.3 - последнего на данный момент.

Контрольный номер транзакции вставляет указанное количество экземпляров. Записи размером 1 КБ (100000 из них - вы можете увеличить его, но остерегайтесь памяти) партиями (транзакциями) 1000. Затем он выполняет два запроса с восходящей и нисходящей сортировкой: четыре всего. Все поля запроса и ORDER BY индексируются.

Я не буду публиковать весь класс (загрузите его из GitHub). Запрос Hazelcast выглядит так:

PagingPredicate predicate = new PagingPredicate(
        new Predicates.AndPredicate(new Predicates.LikePredicate("textField", "%Jane%"),
            new Predicates.GreaterLessPredicate("id", first.getId(), false, false)),
        (o1, o2) -> ((TestEntity)o1.getValue()).getId().compareTo(((TestEntity)o2.getValue()).getId()),
        100);

Соответствующий запрос Ignite:

SqlQuery<Object, TestEntity> query = new SqlQuery<>(TestEntity.class,
        "FROM TestEntity WHERE textField LIKE '%Jane%' AND id > '" + first.getId() + "' ORDER BY id LIMIT 100");
    query.setPageSize(100);

Вот результаты, выполненные на моем 8-ядерном MBP в 2012 году с 8 ГБ памяти:

Hazelcast

Starting - used heap: 49791048 bytes
Inserting 100000 records: ....................................................................................................
Inserted all records - used heap: 580885264 bytes
Map: 100000 entries, used heap: 531094216 bytes, inserts took 5458 ms
Query 1 count: 100, time: 344 ms, heap size: 298844824 bytes
Query 2 count: 100, time: 115 ms, heap size: 454902648 bytes
Query 3 count: 100, time: 165 ms, heap size: 657153784 bytes
Query 4 count: 100, time: 106 ms, heap size: 811155544 bytes

Ignite

Starting - used heap: 100261632 bytes
Inserting 100000 records: ....................................................................................................
Inserted all records - used heap: 1241999968 bytes
Cache: 100000 entries, heap size: 1141738336 bytes, inserts took 14387 ms
Query 1 count: 100, time: 222 ms, heap size: 917907456 bytes
Query 2 count: 100, time: 128 ms, heap size: 926325264 bytes
Query 3 count: 100, time: 7 ms, heap size: 926325264 bytes
Query 4 count: 100, time: 103 ms, heap size: 934743064 bytes 

Очевидным отличием является производительность вставки - заметная в реальной жизни. Однако очень редко одна вставка 1000 записей. Обычно это одна вставка или обновление (сохранение введенных пользовательских данных и т.д.), Поэтому меня это не беспокоит. Однако производительность запросов. Большинство бизнес-приложений, ориентированных на данные, отличаются прочностью.

Обратите внимание на потребление памяти. Ignite намного более голоден, чем Hazelcast. Это может объяснить лучшую производительность запросов. Ну, если я решил использовать сетку в памяти, я должен беспокоиться о памяти?

Вы можете четко сказать, когда сетки данных попадают в индексы, а когда они этого не делают, как они кэшируют скомпилированные запросы (7 мс один) и т.д. Я не хочу спекулировать и позволяю вам играть с ним, как разработчики Hazelcast и Ignite предоставляют некоторую информацию.

Насколько общая производительность, она сопоставима, если не ниже MySQL. Технология IMO в памяти должна улучшиться. Я уверен, что обе компании будут делать заметки.

Результаты, приведенные выше, довольно близки. Однако при использовании в Px100 Data и более высоком уровне Px100 (который сильно зависит от индексированных полей сортировки для разбивки на страницы) Ignite выдвигается вперед и лучше подходит для моей структуры. В первую очередь я забочусь о производительности запросов.