Приложение Gridgain, которое медленнее, чем многопоточное приложение на одной машине

StackOverflow https://stackoverflow.com/questions/4481645

  •  11-10-2019
  •  | 
  •  

Вопрос

Я внедрил свое первое приложение Gridgain и не получаю улучшения производительности, которые я ожидал. К сожалению, это медленнее. Мне нужна помощь в улучшении моей реализации, чтобы она была быстрее.

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

Соответствующий кусок кода ниже. Функция MaxAppliedRange вызовов функционирует FOO для каждого значения в диапазоне x и возвращает максимум, и результат становится максимумом из всех максимумов, найденных каждой заданием.

  scalar {
    result = grid !*~
      (for (x <- (1 to threads).map(i => ((i - 1) * iterations / threads, i * iterations / threads)))
        yield () => maxAppliedRange(x, foo), (s: Seq[(Double, Long)]) => s.max)
  }

Мой код может выбрать между многопоточным выполнением на одной машине или использовать несколько узлов Gridgain, используя приведенный выше код. Когда я запускаю версию Gridgain, она начинается так, как будто она будет быстрее, но тогда всегда случаются несколько вещей:

  • Один из узлов (на другой машине) пропускает сердцебиение, заставляя узел на моем основном компьютере отказаться от этого узла и начать выполнение работы во второй раз.
  • Узел, который пропустил сердцебиение, продолжает выполнять ту же работу. Теперь у меня есть два узла, которые делают то же самое.
  • В конце концов, все задания выполняются на моей главной машине, но, поскольку некоторые задания начались позже, все, чтобы закончить.
  • Иногда исключение бросается Gridgain, потому что узел перешел время, и вся задача потерпела неудачу.
  • Я раздражаюсь.

Я попытался настроить его, чтобы иметь много рабочих мест, поэтому, если он потерпел неудачу, то это не было бы такой большой сделки, но когда я это сделаю, я в конечном итоге выполняется много рабочих мест, выполняемых на каждом узле. Это накладывает гораздо большую нагрузку на каждую машину, что делает его более вероятным, чтобы узел пропустил сердцебиение, заставляя все быстрее идти вниз. Если у меня есть одна работа на процессор, то, если одна задача снятся, другой узел должен начать с самого начала. В любом случае я не могу победить.

Я думаю, что лучше всего сработать, если бы я мог сделать две вещи:

  • Увеличьте тайм -аут для сердцебиения
  • Дроснуть каждый узел, чтобы он выполнял только одну работу за раз.

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

Кто -нибудь может сказать мне, как это сделать? Что мне здесь делать?

Это было полезно?

Решение 2

Теперь у меня это работает правильно. В моей ситуации для моего приложения я получаю примерно на 50% ускорение по сравнению с многопоточным приложением на одной машине, но это не самое лучшее, что я могу сделать. Должно быть сделано больше работы.

Чтобы использовать Gridgain, кажется, что файл конфигурации имеет решающее значение для того, чтобы все работало. Здесь установлено поведение узла и должно соответствовать потребностям вашего приложения.

Одна вещь, которая мне была нужна в моем файле конфигурации XML, заключается в следующем:

    <property name="discoverySpi">
        <bean class="org.gridgain.grid.spi.discovery.multicast.GridMulticastDiscoverySpi">
            <property name="maxMissedHeartbeats" value="20"/>
            <property name="leaveAttempts" value="10"/>
        </bean>
    </property>

Это устанавливает максимальное сердцебиение, которое можно пропустить до того, как узел считается отсутствующим. Я установил это на высокую ценность, потому что у меня была проблема с уходом узлов и возвращением через несколько секунд. В качестве альтернативы, вместо использования многоадрески я мог бы исправить IPS машин с помощью работающих узлов, используя другие свойства в файле конфигурации. Я не делал этого, но если вы используете одни и те же машины снова и снова, это, вероятно, будет более надежным.

Другая вещь, которую я сделал, это:

    <property name="collisionSpi">
        <bean class="org.gridgain.grid.spi.collision.jobstealing.GridJobStealingCollisionSpi">
            <property name="activeJobsThreshold" value="2"/>
            <property name="waitJobsThreshold" value="4"/>
            <property name="maximumStealingAttempts" value="10"/>
            <property name="stealingEnabled" value="true"/>
            <property name="messageExpireTime" value="1000"/>
        </bean>
    </property>

    <property name="failoverSpi">
        <bean class="org.gridgain.grid.spi.failover.jobstealing.GridJobStealingFailoverSpi">
            <property name="maximumFailoverAttempts" value="10"/>
        </bean>
    </property>

Для первого значения ActiveJobsThreshold сообщает узлу, сколько заданий он может работать одновременно. Это лучший способ сделать дроссель, чем изменение количества потоков в службе исполнителя. Кроме того, он делает некоторую балансировку нагрузки, и узлы простоя могут «украсть» работу из других узлов, чтобы все было выполнено быстрее.

Есть лучшие способы сделать это также. Gridgain может выполнять размер заданий на основе измеренной производительности каждого узла, по -видимому, что повысит общую производительность, особенно если у вас есть быстрые и медленные компьютеры в сетке.

В будущем я собираюсь изучить файл конфигурации и сравнить его с Javadocs, чтобы узнать все обо всех различных вариантах, чтобы это запустило еще быстрее.

Другие советы

Я понял.

Во -первых, есть файл конфигурации XML, который управляет деталями того, как работают узлы сетки. Файл конфигурации по умолчанию находится в gridgain_home/config/default-spring.xml. Я мог бы либо отредактировать это, либо скопировать его и передать новый файл в ggstart.sh, когда я запускаю узел сетки. Две вещи, которые мне нужно было добавить:

    <property name="networkTimeout" value="25000"/>

который устанавливает тайм -аут для сетевых сообщений на 25 секунд, и

   <property name="executorService">
        <bean class="org.gridgain.grid.thread.GridThreadPoolExecutor">
            <constructor-arg type="int" value="1"/>
            <constructor-arg type="int" value="1"/>
            <constructor-arg type="long">
                <util:constant static-field="java.lang.Long.MAX_VALUE"/>
            </constructor-arg>
            <constructor-arg type="java.util.concurrent.BlockingQueue">
                <bean class="java.util.concurrent.LinkedBlockingQueue"/>
            </constructor-arg>
        </bean>
    </property>

Первые два аргумента конструктора предназначены для запуска 1 потока, и максимальный размер потока 1. Служба исполнителя управляет потоком, который выполняет задание Gridgain. По умолчанию 100, поэтому мое приложение было перегружено, а сердцебиение было рассмотрено.

Другое изменение, которое я должен был внести в свой код, это:

  scalar.apply("/path/to/gridgain home/config/custom-spring.xml") {
    result = grid !*~
      (for (x <- (1 to threads).map(i => ((i - 1) * iterations / threads, i * iterations / threads)))
        yield () => maxAppliedRange(x, kalmanBruteForceObj.performKalmanIteration), (s: Seq[(Double, Long)]) => s.max)
  }

Потому что без оператора .Apply он запускает узел сетки со всеми параметрами по умолчанию, а не с файлом конфигурации с приведенными выше редакторами, что я хочу.

Теперь это работает точно так, как мне нужно. Я могу разделить задачу на мелкие кусочки, и даже мой самый слабый и самый медленный компьютер может внести вклад в это усилие.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top