Чтение, «Райтинг, рекурсия и повторное использование

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

Конвейеры данных, очевидно, считывают и записывают данные, но хотя люди обычно упоминают блок-схемы направленного ациклического графа (DAG), эта модель ограничивает, и в целом нам нужно что-то более выразительное — как показал язык Ko внутри Google. Есть также веские аргументы в пользу расширения DAG для включения обычных программных конструкций, таких как итерация цикла и рекурсия при оценке результатов.

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

Распределенное рассуждение

Обработка данных может выиграть от явных и неявных циклов с privisos. Все понимают идею перебора очередей и списков, повторного использования одного и того же кода для каждого элемента. Рекурсия означает, что мы сначала обещаем результат, а затем вычисляем его «как раз вовремя». Императивный подход будет состоять в том, чтобы построить все предпосылки для результата одну за другой, а затем объединить их в конце. Результат тот же, но если ставить детали перед пониманием, получается более неуклюжая форма выражения.

В последнем посте мы подчеркнули взаимосвязь между безопасностью процесса и конфиденциальностью данных, упомянув о важности обработки трех F (ошибки, ошибки и недостатки). В этой части мы переходим от 3 F к 4 R: чтение, запись, рекурсия и возможность повторного использования. Как уже упоминалось, воспроизводимость является общим требованием бизнеса, но любые общедоступные (глобальные и изменяемые) данные, задействованные в конвейере обработки, сделают его потенциально невоспроизводимым и переложат бремя управления безопасностью процесса на пользователя. . Это может быть несправедливым бременем, если пользователь в первую очередь интересуется наукой о данных. В облаке ставки выше, поскольку потенциальные последствия масштабирования стихийного бедствия могут иметь потенциально неограниченные затраты.

Рекурсия и конфиденциальность в масштабе

Чтобы выполнить более общую обработку в масштабе, вы можете использовать сочетание итерации и рекурсии для распределенных общих данных для:

  • Повторное использование кода в одном и том же процессе
  • Повторное использование данных в одном и том же процессе

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

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

Перемещение данных в функции и из них напрямую, вместо того, чтобы указывать на них по ссылке, приведет к узким местам в данных, которые досаждают классическим балансировщикам нагрузки промежуточных блоков. Вместо того, чтобы «съедать» данные, процессы могут сидеть рядом с конвейером и погружаться в эти данные по принципу «необходимо знать» («Не ешь, займи место»). Это может привести к побочным преимуществам очень полезной вспомогательной функциональности для частичного анализа данных, например, при тестировании (см. следующий пост № 14).

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

Выход из-под контроля

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

Давайте посмотрим на такой гипотетический пример конвейера, который не является настоящим DAG, и попробуем сформулировать проблему как «хлебный» конвейер как можно проще. На рисунке ниже показан упрощенный веб-сканер, заполненный несколькими URL-адресами, который обращается к этим URL-адресам и сканирует их в поисках дополнительных ссылок, возвращая все новые URL-адреса в очередь для посещения по очереди. Процесс представляет собой DAG процесса, завернутый в неявный цикл данных, что делает его неявно циклическим графом — со всеми потенциальными опасностями бесконечного цикла и т. д. Далее предположим, что данные помещаются в простую старую базу данных, которая явно не является часть трубопровода. Неопытные пользователи, естественно, находят это удобным и могут не оценить проблемы. Он может легко застрять в бесконечном цикле, снова и снова просматривая одни и те же страницы. На первый взгляд каждый поток представляет собой DAG, но весь процесс представляет собой бесконечный недетерминированный цикл. В этом примере нужна надлежащая очередь FIFO, в которой повторяющиеся значения удаляются в течение определенного интервала времени, определенного политикой.

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

Как показано, этот конвейер ничего не делает, пока некоторые данные не будут переданы в последовательную очередь. Чтобы начать это, мы должны предварительно заполнить очередь данных некоторыми URL-адресами, поместив их в базу данных вне диапазона, а затем она начнет сканировать из этих мест и накапливать больше. Но что особенно важно, это ничего не делает, чтобы избежать застревания в петлях, например. если страницы ссылаются друг на друга, весь конвейер может бесконечно колебаться между одними и теми же URL-адресами. Масштабируемый процесс должен избегать повторного отслеживания недавних путей.

Замки на кратковременную память

Мы можем улучшить этот первый набросок несколькими способами — во-первых, добавив блокировку защиты от повторного посещения недавно посещенных URL-адресов где-то в цикле, с датой истечения срока действия для блокировки данных для повторного сканирования (в основном поэтому нейроны имеют мертвое время после срабатывания). — для предотвращения захватов тугой петли). Мы также можем удалить явную параллельную логику, которая не представляет интереса для специалиста по данным, и сделать параллелизм автоматическим в соответствии с количеством ожидающих URL-адресов в потоке и ограничением ресурсов. Таким образом, когда конвейер молчит или когда мы рады «улучшить» его до более низкого приоритета, мы можем уменьшить количество потоков, не останавливая процесс и не теряя его состояния. На приведенной ниже диаграмме показано это поведение.

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

Затем мы можем оставить неявным или в качестве параметра конфигурации количество параллелизма (скажем, максимум 3 потока), которое будет автоматически обрабатываться умными оболочками для задач и ссылок. Для пользователя все это может выглядеть так просто:

# Pipeline notebook

ingress -> getURLs
getURLs ->3 “crawl neighbours”
        -> “store graph”
        -> getURLs

# Notes
[crawl neighbours]
Container = crawler_*.docker.img
Version = 1.2

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

Чтобы справиться с зацикливанием, функция getURLs должна однозначно агрегировать входные данные только из двух источников: i) входной источник, из которого отбрасываются подсказки, и ii) очередь данных, возвращаемая при сканировании. Для полного устранения неоднозначности метода необходимо несколько вариантов политики, но в остальном он хорошо определен и поддается автоматизации. На рисунке ниже схематично показано, как можно агрегировать входные данные. Подробности в другой раз.

Смарт и СмартРРРР

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