Because the lack of implementations of a messaging system in PHP we at Jimdo are going to implement such a solution on our own. Some time ago I wrote another post and asked if somebody has experiences with such techniques or already designed such a beast.
You’ll find a Draft for a php-based messaging system below. We’d be glad if we get some comments from the readers. Because we’re heavily using open source we want to give something back to the community and make the message queue system open source. And, yes, if someone is planning something like this or already knows a solution, please let us know, too. We don’t wanna reinvent the wheel!
But now let’s come to the details ;-)
- Problem
- Existing Solutions
- Implementation Draft
1. The problem
When you’re building an infrastructure that is distributed all over the internet, you’ll come to a point where you can’t rely on synchronous remote calls that - for example - synchronize data on 2 servers:
a) You don’t have any failover system that resends messages if something went wrong (network outages, software failures)
b) Messages are processed over time and you have no control if something goes overloaded by too many requests
Even if you don’t have to send messages all over the Internet there are enough points of failures where something can go wrong. You want a reliable and durable system that fails gracefully and ensures the delivery of messages even after temporary outages of any machine within the system.
2. Existing solutions
In the Java world there is a standard called Java Message Service (JMS). ActiveMQ from the Apache project implements such a solution.
In theory you can connect to a JMS service with PHP using a PECL Module called SAM (Simple Asynchronous Messaging for PHP). While it sounds easy to install and use, I ran into so many problems that I gave up. First, you need to register at IBM and download “XMS - The IBM Message Service API”. After you’ve downloaded the 60MB (!) package you can compile SAM. Add the extension in our php.ini and BAM: “PHP could not startup”. At this point I got really frustrated and gave up. I wanna have something more lightweight.
But in the PHP world I didn’t find anything similar.
3. Our approach to a PHP-based message queueing system
Vocabulary:
Client: The peer that invokes a message
Client-queue: The local client que that will run as a daemon and sends the messages to the servers
Server: The peer that receives messages
3.1 Features
3.1.1 Main Architecture
The system is peer-to-peer based with no central server (and therefore no single point of failure). Every (sending/client) node has its own local queue.
The local queue will have an “angel process” that restarts the daemon if it dies.
3.1.2 Asynchronous / Durability
Messaging is never direct. On the client side (the system that wants to send some message to another peer) there will be a local queue that sends out messages to its peers (called servers). There will be an API available for your applications to put messages into the queue, but the actual message transport will be handled by a separate process.
On the server-side there will be another process that writes the received messages into its queue. This queue will be queried by YOUR application using the provided API. See code examples below.
We will have to take care that operations are atomic. If the client gets a “true”, it can be sure that the data is saved to the local queue. And if the client que gets a “true” from the transport layer it can be sure the message is in the server’s queue.
As you may have noticed already, the solution never executes your code. It’s always queried by the application that makes use of the messaging service.
(HINT: Anyways we can implement a mode on the server side that calls your code. This would be an interface with only one method like “handleMessage(MQ_Message $message)” you’ll have to implement. If your method returns true, the message will be deleted from the server-side queue, otherwise it will be kept for later handling.)
3.1.3 Scalability
Because there is no single instance that could get overloaded scalability issues shouldn’t occur. The system scales somehow horizontal.
3.1.4 Content Independence
The message content is arbitrary. You could even send movies ;-)
3.1.5 Modularity
The underlying database is switchable. We will do our POC-implementation with PDO_sqlite but switching to other PDO-drivers, maybe even text-files, DBM etc. should be possible.
Also, the transport layer should be replaceable (XML-RPC, REST, SOAP, spread, <put here what you want>).
3.1.6 Easy to setup and use
The default configuration should work out of the box with an SQLite backend. See the examples.
3.1.7 “Job done” messages
If a message is completed and processed at the “server”, it can notify the original client that the operation was successful. We’ll have to think about possible solutions because this certainly implies a 2-way-communication.
One approach could be that the sender specifies if he want’s to get an “OK - message processed” from the peer. The client que will poll the server after submitting the message and checks if the message has been set to “PROCESSED” state.
3.1.8 Priority handling
Of course, you can actually set the priority of a message so you can be sure that more important messages will by favored by the que.
3.1.9 Multicasting
It’s possible to send a message to several servers with a single command. The queue will set the state to PROCESSED if all servers notified it that the message was processed.
3.2 Code Examples
3.2.1 Client-side
Starting the queueing daemon should look like this:
/opt/MQ/daemon start
FIXME: Configuration of the Daemon
Sending a message would look like this:
$queueDriver = MQ_QueueDriver::factory('PDO', 'dsn ....');
$transport = MQ_Transport::factory('REST');
$serverOne = new MQ_Peer('http://server1.com/path/to/server');
$serverTwo = new MQ_Peer('http://server2.com/path/to/server');
$queue = new MQ_Client($queueDriver, $transport);
$queue->send($serverOne, 'this is a test message');
$queue->multicast(array($serverOne, $serverTwo), 'this is a test multicast message');
// Send with feedback
$message = $queue->send($serverOne, 'this is a test message', true);
// Wait for the feedback
while ($message->getStatus() != MQ_PROCESSED) {
sleep(1);
}
echo "Now it's processed by the peer, yieehaaa!";
3.2.2 Server-side (get something out of the queue)
Because your main application is not involved into the messaging process the only thing it has to do is to query the queue:
$queueDriver = MQ_QueueDriver::factory('PDO', 'dsn ....');
$queue = new MQ_Server($queueDriver);
// Getting the messages with an infinite-loop iterator
foreach ($queue as $message) {
echo "Sender was: " . $message->getSender();
echo "Message is: " . $message->getMessage();
// Mark the Message as processed, the client que checks if we were processed.
// So the origin has the opportunity to check if we could process the message properly.
$message->setProcessed(true);
}
3.3 Requirements
- PHP 5.2+
- certainly the Zend-Framework
4. The Name?
No name until we have a working prototype - haha.
5. Next steps
- evaluate feedback
- setup a trac, fill tickets
- begin to code
We appreciate your feedback, wishlist, improvements, criticism in the comments as the development will be started soon.
Sönke with assistance from Markus and Christian.



