Как обрабатывать терабайты данных в 1000 потоков на PHP — Hadoop/MapReduce

    Всем привет!

    Уже слышали про Bigdata? Ну да, веб растет, данных становится больше и их нужно держать под контролем и периодически анализировать. Базы данных — лопаются под нагрузкой, реляционная теория не совсем справляется с задачей, нужно решение. Маркетинг активно давит сверху, а железо острыми углами — снизу и попахивает суицидом.

    В этом посте постараюсь дать конкретные работающие рецепты и куски кода с краткими теоретическими выводами, как же обрабатывать >=терабайты в >=1000 потоков на PHP. Чтобы можно было взять и решить задачу, не теряя времени и не забивая голову теорией.

    Однако, если вдруг стало подташнивать и закружилась голова, можно дальше не читать — а полюбоваться на прекрасных птичек и забыть о вышенаписанном. Но будьте на чеку, Bigdata может завтра взять и постучаться в дверь ;-)



    Как обычно делается



    Как обычно бывает в вебе. Складывают данные в БД, пока не лопнет. Если лопается, начинаются разговоры про MySQL sharding, partitioning, вспоминают про мульти-мастер кластер в оперативной памяти.

    Если не помогает, начинаются поиски и внедрения NoSQL решения типа redis или облачного сервиса типа DynamoDB. Неплохо себя зарекомендовал в качестве эффективного поискового движка по объемным данным Sphinx.

    Подсознательно идет расчет — сохраним в БД и потом проанализируем информацию. И это нередко работает. Но не всегда… и это «не всегда» становится чаще.

    Данных еще больше, требуется он-лайн аналитика



    Не всегда можно ответить бизнесу — подождем сутки, проанализируем логи/данные и дадим циферки. Бизнесу часто важно иметь циферки в онлайне, управлять ситуацией по приборам с живыми стрелочками.


    Страшно представить управление самолетом путем анализа записанной в черные ящики информации один раз в сутки в гостинице для пилотов :-)



    Когда поток данных становится еще интенсивнее или бизнес-логика требует наличия текущей информации по еще не обработанным данным… Тогда нам помогают инструменты «потокового анализа» типа:
    1) pinba
    2) Amazon Kinesis
    3) Потоковые парсеры на базе nginx/ragel

    Полезно хотя бы один раз каждый из этих бесценных инструментов понять с листочком и карандашом, еще полезнее — «переспать» с мануалом и прототипом минимум ночь.


    Особо хочется выделить здесь pinba за простоту настройки и легкость эксплуатации и минимум создаваемой нагрузки. Организовать сбор статистики по производительности веб-приложения в браузере его клиентов на основании js Navigation Timing API — делается в 2 файла на PHP на 30 строк.

    Когда же нет возможности анализировать данные онлайн — начинаются поиски решения параллельного анализа накопленных данных и связанных с ним алгоритмов.

    Параллельная обработка массивов данных



    Есть список объектов, допустим это файлы в облаке s3, которых у вас — десятки миллионов. Как бы мы не доверяли облаку, нужно эти файлы периодически выгружать в другое облако/серверы. Каждый файл шифруется, сжимается, происходят другие операции и копируется.

    Аналогичных задач в природе немало:
    • обработка изображений
    • обработка XML-документов через XSLT-фильтр
    • обработка логов
    • сортировки


    Эти задачи подпадают под общий алгоритм «разделяй и властвуй»:
    — распределяем задачки на части
    — каждую часть обрабатываем отдельно и параллельно с другими частями
    — объединяем результаты через агрегацию


    Для PHP можно попытаться решить эту задачу используя очередь типа RabbitMQ и/или Gearman — но придется очень много повозиться для решения исключительных ситуаций, шардинга общей файловой системы, кластеризации на 20 серверов и т.п.

    Поэтому если ваша задача может решиться в 30 потоков PHP на одном сервере — перечисленных инструментов, как правило, достаточно. Однако если вам «не повезло» и нужно за час обработать несколько терабайт и железа дают сколько унесешь — выход есть :-)

    Да, да, конечно это Hadoop, реализующий коррелирующую с фото девушек выше парадигму MapReduce ;-)

    Кому лень читать дальше и хочется узнать рецепт, вот пример исходной задачи и ее решения на Hadoop:

    Нужно сжать, зашифровать и перенести 10 млн. файлов из бакета1 s3 в бакет2 s3.
    Если делать средствами PHP на сервере, то можно форкануть максимум ну 20-30 потоков PHP, которые будут каждый выполняться в своем процессе. И это займет несколько недель. А объем данных растет и нужно системное решение.
    Если то же самое делать средствами Hadoop, то задачу можно выполнить за час, но на большом количестве железок. Если выбрать разумное число железок с 15 потоками на каждой — то можно уложиться в 2 дня.
    Т.е. если через полгода число файлов для обработки вырастет с 10 млн. до 50 млн., нужно будет поменять лишь одну циферку в конфиге запуска кластера Hadoop, увеличив число железок лишь.
    Разве не красиво и системно? :-)


    Hadoop



    Вообще это довольно большой продукт и недельки на 24/7 чтения мануалов наверно не хватит — но этого и не требуется. Мы научимся использовать эту технологию эффективно и быстро, экономя ваше и наше время.

    Установка


    Помимо установки java-софта потребуется еще настроить кластерную файловую систему. Зачем — а как будут ноды кластера обмениваться общими файлами? Но мы поступим хитрее — запустим кластер Hadoop в Амазоне. Там все уже настроено и установлено.

    Подготовка map и reduce скриптов


    Вот тут самое интересное в посте. Hadoop позволяет задействовать скрипты на любом языке — и провести сортировку файла на bash или обработку на PHP/Python/Perl.

    Скриптики читают из стандартного ввода и пишут в стандартный вывод. Ну что может быть проще?

    Скриптиков должно быть 2: mapper, reducer.

    Если нужно просто распараллелить задачу на N серверов — достаточно написать один mapper.

    Пример mapper


    #!/usr/bin/php
    <?php
    error_reporting(-1);
    set_time_limit(0);
    ini_set('memory_limit', '2048M');
    gc_enable();
    
    require '/usr/share/php/aws.phar';
    
    $fp=fopen("php://stdin","r");
    
    while (true) {
    
        $line=stream_get_line($fp,65535,"\n");
        // тут работаем с файлами: шифруем, сжимаем, выгружаем, загружаем
        ...
    }
    
    echo "s3 copied direct\t".$copy_count."\n";
    echo "s3 copied precond\t".$copy_precond_count ."\n";
    echo "s3 src not found\t".$s3_src_not_found ."\n";
    
    


    Если агрегированная статистика не нужна, второй скриптик — не нужен. Если нужна, пишем reducer:

    Пример reducer


    #!/usr/bin/php
    <?php
    error_reporting(-1);
    ini_set('memory_limit', '1024M');
    set_time_limit(0);
    gc_enable();
    
    $ar_reduce = array();
    
    while (($line = fgets(STDIN)) !== false) {
    
    
        $line = str_replace("\n","",$line);
        $ar_line = explode("\t", $line);
    
        if ( !isset($ar_reduce[$ar_line[0]]) ) $ar_reduce[$ar_line[0]] = 0;
        $ar_reduce[$ar_line[0]] += intval($ar_line[1]);
    
    }
    
    
    foreach ($ar_reduce as $key=>$value) {
    
        echo $key."\t".$value."\n";
    
    }
    ?>
    


    Инициализация серверов кластера


    Т.к. скрипты наши на PHP, необходимо подготовить скрипт инициализации, выполняемый на каждом сервере кластера:
    sudo apt-get -y update
    sudo apt-get -y install libssh2-php
    sudo apt-get -y install php5-curl
    sudo rm -f /etc/php5/cli/conf.d/suhosin.ini
    sudo mkdir -p /usr/share/php
    cd /usr/share/php
    sudo wget https://github.com/aws/aws-sdk-php/releases/download/2.5.0/aws.phar
    ...
    


    Выгружаем скрипты на PHP и bash в облако (s3)


    for FILE in bkp_s3_folder_hadoop_bootstrap.sh bkp_s3_folder_hadoop_mapper.php bkp_s3_folder_hadoop_reducer.php; do
    
        s3cmd -c /root/.s3cfg-key put /home/project/cron_jobs/$FILE s3://#папка скриптов#/code/
    
    done
    


    Выгрузка данных для обработки в s3


    Просто, например с помощью s3cmd, выгружаем исходные данные для обработки в папку в s3. Эти данные потом расплывутся по кластеру автоматически. Выгрузить можно сколько угодно данных и пусть кластер с ними мучается.

    Запуск обработки данных в кластере


    И напоследок такая вкусняшка — запускаем кластер для обработки наших данных.

    D=$(date +"%Y-%m-%d_%H-%M-%S")
    
    /opt/aws/emr/elastic-mapreduce --create --stream \
    --name myproject_$D \
    --step-name step_$D \
    --with-termination-protection \
    --step-action CANCEL_AND_WAIT \
    --ami-version '2.4.2' \
    --bootstrap-action '#путь к скрипту инициализации серверов, см. выше#' \
    --bootstrap-action 's3://elasticmapreduce/bootstrap-actions/configure-hadoop' \
    --args "-m,mapred.map.max.attempts=20,-m,mapred.tasktracker.map.tasks.maximum=15,-m,mapred.task.timeout=600000" \
    --input 's3://#папка с исходными файлами для обработки#/input/' \
    --mapper 's3://#папка скриптов#/code/#наш mapper#.php' \
    --reducer 's3://#папка скриптов#/code/#наш reducer#.php' \
    --output 's3://#папка с логами#/output_'$D \
    --log-uri 's3://#папка с логами#/logs/' \
    --num-instances 5 \
    --master-instance-type m1.small \
    --slave-instance-type m1.xlarge \
    --key-pair 'myproject_mapreduce'
    


    Тут важно подобрать правильно число железок для размножения кластера — чем больше, тем конечно быстрее. В данном примере мы устанавливаем не больше 15 процессов на один сервер. Можно больше, это зависит от объема оперативной памяти, но осторожно — следим за ее расходом.

    После отработки кластера в логах можно будет увидеть агрегированную статистику, логи также будут выгружены в s3.

    Обычно скорость обработки, которая до этого делалась неделями — поражает, вдохновляет и выводит на новый уровень осознания IT-континиума не хуже последней части «300 спартанцев» :-)


    Итоги



    В результате у вас появляется бизнес-инструмент, управляемый 2 скриптами на PHP. Число серверов (--num-instances 5) напрямую влияет на скорость обработки загруженного массива данных. В принципе никто не запрещает запустить 100 серверов с 10 потоками на каждом и обработать данные значительно быстрее, чем можно было сделать на одном сервере используя очередь заданий.

    Используя данную технологию простым и понятным образом, мы на одном из наших проектов сократили время обработки десятков миллионов объектов в s3 с недель до 2 дней.

    Коллеги, если есть вопросы, пожалуйста спрашивайте в комментах и посещайте наши конференции — мы с удовольствием поделимся опытом. И всем удачи в реализации веб-проектов и побед над Bigdata!
    Метки:
    1С-Битрикс 92,54
    Компания
    Поделиться публикацией
    Комментарии 51
    • +28
      Надо больше смешных картинок.
      • +11
        Я пока фотки вставлял, уровень тестостерона достиг критической отметки и статью с трудом удалось дописать :-)
        • +15
          Кресло чуть-чуть приопустить и тестостерон не мешает.
          • +3
            Особенно с Гомером.
            • +1
              Гомер был на фразу «провести ночь с мануалом» :-) Предлагаете и туда девушку вставить? :-)
              • 0
                К фразе «провести ночь с...» конечно надо картинку с девушкой.
                • +2
                  Картинка с девушкой
                  image
                  • +2
                    Это женщина кагбэ) Замужняя, и многодетная мать, к тому же!
        • +9
          Как обрабатывать терабайты данных в 1000 потоков на PHP — Hadoop/MapReduce

          Т.е. бросаем PHP и берём Java?:)
          • –5
            Зачем? Все делаем на PHP/bash/Python — и подключаем лишь библиотечку, которая может нашу логику раскидать на 5-500 серверов, прогнать по данным и вернуть ответ :-)
            • 0
              На самом деле на жаве мап/редьюс джобы написать проще и работало бы быстрей.
              • 0
                Жаву не очень любят в мире быстрых вычислений, unix и C ;-) Она медленная, жирная, много требует и при этом постоянно подвисает на сборках мусора. А пригрузив готовый софт на java задачками, написанными на perl/bash или просто вызвав юниксовую команду типа sort/grep — почему бы и нет? :-)
                • +9
                  Т.е. PHP любят в мире быстрых вычислений, а Java — нет? о_О
                  • –1
                    Ну. PHP это язык-сборщик, выполняет типа роль клея для состыковки возможностей многочисленных библиотек, часто активно обитающих в unix. Бизнесовая технология — соединил высокопроизводительные библиотеки и запустил в сжатые сроки.

                    А java претендует на роль «безалкогольного» С++/C, оперирует почти примитивными типами данных и как-бы предназначена для написания компонентов для PHP. Но проблема в том, что компоненты на java почти не используют ни в PHP, ни в python — предпочитая использовать быстрые C-библиотеки.

                    И получается что стек: C/C++/unix/PHP — дает быстрый результат в ожидаемые сроки, а java + java — это дольше, тяжелее, и библиотек под нее значительно, в разы меньше, чем можно взять в opensource и вызывать через механизм плагинов PHP.

                    • 0
                      Она медленная, жирная, много требует и при этом постоянно подвисает на сборках мусора.

                      Воу воу…

                      А java претендует на роль «безалкогольного» С++/C, оперирует почти примитивными типами данных и как-бы предназначена для написания компонентов для PHP. Но проблема в том, что компоненты на java почти не используют ни в PHP, ни в python — предпочитая использовать быстрые C-библиотеки.

                      Ничего не понял
                      • 0
                        Я о том, что у java своя очень специфическая ниша, т.к. ей не получилось гармонично встроится в стек C/C++/unix/PHP/Python/Perl — а попытки сделать это не прекращаются и поныне.

                        Именно поэтому нет особого смысла вместо PHP использовать Java, ну только в ряде исключительных случаев где нужен JIT и более совершенная сборка мусора :-)
                        • –1
                          Так и скажите, что вам Java не нравится ;-)
                          • +1
                            Очень нравится! Особенно тщательность проектирования API, продуманное использование паттернов проектирования — этого так не хватает скриптовым языкам типа знаете каких. Java учит мыслить системно, объектно. Да и сколько бизнесового софта, полезного, тот же Amazon Web Services частями на ней написаны :-)
                  • +4
                    Это заблуждения, то что она медленная
                    • +1
                      Лично проверял, в т.ч. на проектах с активным использованием JBoss :-) Проблема java — увлечение ООП и плохо предсказуемый сборщик мусора. В результате дикие требования к железу и памяти. JIT по идее должен ее ускорить и он делает это иногда, но до сих пор неумело и не очень уместно. А GUI на java — просто подвисающий ад какой-то: от NetBeans до Eclipe и JDeveloper.

                      Не верю, что появится технология с автоматическим управлением памятью с высокой скоростью работы, близкой к C. Если только если процессоры под ООП заточат, но тоже сомнительно.
                      • 0
                        Лично проверял, в т.ч. на проектах с активным использованием JBoss :-)


                        Это как измерять максимальную скорость, доступную автомобилям, при помощи самосвала КРАЗ.
                        • +1
                          Сравните код на С с аналогичным на Java — разница налицо. Объект на объекте и объектом погоняет пока не доберется до системного вызова read и прочитает 1 байт ;-)
                          • +2
                            Я 15 лет пишу на C высокоэффективные приложения, и около 10 — на Java. Java может быть очень быстрой, медленнее C, но всё равно очень быстрой. С Java проблемы возникают не из-за технологии, а из-за непонимания разработчиками того, что они делают и во что это выльется в реальности.
                            • +1
                              Согласен, она может быть очень быстрой когда сработает JIT через определенное время в серверном режиме виртуальной машины. Но она живет в собственном виртуальном мире, которому требуется виртуальная машина с кучей потрохов и скорость запуска этого мира…

                              Конкретный практический пример. Амазон кстати сначала сделал консольные утилиты работы с их API на java, но через определенное время переписал их на python.

                              Мы из bash первое время дергали маскирующиеся под unix-команды вызовы API с java и под нагрузкой машина просто начинала сходить с ума, падало ядро linux с ожиданиями блокировок или CPU уходило под 100%.

                              Пришлось вырезать java вызовы из bash-автоматики и переходить на более легкие интерфейсы к API Амазона на PHP/python. Нагрузка уменьшилась в разы.
                              • 0
                                Мы из bash первое время дергали маскирующиеся под unix-команды вызовы API с java и под нагрузкой машина просто начинала сходить с ума, падало ядро linux с ожиданиями блокировок или CPU уходило под 100%.

                                Ну всё абсолютно логично, потому что у Java большие издержки за запуск VM. Вы привели как раз пример непонимания того, как надо готовить кошек Java :)
                                • +1
                                  Одно время назад реализовал на PHP сервер, использующий мультиплексор сокетов в одном процессе через select. Тут наверно java бы лучше подошла с ее качественно иной сборкой мусора и JIT и работала бы побыстрее ;-)
            • +1
              Люблю азиаток :) А еще «мастер-мастер-кластер» — забавно звучит.
            • 0
              Я вроде отписывался от блога Битрикса, а оно в ленте…
              Статья, если честно, пустая, но за ссылочки спасибо, буду знать куда смотреть, если что.

              И мне кажется, или самолетами по данным с аварийных самописцев не управляют?

              • –3
                А вы хотели подробности по Map/Reduce изнутри? Но кому это интересно будет.
                • +2
                  терабайты данных, 1000 потоков и PHP?
                  ну или хотя бы что-нибудь наглядное, на вашем же примере с битриксом и описание задачи, которая у вас занимала столько времени и была прекрасно решена с помощью MR?

                  почему
                  $ar_reduce = array();
                  
                  дважды?)
                  • 0
                    Я понял, смотрите пример. Есть задача сжать, зашифровать и перенести 10 млн. файлов из бакета1 s3 в бакет2 s3.

                    Если делать средствами PHP на сервере, то можно форкануть максимум ну 20-30 потоков PHP, которые будут каждый выполняться в своем процессе. И это займет несколько недель. А объем данных растет и нужно системное решение.

                    Если то же самое делать средствами Hadoop, то задачу можно выполнить за час, но на большом количестве железок. Если выбрать разумное число железок с 15 потоками на каждой — то можно уложиться в 2 дня.

                    Т.е. если через полгода число файлов для обработки вырастит с 10 млн. до 50 млн., нужно будет поменять лишь одну циферку в конфиге запуска кластера Hadoop, увеличив число железок лишь.

                    Красиво же получается и просто. Разве не так?
                    • +2
                      Зачем нужен MR и Hadoop я более или менее представляю. И примеров его использования я также могу придумать много. Просто в таком случае я не представляю какой смысл в этой статье, поскольку вряд ли здесь описано что-то совершенно новое (или у вас задача и была только лишь в том, чтобы перенести 10 млн файлов?) и, наверное, у самого амазона есть туториалы как все это у них завести на PHP.
                      Вопрос только лишь в том, действительно ли это задача для PHP или же нет.
                      Возможно, я ошибаюсь.
                      • +1
                        Смысл в том, что готовых примеров боевого использования PHP + Hadoop я как не искал — не нашел. Было немного воды по Hadoop + Python. Пришлось весь путь преодолевать пробивая головой стены и ловя подводные камни. Зато результат превзошел все ожидания. Теперь делюсь с коллегами опытом :-)
                        • –1
                          А на java, которую я хорошо знаю и люблю — примеров полно, но разбираются в java — очень ограниченное число людей. И еще одной целью была принести полезные решения из этой области в мир веб-разработчиков на PHP ;-)
                      • +1
                        А, забыл, на входе у вас список названий файлов из 10 млн. позиций.
                        • 0
                          Убрал лишний массив, опечатка, спасибо.
                      • 0
                        Вы правы! Самолетами не управляют с аварийных самописцев, выделю жирным и подчеркну :-)
                      • +1
                        На Storm не смотрели?
                        • +1
                          Знаем. Потоковые обработчики данных — это тренд сейчас. Амазон недавно, писал выше, облачный сервис на эту тему выпустил даже (Kinesis). Хотя для односерверных задач вот присматриваюсь к nginx/ragel — очень быстрые комплируемые из регулярок state-машины думаю вполне подойдут.
                        • +10
                          Если кластер — мульти-мастер
                          Никакой он Вам не кластер
                          Он уже тупящий сид
                          Если вдруг позволит GID

                          Прочитай про map-reduce
                          Форкни и забудь про fuse
                          Файлы полетят в Hadoop
                          Вроде ты уже не нуб!

                          Больше скриптов-канапэ
                          Ты пиши на ПохАпэ
                          Девок фотки изучай
                          На спартанцев — не кончай!

                          Новый бизнес-инструмент
                          Развернешь теперь в момент
                          Весь поток в S3 летит
                          Ну и менеджер хвалит

                          Число серверов растет
                          Прибыль наша вверх идет
                          Обработку сократили
                          Всех с bigdat'ой победили!
                          • +1
                            Замечательно передали суть поста, допишу музыку и на ютуб! :-)
                            • +4
                              BigData рэп?)
                              • +1
                                Если серьезно, то толковой документации по Hadoop Streaming для использования его сисадмином, знающим bash/perl — практически нет. Немного воды лишь про его использование с python где-то в сети валяется. Особенно это касается конфигурации streaming под нагрузку, обработки ошибок, перезапуска заданий и т.п. Однако инструмент то полезный и нужный в быту, сами хорошо знаете.

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

                                А после поста — это сделает даже веб-разработчик на PHP :-)
                              • +2
                                >> Как бы мы не доверяли облаку, нужно эти файлы периодически выгружать в другое облако/серверы
                                Сказали они и выгрузили из S3 в S3.

                                А если серьёзно, нужно иметь хотябы насколько аккаунтов AWS на разных юрлиц. Или вообще хранить самую резрвную копию в другом облаке.
                                Сколько бы контейнеров в AWS не было, есть главный риск — амазон административно, извините, пукнет отказом в обслуживании в вашу сторону по любой причине.
                                От административных отказов, к сожалению, никто не застрахован.
                                • +1
                                  Абсолютно верно. Поэтому мы используем как минимум 2 конфигурации hadoop-кластеров. Один для копирования ( s3 условный COPY) из s3 в s3 — достаточно несколько машин, а другой, значительно более мощный — именно для выгрузки файлов на сторонние мощности за пределами Амазона — и только в этом случае, как я писал выше, файлы скачиваются в общую файловую систему Hadoop (HDFS), шифруются, подписываются и копируются из облачного провайдера.

                                  • +2
                                    Спасибо за подробный комментарий!
                                • +1
                                  Мапредьюз можно писать на чем угодно Тьюринг-полном, только вопрос — зачем?

                                  Все, что было спроектировано после Хадупа, уже позволяет писать задачи не на языке реализации, как в вашем случае, без стольких лишних телодвижений.
                                  • +1
                                    MR пакетный. Когда появляется задача «надо много и на потоке», то MR уже не кажется таким прекрасным
                                    • 0
                                      Вот у нас получилось задачу много и на потоке преобразовать в много и каждый в своем потоке. Это дороже да, но если есть возможность и нужно сделать быстро и потоков на одном сервере уже недостаточно — Hadoop/MR помогает.
                                    • –3
                                      Пехапешники узнали о существовании MR парадигмы и реализующего ее Hadoop, не прошло и 10 лет!
                                      • 0
                                        Организовать сбор статистики по производительности веб-приложения в браузере его клиентов на основании js Navigation Timing API — делается в 2 файла на PHP на 30 строк.


                                        А можно примеров рабочих увидеть? В сети такой информации не нашел. Нужно системно собрать статистики на несколько тысяч сайтов по списку.

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

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