One of the things that I think PHP developers do not do well is asynchronous processing. PHP developers have written reams of applications that do all their calculations up front and over-and-over again for multiple requests. Or they will just write their code to work linearly, regardless of the scalability implications. In this chapter I wrote a simple example showing how you can do some asynchronous processing. It is a basic example that I use and there is a LOT more I could have talked about, and perhaps I should have. But this example will get you started thinking about how to architect your application so that you can greatly increase the scalability of your application.
Chapter 1: Networking and Sockets
Chapter 2: Binary Protocols
Chapter 3: Character Encoding
Chapter 4: Streams
Chapter 5: SPL
Chapter 6: Asynchronous Operations with Some Encryption Thrown In
Chapter 7: Structured File Access
Chapter 8: Daemons
Chapter 9: Debugging, Profiling, and Good Development
Chapter 10: Preparing for Success
Asynchronous Operations with some Encryption thrown in
One of the primary ways if increasing the ability of your website to scale is that of asynchronous operations. Modern web applications have a lot of logic to execute for each request and the effect of this is often slow requests. However, web requests are intended to be snappy. This is partially due to the demands of users but also because web sites need to be able to serve up content to large numbers of people on a moment’s notice.
The problem of asynchronous operations is going to have a different solution depending on the type of application that is being written. However, what we’re going to do is look at an example of how you could implement this in your application. I would not suggest that you take this code and throw it into a production environment, but at the same time, the concepts that we demonstrate here are quite pertinent to what you may need in a production environment.
We are going to use an example that uses a combination of different applications. The example application that we’re going to build is a simple credit card processor. This is probably the most common need for asynchronous operations that I have seen. It may not be the most interesting example, but it probably is the most pertinent. Also, because of the whole credit aspect we need to throw encryption in. When you first read the title to this chapter you may have thought “how in the world are these two related?” Well, credit card processing is why. We could have done something like search to show an example, but some other company beat me to it.
Another question you may have is “why is this even a problem? Couldn’t you just handle this in the web server?” The answer is “yes, you could.” But there is a caveat to that. The caveat is “if you are not concerned with scalability or high load.” For the most efficient use of a front end web server you do not want to have it sitting idle waiting for PHP to handle the response to come back from the credit card processor. One of the reasons for this is that if you have a high number of transactions you can actually run out of spare processes to serve other requests. Without having some kind of asynchronous processing going on, your front end web servers could be overloaded while being completely idle if someone put in a Luhn-validated, but inactive, credit card number. This would be a very easy to implement denial of service attack. But by offloading any long-running functionality to a backend queuing mechanism, the front end can remain snappy while any load is managed in the back end.
This brings us to what our architecture will look like. It will be relatively simple. Our front end will be the Apache/PHP instance that you know and love. The backend credit card handler will be running Zend Server’s Job Queue. The Job Queue is a feature in Zend Server 5.0 and above that allows you to run jobs asynchronously from the front end. We could write our daemon for this example, but we will cover daemons in another chapter. Here we just need something that already works.
The way this works is that a form is submitted from the browser. This form should contain all of the information needed to do a valid credit card transaction. For processing the credit card transaction we are going to be using Authorize.net. Why? Because it came up first in a Google search and doesn’t require you to have an actual merchant account to test its API.
The web browser, once it has the HTML, will make an Ajax request not to the web server, but to the message queue. Feel free to use any message queue that you want. However, it should support some kind of HTTP request. However, what we’re going to do is build a very small queue proxy whose only purpose will be to broker requests from the back end job queue to the front end listener. It will not have durability or any of the other features that a typical message queue would have. There are other message queue software packages available, but they tend to be a little difficult to set up for the simple demonstration we’re going to have here. But if you end up using the methods described here I would recommend taking a look at some of the message queues that are already available. Many of them already have HTTP-based messaging available.
Getting the web page to properly display the data from the message queue is actually a bit of a pain due to the browser-domain, so-called security features. This is especially if you just want a simple example that could possibly be re-used. It’s quite do-able, as you can see, but because of the security restrictions in the browser you may need some patience. The message queue’s HTTP API is the reason for this and it’s not because of HTTP, but because of your browser. It doesn’t matter if you are on the same IP address with a different port or on a sub domain, your browser is going to complain about cross-domain permissions issues.