October 3rd, 2007 at 14:15
What about the Simple Asynchronous Messaging for PHP extension (SAM)?
Support can be added for additional messaging backends as well.
http://pecl.php.net/package/sam
October 3rd, 2007 at 14:18
Oops, missed your blurb about it :), but it’s not really that complex to get up and running. Works quite nicely I may add
October 3rd, 2007 at 14:27
Amazon SQS ?
Of course if the queued data is sensitive it may not be an option to use a third party.
http://www.amazon.com/Simple-Queue-Service-home-page/b/ref=sc_fe_l_2/102-2998428-4228157?ie=UTF8&node=13584001&no=342430011&me=A36L942TSJ2AJA
October 3rd, 2007 at 14:56
Why not use ActiveMQ with the STOMP client (which is pure PHP)?
Then you can also use BlackbirdESB and get most of what you’re looking for above, plus have an already proven good implementation of a MQ.
October 3rd, 2007 at 16:29
I must ask the same question as MSM, as we’ve been doing more research ourselves, ActiveMQ seems to be able to handle most of what we need, we just need to start a POC. We’re also looking at Amazon SQS, again the Queing system shouldn’t be complex, the application around it can be.. so speed in a queuing system is of the utmost importance.
even if we’re using sql lite, one thing we may want to add in is fault tolerance, like the sweeper process I mentioned in your first post. I’d love to work with you guys on this..
October 3rd, 2007 at 18:04
Check J-EAI - http://www.process-one.net/en/jeai/ - and RabbitMQ - http://www.rabbitmq.com/
October 3rd, 2007 at 18:28
Hi MSM and Vid,
thanks for your responses. The main reason against ActiveMQ or others is that we wanna something decentralized. Even if the network is down or the server is not reachable the sender should be able to “fire and forget” the message. I dunno if that can be acomplished with activemq and others (maybe with one activemq per peer and they all are being “replicated” / “clustered”?).
Vid, I’ll write you an e-mail, let’s see how we can work together, thanks!
October 3rd, 2007 at 18:53
J-EAI is written in Erlang and thus is “replicated” / “clustered” by default. Check it out at least even if you don’t end up using it.
October 3rd, 2007 at 21:58
Hi,
you may want to check out Spread, this is a C app, with bindings for PHP, and handles all of the above cases as well as being opensource..
http://www.spread.org/
http://pecl.php.net/package/spread
Hope that helps:)
October 4th, 2007 at 10:10
Great idea. Acctually I allways get a bit scared about long runing php process. Garbage Collection in PHP doesn’t usually work well for this use case. Altough there’s a Google SoC Project which tries to enhance the PHP GC, no idea about the success of it.
I think the database backend needs some kind of transaction suport that everything works correct.
October 4th, 2007 at 10:20
Hi Leo,
yeah that’s the reason why we want to implement an angel process that restarts the php process if something goes wrong (OOM, fatal error etc).
October 7th, 2007 at 05:43
Hey,
we’re actually using STOMP protocol. It both supports in ActiveMQ and there is native clients for most script lanuages (php,perl,ruby,etc). This protocol designed to be easy implementable in each languages. More info & the PHP client: http://stomp.codehaus.org/PHP
BTW if you’re creating a native PHP MQ server that will be a definiately very interesting service, I would like to see that, so good luck! :)
October 9th, 2007 at 15:39
It’s already been said but would strongly recommend looking at Amazon’s SQS - their API is very clever in it’s simplicity and a much better model than JMS for this IMO - others are also trying to reproduce it - http://www.rhonabwy.com/wp/2007/08/25/django-queue-service/
Some random thoughts
- JMS / ActiveMQ support a bunch of enterprise use cases that are not worth trying to reproduce in PHP, especially when there are other more convincing languages to try in - http://www.rabbitmq.com/ . By contrast an Amazon SQS-alike should be doable
- Note ActiveMQ doesn’t have to be a SPOF although it behaves like a “server” - it has ways to replicate or forward queues and it’s possible to run a “server” inside you local client Java VM, replicating messages to the real server across the network
- From my standpoint, this should be doable with Apache + mod_php + DB + HTTP. Sure clients will have to poll the network but that fact can be hidden behind an API and made to look like the server pushed.
- Multicast? I wouldn’t go about trying to implement that at some protocol level. Again if you want to do publish / subscribe, you can simulate this again in the client API.
October 24th, 2007 at 10:57
I have a similar need and came across PHPMQ project: http://sourceforge.net/projects/phpmq
It is built upon Java JMS and Mantaray
There is an Oreilly article about it here: http://www.onjava.com/pub/a/onjava/2004/10/27/php-jms.html
Anyone had any luck implementing it?
December 10th, 2007 at 08:17
\o/ Zend Framework
November 23rd, 2008 at 12:29
I’ve used Dropr to deliver 100’s of millions of messages… works very well!
Thanks to all!
August 15th, 2010 at 06:42
Do you know that this is correct time to get the home loans, which can help you.
September 2nd, 2010 at 10:42
this is right!!!!!!!!!!!!!!