Apache Ignite — вычисления в гриде

    Вычисления в гриде или майнинг «красивых» хешей, такую задачу я решил проверить для вычисления в гриде Apache Ignite. Ранее я пробовал и писал Ignite как Sql БД, но для себя я понял что это пока удобная опция в этой вычислительной системе (к SQL на Ignite я еще вернусь), именно так как вычислительная система я себе ее представляю с возможностью быстрой и не дорогой масштабируемостью. Вот это и посмотрим, как можно быстро и недорого нарастить вычисления, или нет, например нарастить вычисления 1 мощного компьютера добавляя к нему несколько слабых.

    Задача такая, для блоков данных-транзакций вычислить хеш, но не простой, а с некоторой сложностью, например содержащий подряд семь символов 'А'. Что бы это было возможно, к блоку данных будем приклеивать постоянно увеличивающейся в цикле число, пока не будет получен хеш заданной сложности. Да, это похоже как делают майнеры добывая крипто валюту. Поскольку у меня несколько транзакций я их буду отправлять в вычислительный грид. Вычислительный грид это ноды Ignite, запущенные экземпляры на разных компьютерах, они сами себя обнаруживают и образуют грид. Распределяться эти вычисления между нодами будут равномерно и автоматически.

    И так мои вычислительные мощности, в домашних условиях это:

    Intel Core I5-7400 3,5 Ггц 8 Гб. ОЗУ
    Intel Core I3-6100 3,7 Ггц 8 Гб. ОЗУ
    Intel Core 2Duo E6550 2,3 Ггц 8 Гб. ОЗУ
    На каждом из них будет запускаться Ignite.

    Вот один из шаблонов которые предлагает Ignite для вычисления в гриде
    //Стартуем клиента
    Ignition.setClientMode(true);
    try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
    
        //Подготовка к вычислениям, создание задач 
        //Проходим через все задания и создаем задачу на выполнение, добавляем в список
        for (final T item: list) {
            calls.add(new IgniteCallable<String>() {
                @Override public String call() throws Exception {
                    //Вот этот код будет выполняться на нодах, на разных компьютерах в сети 
                    return result;
                }
            });
        }
    
        // Запускаем список заданий на ноды грида
        Collection<String> res = ignite.compute().call(calls);
    
        // Получаем результат от каждой ноды 
        for (String hash : res) {
            System.out.println(">>> Check all nodes for output : " + result);
        }
    }
    


    Вот код который будет вычисляться на нодах грида (public String call())
                    calls.add(new IgniteCallable<String>() {
                        @Override public String call() throws Exception {
                            System.out.println();
                            System.out.println(">>> Id  transaction=#" + transaction.getId() + " on this node from ignite job.");
    
                            MessageDigest md = MessageDigest.getInstance("MD5");
                            String transactHash;
                             // ищем красивый хеш
                            do {
                                md.update(transaction.getDifficultyContent().getBytes());
                                byte[] digest = md.digest();
                                transactHash = DatatypeConverter.printHexBinary(digest).toUpperCase();
                                // увеличиваем сложность
                                transaction.setDifficulty(transaction.getDifficulty() + 1);
                            } while (!transactHash.contains("AAAAAAA"));
    
                            return transactHash;
                        }
                    });
    


    Полный код
    public class MyComputeCallable {
        // Данные для транзакции 
        public static final String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr,# " +
                "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.#" +
                "At vero eos et accusam et justo duo dolores et ea rebum.#" +
                "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.";
    
        /**
         * Executes example.
         *
         * @param args Command line arguments, none required.
         * @throws IgniteException If example execution failed.
         */
        public static void main(String[] args) throws IgniteException {
            String[] loremIpsum = LOREM_IPSUM.split("#");
            List<Transaction> transactionList = new ArrayList<>();
            for (int i= 0; i <= 10; i++) {
                transactionList.add(i, new Transaction(i, loremIpsum[i % 4]));
            }
    
            Ignition.setClientMode(true);
    
            try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
                System.out.println();
                System.out.println(">>> Compute callable example started.");
    
                Collection<IgniteCallable<String>> calls = new ArrayList<>();
    
                // Iterate through all words in the sentence and create callable jobs.
                for (final Transaction transaction : transactionList) {
                    calls.add(new IgniteCallable<String>() {
                        @Override public String call() throws Exception {
                            System.out.println();
                            System.out.println(">>> Id  transaction=#" + transaction.getId() + " on this node from ignite job.");
    
                            MessageDigest md = MessageDigest.getInstance("MD5");
                            String transactHash;
                            do {
                                md.update(transaction.getDifficultyContent().getBytes());
                                byte[] digest = md.digest();
                                transactHash = DatatypeConverter.printHexBinary(digest).toUpperCase();
                                // увилмваем сложность
                                transaction.setDifficulty(transaction.getDifficulty() + 1);
                            } while (!transactHash.contains("AAAAAAA"));
    
                            return transactHash;
                        }
                    });
                }
    
                // Execute collection of callables on the ignite.
                long millis = System.currentTimeMillis();
                Collection<String> res = ignite.compute().call(calls);
    
                System.out.println();
                // individual received from remote nodes.
                for (String hash : res) {
                    System.out.println(">>> Check all nodes for output hash: " + hash);
                }
    
                System.out.println(">>> Total msec: " + (System.currentTimeMillis() - millis));
            }
        }
    }
    //----------------------- Transaction   ---------------------------------
    public class Transaction {
        private int difficulty;
        private int id;
        private String content;
    
        public Transaction(int id, String content) {
            this.id = id;
            this.content = content;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public int getDifficulty() {
            return difficulty;
        }
    
        public void setDifficulty(int difficulty) {
            this.difficulty = difficulty;
        }
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
        public String getDifficultyContent() {
            return "" + difficulty + content;
        }
    
    }
    


    Результат вычислений для 11-и транзакций на одной ноде (один компьютер), код выше
    Компьютер
    Результат msec.
    I5
    40 909
    I3
    57 162
    2 Duo
    140 673

    Приятно что мощности со времен 2Duo выросли. А вот так это выглядело на картинках с I5

    Консоль Ignite
    image
    Видно что к серверу подключился клиент (srevers=1, clients=1), на ноду прилетели транзакции для вычислений (всего 11) >>> Id transaction…
    по окончании клиент отключился (srevers=1, clients=0)

    Вывод программы (красивые хеши)
    image
    А вот вычисленные «красивые» хеши

    А теперь начнем наращивать мощность вычисления т.е. запускать на нескольких компьютерах Ignite server. Поскольку пример реализован так, что ожидает выполнение всех задач, то окончанием будет вычислением на последней ноде, и если мы подключаем слабые компьютеры к сильным, результат будет падать (по крайне мере вначале).

    Результат вычислений на нескольких нодах.
    Ноды
    Результат msec.
    I5+I3
    44 389
    I5+I3+2Duo
    68 892

    Видно например что добавив к I5, I3 результат стал ниже чем для одного I5, но лучше чем один I3. Таким образом время вычисления для данной реализации будет мериться по слабой ноде и равно времени за которое нода обработает свою порцию задач. Что бы получить время вычисления в комбинации I5, I3 стала лучше чем на одном I5, нужно понять на каком количестве транзакций I3 покажет время лучшее чем I5 для всех. Экспериментально быстро установил, что I3 порцию из 4-5 транзакций обрабатывает также или лучше как I5 все 11 транзакций, таким образом такие порции возможны когда в гриде будут 3 ноды — I5 + I3 +I3, мои ожидания, что мой грид вычислит эту задачу ~30 сек.(против 40 сек. на одном I5), вот такая масштабируемость.

    Ну а добавляя к слабым компьютерам в гриде мощные, конечно сразу получаем увеличение. Один 2Duo считал 140 сек, а в гриде с другими за 68 сек.

    Так выглядит одна из консолей Ignite для трех нод в гриде

    image

    Показывает 3 сервера, один клиент который рассылает на них задачи, CPU показывает как сумму с трех компьютеров, ну память тоже как сумму. Видно что нода получила 4-ре задачи из 11-и (транзакций), по окончании остались три сервера.

    В целом распределенные задачи решаются здорово, предлагаются различные шаблоны, с разными возможностями. Далее хочу вернуться к SQL в Ignite и поработать с кешам, напишу…

    Топология
    image
    image

    Материалы:

    Ignite Getting Started
    • +16
    • 4,6k
    • 2
    Поделиться публикацией

    Комментарии 2

      0
      В xml конфиге ignite только настройки TcpDiscovery? Или ещё что-то?
        0
        из поставки — apache-ignite-fabric-2.3.0-bin\examples\config\example-default.xml
                    <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
                        <property name="ipFinder">
                            <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
        

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

      Самое читаемое