работа с rabbitmq php
RabbitMQ — установка и простейший пример на PHP
RabbitMQ — это мощный инструмент, реализующий обмен сообщениями между компонентами программной среды, будь-то процессы, web-приложения, клиент-сервер и прочее. Обмен сообщениями происходит по стандарту AMQP, который своим появлением решил огромную кучу проблем и вылечил множество головных болей разработчиков.
Самым большим преимуществом является то, что стандарт доступен в огромном количестве языков программирования, это позволяет обмениваться сообщениями скрипту на PHP со скриптом на Python и им обоим отправлять сообщения на сервер, который написан на Java. В двух словах — очень удобно!
Основные термины:
Producer — поставщик — программа, которая отправляет сообщения в очередь.
Consumer — подписчик — программа, которая принимает сообщения из очереди, чаще всего находится в режиме ожидания и при получении сообщения сразу же приступает к его обработке.
Queue — очередь — та самая «труба» через которую сообщения от поставщика попадают к подписчику. Очередь не имеет ограничений ни на количество поставщиков, ни на количество подписчиков и даже нет ограничения на количество сообщений, хранящихся в ней на данный момент. Существует очередь внутри самого RabbitMQ и им же полностью обслуживается, наша забота только в том, чтобы отправлять в нее сообщения и получать их.
Про глубинный принцип работы инструмента сейчас писать не буду, возможно в одном из следующих включений, лучше расскажу как установить, настроить и начать пользоваться Rabbit ом.
Установка RabbitMQ на Linux
Первый делом нужно установить RabbitMQ Server, который как раз отвечает за «трубу», через которую будут посылаться сообщения, его наличие в системе гарантирует успех.
В системах, основанных на Debian, в том числе и Ubuntu, установить сервер можно через терминал из стандартного репозитория, но в этом случае не гарантируется свежая версия программы.
После этого можно подключать библиотеку Rabbit а уже непосредственно в проект.
Подключить RabbitMQ в проект с помощью Composer
У меня уже были заметки про установку библиотек с помощью Composer`а, это очень удобно. Создаем в папке с проектом файл composer.json и пишем туда такое содержимое.
Далее открываем папку с проектом и терминале и запускаем установку зависимостей
После этого в корне проекта появится папка vendor с установленной в ней библиотекой RabbitMQ.
Возможные проблемы! Иногда композер не может найти некоторые библиотеки в системе, например, у меня не нашлось двух библиотек, их нужно просто доустановить. В моем случае это были php-bcmath и php-mbstring, установить их легко.
Следующим шагом будет подключить файл autoloader.php в файлы исходного кода в своем проекте с помощью require_once, например, если файл script.php лежит в корне проекта, то строчка будет выглядеть вот так
С этого момента можно пользоваться библиотечными функциями.
Пример обмена сообщением с помощью RabbitMQ
В заголовке статьи обозначено, что пример подключения в проект и использования библиотеки я приведу на PHP. А пример будет простейший — два скрипта, одна очередь. Скрипт producer.php отправит в очередь сообщение со строкой, а скрипт consumer.php будет «слушать» очередь и выводить все строки, которые оттуда получит.
producer.php
consumer.php
Заключение
На самом деле инструмент очень мощный, позволяет строить очень гибкие архитектурные решения и не заморачиваться над передачей сообщений между компонентами. Вполне возможно, что я напишу еще несколько заметок о RabbitMQ с примерами посложнее или о том, как он работает. Ну а пока у меня все, спасибо за внимание!
Работа с rabbitmq php
This tutorial assumes RabbitMQ is installed and running on localhost on the standard port ( 5672 ). In case you use a different host, port or credentials, connections settings would require adjusting.
Where to get help
If you’re having trouble going through this tutorial you can contact us through the mailing list or RabbitMQ community Slack.
RabbitMQ is a message broker: it accepts and forwards messages. You can think about it as a post office: when you put the mail that you want posting in a post box, you can be sure that the letter carrier will eventually deliver the mail to your recipient. In this analogy, RabbitMQ is a post box, a post office, and a letter carrier.
The major difference between RabbitMQ and the post office is that it doesn’t deal with paper, instead it accepts, stores, and forwards binary blobs of data ‒ messages.
RabbitMQ, and messaging in general, uses some jargon.
Producing means nothing more than sending. A program that sends messages is a producer :
A queue is the name for a post box which lives inside RabbitMQ. Although messages flow through RabbitMQ and your applications, they can only be stored inside a queue. A queue is only bound by the host’s memory & disk limits, it’s essentially a large message buffer. Many producers can send messages that go to one queue, and many consumers can try to receive data from one queue. This is how we represent a queue:
Consuming has a similar meaning to receiving. A consumer is a program that mostly waits to receive messages:
Note that the producer, consumer, and broker do not have to reside on the same host; indeed in most applications they don’t. An application can be both a producer and consumer, too.
«Hello World»
(using the php-amqplib Client)
In this part of the tutorial we’ll write two programs in PHP that communicate using RabbitMQ. This tutorial uses a client library that requires PHP 7.x or 8.x.
First program will be a producer that sends a single message, and the second one will be a consumer that receives messages and prints them out. We’ll gloss over some of the detail in the php-amqplib API, concentrating on this very simple thing just to get started. It’s a «Hello World» of messaging.
The php-amqplib client library
RabbitMQ speaks multiple protocols. This tutorial covers AMQP 0-9-1, which is an open, general-purpose protocol for messaging. There are a number of clients for RabbitMQ in many different languages. We’ll use the php-amqplib in this tutorial, and Composer for dependency management.
Add a composer.json file to your project:
Provided you have Composer installed and functional, you can run the following:
Now we have the php-amqplib library installed, we can write some code.
Sending
then we can create a connection to the server:
Next we create a channel, which is where most of the API for getting things done resides.
To send, we must declare a queue for us to send to; then we can publish a message to the queue:
Lastly, we close the channel and the connection:
Sending doesn’t work!
Receiving
That’s it for our publisher. Our receiver listens for messages from RabbitMQ, so unlike the publisher which publishes a single message, we’ll keep the receiver running to listen for messages and print them out.
The code (in receive.php ) has almost the same include and use s as send :
Setting up is the same as the publisher; we open a connection and a channel, and declare the queue from which we’re going to consume. Note this matches up with the queue that send publishes to.
Note that we declare the queue here, as well. Because we might start the consumer before the publisher, we want to make sure the queue exists before we try to consume messages from it.
We’re about to tell the server to deliver us the messages from the queue. We will define a PHP callable that will receive the messages sent by the server. Keep in mind that messages are sent asynchronously from the server to the clients.
Putting it all together
Now we can run both scripts. In a terminal, run the consumer (receiver):
then, run the publisher (sender):
The consumer will print the message it gets from the sender via RabbitMQ. The receiver will keep running, waiting for messages (Use Ctrl-C to stop it), so try running the sender from another terminal.
Listing queues
You may wish to see what queues RabbitMQ has and how many messages are in them. You can do it (as a privileged user) using the rabbitmqctl tool:
On Windows, omit the sudo:
Time to move on to part 2 and build a simple work queue.
Production [Non-]Suitability Disclaimer
Please keep in mind that this and other tutorials are, well, tutorials. They demonstrate one new concept at a time and may intentionally oversimplify some things and leave out others. For example topics such as connection management, error handling, connection recovery, concurrency and metric collection are largely omitted for the sake of brevity. Such simplified code should not be considered production ready.
Please take a look at the rest of the documentation before going live with your app. We particularly recommend the following guides: Publisher Confirms and Consumer Acknowledgements, Production Checklist and Monitoring.
Getting Help and Providing Feedback
If you have questions about the contents of this tutorial or any other topic related to RabbitMQ, don’t hesitate to ask them on the RabbitMQ mailing list.
Help Us Improve the Docs 1 «Hello World!»
The simplest thing that does something
2 Work queues
Distributing tasks among workers (the competing consumers pattern)
3 Publish/Subscribe
Sending messages to many consumers at once
4 Routing
Receiving messages selectively
5 Topics
Receiving messages based on a pattern (topics)
6 RPC
7 Publisher Confirms
Reliable publishing with publisher confirms
Работа с rabbitmq php
В этом разделе помещены уроки по PHP скриптам, которые Вы сможете использовать на своих ресурсах.
Фильтрация данных с помощью zend-filter
Когда речь идёт о безопасности веб-сайта, то фраза «фильтруйте всё, экранируйте всё» всегда будет актуальна. Сегодня поговорим о фильтрации данных.
Контекстное экранирование с помощью zend-escaper
Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак. В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.
Подключение Zend модулей к Expressive
Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение. В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.
Совет: отправка информации в Google Analytics через API
Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.
Подборка PHP песочниц
Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.
Совет: активация отображения всех ошибок в PHP
При поднятии PHP проекта на новом рабочем окружении могут возникнуть ошибки отображение которых изначально скрыто базовыми настройками. Это можно исправить, прописав несколько команд.
Агент
PHP парсер юзер агента с поддержкой Laravel, работающий на базе библиотеки Mobile Detect.
Работа с rabbitmq php
This tutorial assumes RabbitMQ is installed and running on localhost on the standard port ( 5672 ). In case you use a different host, port or credentials, connections settings would require adjusting.
Where to get help
If you’re having trouble going through this tutorial you can contact us through the mailing list or RabbitMQ community Slack.
In the first tutorial we wrote programs to send and receive messages from a named queue. In this one we’ll create a Work Queue that will be used to distribute time-consuming tasks among multiple workers.
The main idea behind Work Queues (aka: Task Queues) is to avoid doing a resource-intensive task immediately and having to wait for it to complete. Instead we schedule the task to be done later. We encapsulate a task as a message and send it to a queue. A worker process running in the background will pop the tasks and eventually execute the job. When you run many workers the tasks will be shared between them.
This concept is especially useful in web applications where it’s impossible to handle a complex task during a short HTTP request window.
Preparation
We will slightly modify the send.php code from our previous example, to allow arbitrary messages to be sent from the command line. This program will schedule tasks to our work queue, so let’s name it new_task.php :
Our old receive.php script also requires some changes: it needs to fake a second of work for every dot in the message body. It will pop messages from the queue and perform the task, so let’s call it worker.php :
Note that our fake task simulates execution time.
Run them as in tutorial one:
Round-robin dispatching
One of the advantages of using a Task Queue is the ability to easily parallelise work. If we are building up a backlog of work, we can just add more workers and that way, scale easily.
First, let’s try to run two worker.php scripts at the same time. They will both get messages from the queue, but how exactly? Let’s see.
In the third one we’ll publish new tasks. Once you’ve started the consumers you can publish a few messages:
Let’s see what is delivered to our workers:
By default, RabbitMQ will send each message to the next consumer, in sequence. On average every consumer will get the same number of messages. This way of distributing messages is called round-robin. Try this out with three or more workers.
Message acknowledgment
Doing a task can take a few seconds. You may wonder what happens if one of the consumers starts a long task and dies with it only partly done. With our current code, once RabbitMQ delivers a message to the consumer it immediately marks it for deletion. In this case, if you kill a worker we will lose the message it was just processing. We’ll also lose all the messages that were dispatched to this particular worker but were not yet handled.
But we don’t want to lose any tasks. If a worker dies, we’d like the task to be delivered to another worker.
In order to make sure a message is never lost, RabbitMQ supports message acknowledgments. An ack(nowledgement) is sent back by the consumer to tell RabbitMQ that a particular message has been received, processed and that RabbitMQ is free to delete it.
If a consumer dies (its channel is closed, connection is closed, or TCP connection is lost) without sending an ack, RabbitMQ will understand that a message wasn’t processed fully and will re-queue it. If there are other consumers online at the same time, it will then quickly redeliver it to another consumer. That way you can be sure that no message is lost, even if the workers occasionally die.
A timeout (30 minutes by default) is enforced on consumer delivery acknowledgement. This helps detect buggy (stuck) consumers that never acknowledge deliveries. You can increase this timeout as described in Delivery Acknowledgement Timeout.
Message acknowledgments were previously turned off by ourselves. It’s time to turn them on by setting the fourth parameter to basic_consume to false (true means no ack) and send a proper acknowledgment from the worker, once we’re done with a task.
Using this code we can be sure that even if you kill a worker using CTRL+C while it was processing a message, nothing will be lost. Soon after the worker dies all unacknowledged messages will be redelivered.
Acknowledgement must be sent on the same channel that received the delivery. Attempts to acknowledge using a different channel will result in a channel-level protocol exception. See the doc guide on confirmations to learn more.
Forgotten acknowledgment
In order to debug this kind of mistake you can use rabbitmqctl to print the messages_unacknowledged field:
On Windows, drop the sudo:
Message durability
We have learned how to make sure that even if the consumer dies, the task isn’t lost. But our tasks will still be lost if RabbitMQ server stops.
When RabbitMQ quits or crashes it will forget the queues and messages unless you tell it not to. Two things are required to make sure that messages aren’t lost: we need to mark both the queue and messages as durable.
First, we need to make sure that the queue will survive a RabbitMQ node restart. In order to do so, we need to declare it as durable. To do so we pass the third parameter to queue_declare as true :
This flag set to true needs to be applied to both the producer and consumer code.
Note on message persistence
Fair dispatch
You might have noticed that the dispatching still doesn’t work exactly as we want. For example in a situation with two workers, when all odd messages are heavy and even messages are light, one worker will be constantly busy and the other one will do hardly any work. Well, RabbitMQ doesn’t know anything about that and will still dispatch messages evenly.
This happens because RabbitMQ just dispatches a message when the message enters the queue. It doesn’t look at the number of unacknowledged messages for a consumer. It just blindly dispatches every n-th message to the n-th consumer.
In order to defeat that we can use the basic_qos method with the prefetch_count = 1 setting. This tells RabbitMQ not to give more than one message to a worker at a time. Or, in other words, don’t dispatch a new message to a worker until it has processed and acknowledged the previous one. Instead, it will dispatch it to the next worker that is not still busy.
Note about queue size
If all the workers are busy, your queue can fill up. You will want to keep an eye on that, and maybe add more workers, or have some other strategy.
Putting it all together
Final code of our new_task.php file:
Using message acknowledgments and prefetch you can set up a work queue. The durability options let the tasks survive even if RabbitMQ is restarted.
Now we can move on to tutorial 3 and learn how to deliver the same message to many consumers.
Production [Non-]Suitability Disclaimer
Please keep in mind that this and other tutorials are, well, tutorials. They demonstrate one new concept at a time and may intentionally oversimplify some things and leave out others. For example topics such as connection management, error handling, connection recovery, concurrency and metric collection are largely omitted for the sake of brevity. Such simplified code should not be considered production ready.
Please take a look at the rest of the documentation before going live with your app. We particularly recommend the following guides: Publisher Confirms and Consumer Acknowledgements, Production Checklist and Monitoring.
Getting Help and Providing Feedback
If you have questions about the contents of this tutorial or any other topic related to RabbitMQ, don’t hesitate to ask them on the RabbitMQ mailing list.
Help Us Improve the Docs 1 «Hello World!»
The simplest thing that does something
2 Work queues
Distributing tasks among workers (the competing consumers pattern)
3 Publish/Subscribe
Sending messages to many consumers at once
4 Routing
Receiving messages selectively
5 Topics
Receiving messages based on a pattern (topics)
6 RPC
7 Publisher Confirms
Reliable publishing with publisher confirms
Взаимодействие PHP и Erlang посредством RabbitMQ
Вступление
Чем больше программируешь на php, тем чаще попадаются задачи, для решения которых нужен демон на сервере. Да, конечно существует phpDaemon, cron или костыли, которые при каждом n-ом запуске скрипта вызывают какой-то определенный набор операций. Но когда мы говорим о проектах с нагрузкой больше, чем на обычном сайте, мы начинаем расстраиваться.
В одном из проектов для решения такой задачи мы решили использовать связку php+RabbitMQ+erlang. На php уже был написан необходимый функционал, нам надо было лишь разнести вызовы по времени и на разные машинки. Конкретно задача звучала так: написать парсер пользователей с внешнего хранилища данных и, самое главное, поддерживать актуальность данных, а в случае их изменения, посылать уведомления.
Исходные данные
— Rest-функция на php, добавляющая пользователя в избранное. Из этого списка в дальнейшем и будут формироваться пользователи, актуальность информации которых мы и будем поддерживать, а в случае изменения — посылать уведомления на клиента.
— Приложение на erlange, который должен координировать, каких пользователей мы сейчас обрабатывем и т.д. Обработка информации с внешнего источника осуществляется двумя путями — это парсинг html страниц или где это возможно — запросы api. Для обработки ответов используется rest-функция, написанная на php.
— Мы должны поддерживать возможность простого масштабирования на большое количество серверов. Список пользователей, которые надо парсить, находятся в очередях, формируемых RabbitMQ.
Задача номер 1 — настроить расширение php для работы с RabbitMQ
В первую очередь устанавливаем дополнительный программные пакеты:
Далее сама установка, найденная на просторах интернета:
Если вам повезло, то все установилось верно.
Задача номер 2 — установить RabbitMQ и web-панель управления им
Далее по данному адресу вы получаете доступ к управления очередями, по умолчанию логин(guest) и пароль(guest)
ip.addres:15672/
Задача номер 3 — через php влиять на очереди RabbitMQ
Задача номер 4 — Создать приложение на erlange используя rebar
Задача номер 5 — Запускаем приложение на erlange
Сначала устанавливаем CMake:
В Makefile прописываем следующее:
Задача номер 6 — подключить необходимые библиотеки для связи RabbitMQ и Erlang
В rebar.config помещаем следующее:
Выполняем rebar get-deps, подтягивающий зависимости. Далее возникли сложности с оставшимися библиотеками, поэтому пришлось использовать то, что написано на официальном сайте RabbitMQ. Но перед эти доустанавливаем необходимые пакеты:
После заходим в папочку deps, которую создал rebar и, используя git, все скачиваем, а после устанавливаем:
Задача номер 7 — из Erlangа получать сообщения из очередей RabbitMQ
Файл myapp_app.erl оставляем чуть чуть редактируем, чтобы можно было запускать из makefile, что мы написали:
Файл myapp_sup.erl, отвечающий за наблюдение процессами, дописываем вызов нашего модуля из init:
Модуль, отвечающий за связь с RabbitMQ:
Тут все достаточно просто, мы подписываемся на очередь «yyyyyyy2»:
Затем сообщаем RabbitMQ, что сообщение успешно обработано: