This post is written by Martin Samson of The Hotel Communication Network. We love when customers post about how they use New Relic in their environment. Martin posted it on his own blog, and we asked him if we could share it with our extended audience. He said yes. Thanks Martin!
Creating a fast RESTful API using CakePHP and New Relic
In early 2012, the development team at The Hotel Communication Network set out to build a RESTful API to simplify communication between the various components of our platform. Early in the process, we began to evaluate the different options available to us: Ruby on Rails, CakePHP, Django, Lithium and ExpressJS.
We had the following requirements:
* Rapid development
* Unit tested
* Wrap the database with a safe interface (CRUD)
* Be compatible with multiple languages
The application started as a simple CRUD interface to be completed with a two week deadline. All frameworks were up to the task, albeit CakePHP was well known by all of us.
Reasons we chose CakePHP:
* We already use 1.x extensively.
* Our database was already compatible.
* The IRC channel is vibrant.
* It’s easy to understand.
We started development in late March 2012. None of us had any experience with the new version of the framework; as it was just released. Once all the entities were defined, we built the API from the outside in by defining how resources should be accessed, modified and created. A lot of time was saved because our database already followed CakePHP’s naming conventions; the bake tool was used to generate the models and their test skeletons; the validation rules, routes and controllers quickly followed.
CakePHP has matured quite nicely, associations are now lazy-loaded. Object loading greatly improved, you can easily apply “Objects on Rails” principles. Most of the logic was moved from models to distinct objects resulting in slim controllers and not-so-fat models, with clean business objects. It allowed our models to handle only data concerns (validation and persistence) thus giving us faster unit tests. CakePHP’s move to PHPUnit made for better tests and reports.
Our app, code named Butterfly, quickly grew from a simple CRUD application to the core of our platform. Most business logic was consolidated, eliminating code duplication.
Finally, all the REST routes were manually specified to give us more flexibility and control.
Tips when using CakePHP:
* Use model validation for everything. Really. Use it to verify a related entity’s existence.
* Use components to wrap repetitive controller logic such as GET parameter parsing.
* Separate concerns between models and business objects. CakePHP 2.x allows loading any classes with App::uses(). See Objects on Rails by Avdi Grimm
* Use the whitelist when saving data. (See RoR / GitHub mass assignment security problem.)
* Write unit tests! We have over 300 tests and thousands of assertions.
* Use simple views combined with the RequestHandler. Our API is only accepting and serving JSON, but we could easily add XML.
Running Butterfly on Apache 2.2 + mod_php seemed fast on our development machines although it quickly crumbled in our staging environment. At that point, we really didn’t know what was wrong and why responses were getting slower and slower. We were blind.
Enter New Relic
New Relic is a real-time monitoring service built to help you squeeze performance out of your applications. We heard lots of good things about them from a newly employed engineer and Shopify’s Tweets.
The whole process of signing up, installing the PHP module and getting a t-shirt took less than 10 minutes on FreeBSD! We were blown away once we viewed the dashboard: it automatically detected the framework and produced useful, near real-time graphs. From slowest controller to detailed database queries, we could drill down to a specific section of the system to determine what needed be optimized. A great feature is the ability to backtrace from any SQL query to its callers.
To our surprise, CakePHP’s built-in authentication with ACL was the slowest part of the application, due to joining in the aro/aco/users tables. We also discovered one of our applications was not caching properly, requesting object schemas on each call.
NGINX + PHP-FPM is being marketed as a really fast alternative forapache + mod_php. The metrics allowed us to compare NGINX to Apache, within our environment. Switching to it resulted in a 100% speed increase!
New Relic enabled us to optimize early in the development process, gave us visibility and the metrics to back changes. We are now entering the production phase and New Relic will help us keep track of improvements, enabling us to deliver a better end-user experience.