У меня проблема, которая немного затрудняет попытку понять идеальное решение, и, чтобы лучше объяснить это, я расскажу здесь свой сценарий.
У меня есть сервер, который будет получать заказы от нескольких клиентов. Каждый клиент будет представлять набор повторяющихся задач, которые должны выполняться через определенные промежутки времени, например: client A отправляет задание AA, которое должно выполняться каждую минуту между 2009-12-31 и 2010-12-31 ; поэтому, если моя математика правильная, это около 525 600 операций в год, учитывая больше клиентов и задач, было бы невозможно разрешить серверу обрабатывать все эти задачи, поэтому я придумал идею рабочих машин. Сервер будет разработан на PHP.
Рабочие машины – это просто обычные дешевые компьютеры на базе Windows, которые я буду размещать у себя дома или на рабочем месте, каждый рабочий будет иметь выделенное интернет-соединение ( с динамическими IP-адресами ) и ИБП, чтобы избежать перебоев в подаче электроэнергии. Каждый работник также будет запрашивать сервер каждые 30 секунд или около того через вызовы веб-службы, выберет следующее незавершенное задание и обработает его. Как только работа будет завершена, работник будет отправлять выходные данные на сервер и запрашивать новое задание и так далее до бесконечности. Если необходимо масштабировать систему, я должен просто создать нового работника, и все это должно выполняться без проблем. Рабочий клиент будет разработан в PHP или Python.
В любой момент времени мои клиенты должны иметь возможность входа на сервер и проверки состояния заданий, которые они заказывали.
Теперь вот где сложная часть пинает:
У меня есть некоторые сомнения относительно общего дизайна базы данных и технологий использования.
Первоначально я думал об использовании нескольких баз данных SQLite и присоединении их ко всем на сервере, но я не могу понять, как я буду группировать клиенты для создания отчетов о работе .
Я никогда не работал ни с одной из следующих технологий: memcached , CouchDB , Hadoop и все такое, но я хотел бы знать, подходит ли какая-либо из них для моей проблемы, и если да, которую вы рекомендуете для новичков, «распределенные вычисления» (или эта параллель?), как я. Имейте в виду, что у рабочих есть динамические IP-адреса.
Как я уже сказал, у меня также возникают проблемы с общим дизайном базы данных, отчасти потому, что я все еще не выбрал какую-либо конкретную СУБД R (D), но одна проблема, которая у меня есть, и я думаю, что это агностически для СУБД, которую я выбираю, к системе очередей … Должен ли я предварительно просчитать все абсолютные временные метки к определенному заданию и иметь большой набор временных меток , выполнить и пометить их как полные в порядке возрастания или у меня будет более умная система типа « когда модуль временной метки 60 = = 0 -> выполнить ". Проблема с этой «умной» системой заключается в том, что некоторые задания не будут выполняться, потому что некоторые работники могут ждать ничего, пока другие перегружены. Что ты предлагаешь?
PS: Я не уверен, правильно ли заголовок и теги этого вопроса отражают мою проблему и что я пытаюсь сделать; если нет, отредактируйте соответствующим образом.
Спасибо за ваш вклад!
@timdev:
Похоже, вы на пороге воссоздания Гирмана . Вот введение для Gearman:
Gearman предоставляет общую инфраструктуру приложений для работы с другими машинами или процессами, которые лучше подходят для работы. Он позволяет выполнять параллельную работу, обрабатывать баланс нагрузки и вызывать функции между языками. Он может использоваться в различных приложениях, с веб-сайтов высокой доступности и для транспорта событий репликации базы данных. Другими словами, именно нервная система связана с передачей распределенной обработки.
Вы можете написать как ваш клиент, так и код рабочего стола в PHP.
Повторите свой вопрос о сервере Gearman, скомпилированном для Windows: я не думаю, что он доступен в аккуратном пакете, предварительно созданном для Windows. Gearman все еще довольно молодой проект, и они, возможно, не достигли зрелости до готовых к запуску дистрибутивов для Windows.
Сотрудники Sun / MySQL Эрик Дэй и Брайан Акер дали учебное пособие для Gearman в OSCON в июле 2009 года, но в их слайдах упоминаются только пакеты Linux.
Вот ссылка на проект Perl CPAN Testers, который указывает, что Gearman-Server может быть построен на Win32 с использованием компилятора Microsoft C ( cl.exe
), и он проходит тесты: http://www.nntp.perl.org/group /perl.cpan.testers/2009/10/msg5521569.html Но я предполагаю, что вам нужно скачать исходный код и создать его самостоятельно.
Gearman кажется идеальным кандидатом для этого сценария, возможно, вы даже захотите виртуализировать свои машины Windows на несколько рабочих узлов на машину в зависимости от того, сколько вычислительной мощности вам нужно.
Также система постоянных очередей в редукторе предотвращает потерю рабочих мест при сбое рабочего или сервера редуктора. После перезапуска службы очередь просто продолжается там, где она остановилась перед сбоем / перезагрузкой, вам не нужно заботиться обо всем этом в своем приложении, и это большое преимущество и экономит много времени / кода
Разработка пользовательского решения может работать, но преимущества механизма, особенно постоянной очереди, кажутся мне, что это может быть наилучшим решением для вас на данный момент. Я не знаю о бинарнике окон для редуктора, но я думаю, что это должно быть возможно.
Более простым решением было бы иметь единственную базу данных с несколькими связанными php-узлами. Если вы используете правильную RDBMS (MSql + InnoDB будет делать), вы можете заставить одну таблицу действовать как очередь. Затем каждый работник вытаскивает задачи из этого для работы и записывает их обратно в базу данных по завершении, используя транзакции и блокировку для синхронизации. Это немного зависит от размера входных / выходных данных. Если он большой, это может быть не самая лучшая схема.
Я бы избежал sqlite для такого рода задач, хотя это очень замечательная база данных для небольших приложений, она не справляется с параллелизмом очень хорошо, у нее есть только одна блокировка strategey, которая должна блокировать всю базу данных и сохранять ее заблокированной до транзакции sinlge завершено.
Рассмотрите Postgres, у которого есть параллелизм в промышленной силе и управление блокировками, и может прекрасно справляться с несколькими одновременными транзакциями.
Также это звучит как работа для очередей! Если бы вы были в hte Java world, я бы порекомендовал архитектуру JMS для вашего решения. Существует проект 'dropr', чтобы сделать что-то подобное в php, но все его довольно новое, поэтому он может не подходить для вашего проекта.
Какую бы технику вы ни использовали, вы должны пойти на решение «свободного рынка», где рабочие потоки потребляют доступные «рабочие места» так быстро, как только могут, а не «командная экономика», где центральный процесс распределяет задачи для выбора работников.
Настройка главного сервера и нескольких рабочих выглядит правильно в вашем случае.
На главном сервере я бы установил MySQL (Percona InnoDB версия стабильная и быстрая ) в репликации master-master, поэтому у вас не будет одной точки отказа. Главный сервер будет располагать API, который работники будут тянуть через каждые N секунд. Мастер проверяет, есть ли доступное задание, если это необходимо, чтобы отметить, что задание было назначено рабочему X и вернуть соответствующий вход работнику (все это через HTTP). Кроме того, здесь вы можете хранить все файлы сценариев рабочих.
На рабочих я настоятельно рекомендую вам установить дистрибутив Linux. В Linux проще настроить запланированные задачи, и в целом я считаю, что это более подходит для работы. С помощью Linux вы можете даже создать живое изображение cd или iso с прекрасно настроенным рабочим и установить его быстро и легко на всех машинах, которые вы хотите. Затем настройте задание cron, которое будет RSync с основным сервером для обновления / изменения скриптов. Таким образом вы измените файлы только в одном месте (главный сервер), и все рабочие получат обновления.
В этой конфигурации вам не нужны IP-адреса или количество рабочих, потому что рабочие подключаются к мастеру, а не наоборот.
Рабочее задание довольно просто: спросите API о работе, сделайте это, отправьте результат через API. Промыть и повторить 🙂
Вместо того, чтобы повторно изобретать колесо очередей через SQL, вы могли бы использовать систему обмена сообщениями, такую как RabbitMQ или ActiveMQ, как ядро вашей системы. Каждая из этих систем обеспечивает протокол AMQP и имеет резервные очереди на жестком диске. На сервере у вас есть одно приложение, которое подталкивает новые задания в «рабочую» очередь в соответствии с вашим расписанием, а другое – записывает результаты из очереди «результата» в базу данных (или действует на нее каким-то другим способом).
Все рабочие подключаются к RabbitMQ или ActiveMQ. Они выходят из рабочей очереди, выполняют задание и помещают ответ в другую очередь. После того, как они это сделали, они ПРИЗЫВАЮТ первоначальную заявку на задание, чтобы сказать «ее сделано». Если рабочий отключит свое соединение, задание будет восстановлено в очередь, чтобы другой рабочий мог это сделать.
В базе данных могут храниться все, кроме очередей (описания должностных обязанностей, детали клиента, завершенная работа). Но что-нибудь в реальном времени нужно ставить где-то в другом месте. В моей собственной работе я транслирую данные о реальном энергопотреблении, и многие люди попадают в базу данных, чтобы опросить ее, это плохая идея. Я написал о живых данных в своей системе .
Я думаю, вы идете в правильном направлении с главным дистрибьютором вакансии и рабочими. Я бы связался с ними через HTTP.
Я бы выбрал C, C ++ или Java для клиентов, поскольку у них есть возможности запускать скрипты (execvp в C, System.Desktop.something в Java). Рабочие места могут быть просто именем сценария и аргументов для этого скрипта. Вы можете вернуть клиентам статус на рабочие места. Если задания не удались, вы можете повторить их. Вы можете опросить клиентов каждую минуту (или каждые х секунд и заставить сервер сортировать задания)
PHP будет работать на сервере.
MySQL будет работать отлично для базы данных. Я бы просто сделал две метки времени: начало и конец. На сервере я бы поискал WHEN SECONDS == 0