Попытка создать распределенный искатель с ZeroMQ

Я только начал изучать ZeroMQ и хочу создать распределенный webcrawler в качестве примера во время сглаживания.

Моя идея состоит в том, чтобы иметь «сервер», написанный на PHP, который принимает URL-адрес, где должен начаться сканирование.

Рабочим (C # cli) придется сканировать этот URL-адрес, извлечь ссылки и вернуть их обратно в стек на сервере. Сервер продолжает отправлять URL-адреса в стек сотрудникам. Возможно, redis будет отслеживать все просканированные URL-адреса, поэтому мы не сканируем сайты несколько раз и можем извлекать статистику текущего процесса.

Я хотел бы, чтобы сервер распределял задачи равномерно, знал новых / отсутствующих сотрудников и перераспределял URL-адреса, когда рабочий не отвечает.

Почему PHP для сервера: мне очень нравится PHP, вот и все. Я не хочу, чтобы сделать пример / тестовый проект более сложным.

Почему C # для миньонов: потому что он работает на большинстве машин Windows. Я могу предоставить исполняемый файл различным друзьям, которые могут просто выполнить его и помочь мне проверить мой проект.

Процесс обхода и redis функциональность не являются частью моего вопроса.

Первым моим подходом был шаблон PUSH / PULL, который обычно работает для моего сценария, но не знает о его фаворитах. Я думаю, что мне нужен посредник DEALER / ROUTER посередине, и я должен сам справиться с осознанием рабочего.

Я нашел этот вопрос, но я не уверен, понимаю ли я ответ …

Я прошу некоторых советов о том, как импортировать материал zmq. Правильно ли подходит дилер? Есть ли способ получить автоматическое информирование работников? Я думаю, мне нужны некоторые ресурсы / примеры, или вы думаете, что мне просто нужно копать глубже в руководстве zmq?

Однако некоторые намеки на правильное направление были бы замечательными 🙂

ура

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

Определение всех событий

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

DISPATCH_WORK_TO_CRAWLER_EVENT CRAWLER_NODE_STATUS_EVENT ... 

Определение стандартного сообщения

Вся связь между сервером и сканерами должна выполняться с использованием ZMsg, поэтому определите стандарт, который организует ваши фреймы, примерно так:

 Frame1: "Crawler v1.0" //this is a static header Frame2: <event type> //ex: "CRAWLER_NODE_STATUS_EVENT" Frame3: <content xml/json/binary> //content that applies to this event (if any) 

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

сервер

Используйте один ROUTER на сервере для асинхронной и двунаправленной связи с сканерами. Кроме того, используйте PUB сокет для передачи сообщений о сердцебиении.

Не блокируйте гнездо ROUTER, используйте POLLER для циклического POLLER каждые 5 POLLER или что-то еще, это позволяет серверу периодически выполнять другие действия, например, передавать события биения на сканеры; что-то вроде этого:

 Socket rtr = .. //ZMQ.ROUTER Socket pub = .. //ZMQ.PUB ZMQ.Poller poller = new ZMQ.Poller(2) poller.register( rtr, ZMQ.Poller.POLLIN) poller.register( pub, ZMQ.Poller.POLLIN) while (true) { ZMsg msg = null poller.poll(5000) if( poller.pollin(0)){ //messages from crawlers msg = ZMsg.recvMsg(rtr) } //send heartbeat messages ZMsg hearbeatMsg = ... //create message content here, //publish to all crawlers heartbeatMsg.send(pub) } 

Чтобы ответить на вопрос о осведомленности о работниках, простой и эффективный метод использует стек FIFO вместе с сообщениями сердцебиения; что-то вроде этого:

  • сервер поддерживает простой стек FIFO в памяти
  • сервер отправляет heartbeats; сканеры отвечают своим именем узла; ROUTER автоматически помещает адрес узла в сообщение также (считывание при обтекании сообщения)
  • нажимать 1 объект на стек, содержащий имя узла и адрес узла
  • когда сервер хочет отправить работу поисковому роботу, просто введите следующий объект из стека, правильно создайте сообщение и адрес (используя адрес узла), а от него идет этот рабочий
  • отправляйте больше работы другим сканерам таким же образом; когда искатель отвечает на сервер, просто нажмите еще один объект с именем / адресом узла в стеке; другие работники не будут доступны, пока они не ответят, поэтому мы их не беспокоим.

Это простой, но эффективный метод распределения работы, основанный на доступности работников, а не слепо откладывать работу. Проверьте пример lbbroker.php , концепция такая же.

Гусеничный (рабочий)

Работник должен использовать один разъем DEALER вместе с SUB . DEALER является основным сокетом для асинхронной связи, и SUB подписывается на сообщения о сердцебиении с сервера. Когда работник получает сообщения о сердцебиении, он отвечает на сервер в гнезде DEALER.

 Socket dlr = .. //ZMQ.DEALER Socket sub = .. //ZMQ.SUB ZMQ.Poller poller = new ZMQ.Poller(2) poller.register( dlr, ZMQ.Poller.POLLIN) poller.register( sub, ZMQ.Poller.POLLIN) while (true) { ZMsg msg = null poller.poll(5000) if( poller.pollin(0)){ //message from server msg = ZMsg.recvMsg(dlr) } if( poller.pollin(1)){ //heartbeat message from server msg = ZMsg.recvMsg(sub) //reply back with status ZMsg statusMsg = ... statusMsg.send(dlr) } 

Остальное вы можете выяснить самостоятельно. Работайте с примерами PHP , создавайте материал, разбивайте его, создавайте больше, это единственный способ, которым вы научитесь!

Получайте удовольствие, надеюсь, что это поможет!