Приложение GridGain, которое медленнее многопоточного приложения на одной машине - PullRequest
3 голосов
/ 19 декабря 2010

Я реализовал свое первое приложение 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 ]

2 голосов
/ 19 декабря 2010

Теперь у меня все работает правильно. В моей ситуации с моим приложением я получаю ускорение на 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>

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

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

    <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, чтобы узнать обо всех различных параметрах, чтобы заставить его работать еще быстрее.

2 голосов
/ 19 декабря 2010

Я понял это.

Во-первых, есть файл конфигурации 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. Служба executor контролирует пул потоков, который выполняет задания сетки.По умолчанию установлено значение 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 запускает узел сетки со всеми параметрами по умолчанию, а не файл конфигурации с вышеуказанными правками, что мне и нужно.

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

...