Queuing with RabbitMQ and PHP
There are many times that you want to write background processes and queue up the tasks so that they can be handled in sequential order. There are any number of queues available for software developers, and one that I’ve really taken a liking to is RabbitMQ. Besides the fact that the queue is designed to requeue messages that are unsuccessfully delivered, RabbitMQ is fast and efficient.
This week I’ll be describing how to implement RabbitMQ in a PHP application. There’s a lot to cover, so this will be a three-part series to help you understand RabbitMQ’s unique style (as well as understand AMQP, the protocol behind RabbitMQ). The other posts will publish tomorrow and Thursday. Let’s dive right in.
What is a connection? What is a channel?
RabbitMQ has a typical “connection” which is a TCP/IP connection to the RabbitMQ server. However, RabbitMQ is a bit more complicated, introducing a concept called the channel.
A channel is almost a “connection-within-a-connection”. This special connection is akin to a transaction between the client and the RabbitMQ server, but treating it like a transaction is a bit of a misnomer.
An open channel helps prevent TCP/IP connection timeouts, and also reduces TCP/IP connections while still allowing atomic communications from multiple workers over the same channel. The documentation indicates that a channels are “lightweight connections that share a single TCP connection”.
A connection to RabbitMQ is insufficient; a channel must be open to read from or write to RabbitMQ.
A RabbitMQ Exchange
RabbitMQ also has a concept called the “exchange”. An exchange is defined as a mechanism that “…take(s) a message and route(s) it into zero or more queues.”
Exchanges are essentially defined to hold queues. Queues are bound to exchanges. And exchanges are designated to behave in certain ways.
For example, exchanges can be designed to evenly distribute tasks among available consumers (a direct exchange). An exchange can also send out the same message to all workers (a fanout exchange) or send certain messages to certain members based on a pre-determined criteria (a topic exchange).
By default, an exchange doesn’t survive a restart of RabbitMQ, or the unsubscription of all workers (e.g. if all workers die or are shut down, the exchange is deleted and so is all the data inside the queue). But exchanges can be declared durable, which means they will survive until they are deleted, purged or run out of instructions for the workers to do.
One Exchange, Many Queues
In RabbitMQ, queues are part of exchanges (they’re bound to the exchange). Queues can also be marked as durable, and queues are actually what store the messages (not unlike a database table).
Publish to Exchange, Consume a Queue
The hardest thing to realize in RabbitMQ is that you don’t actually publish messages to a queue; you publish them to the exchange.
When publishing to the exchange, the exchange will use the rules it knows to route the message to the right queue. There are opportunities to create extremely complicated routings, although most often you’ll end up creating simple one exchange per queue settings.
But you do consume the queue. The consumer knows about a specific queue and consumes messages from the queue based on the queue rules (certain consumers can consume certain routing keys but not others, for example).
Installing AMQP and RabbitMQ for PHP
RabbitMQ has a great set of instructions for installing RabbitMQ from their own package distribution; this is the easiest way to get the newest RabbitMQ features. You can grab these directions in the documentation.
Once RabbitMQ is installed, you’ll need to install the AMQP PECL package. This package will need the dev headers for RabbitMQ (librabbitmq-dev). The PECL package is pretty simple to install (pecl install amqp) and the PHP documentation for the AMQP package is sparse, but complete.
Next, we’ll discuss building a publisher followed by a discussion on building consumers for RabbitMQ.
See more in the RabbitMQ documentation
RabbitMQ has great documentation. You can read more about the AMQP spec and RabbitMQ’s implementation here.