Thursday, February 3, 2011

Using Memcached in PHP in addition to a MySQL Database

I've been hearing a lot of buzz lately about NoSQL solutions. I personally don't think that relational databases will ever be obsolete. However, I do know from experience that you can dramatically improve the performance and scalability of your MySQL based web app by implementing a caching layer using Memcached.

I am going to walk you through some basic examples here.

I am assuming that you already have your caching server or servers set up, this is just going to walk through the PHP code to talk to your existing servers. If you need set up instructions check out This Link.

I usually use objects to access my database so first I am going to create an abstract class with a memcached connection method for the child classes to inherit.

abstract class MasterData
{
 
   protected $myCache; //memcache object
 
   /********************************************************
   *************** Start MasterData Methods ****************
   *********************************************************/
 
   /* Constructer. Initialize all objects */
   public function __construct() {
      // here we call our memcache creation method
      // in real life our constructor would do more 
      // than this, but this isn't real life, this is
      // my blog
      $this->createCache();
   }
 
   /* Create memcache object */
   public function createCache() {
      // load a memcache object into the myCache property
      $this->myCache = new Memcache;
      
      // CACHE_HOST and CACHE_PORT are constants that should be set
      // in your configuration file to the ip address and port of 
      // your cache server
      $this->myCache->connect(CACHE_HOST, CACHE_PORT);
   }
  
   /********************************************************
   ************** End MasterData Methods *******************
   *********************************************************/

}

Now we are going to create a child object that can extend this MasterData object.

// our fictional CommentData class that extends our MasterData class
class CommentData extends MasterData
{
   /********************************************************
   *************** Start Comment Methods *******************
   *********************************************************/
 
   /* get comment list for a post */
   public function getPostCommentList($postID) {
      // first we check to see if this data is cached.
      // we send the get method a unique key that we
      // use to save this queries data
      $cacheResult = $this->myCache->get('postcomments:'.$postID);

      // if we found a valid cached result for this, we dont have 
      // to run our query, we can just return the result
      if ($cacheResult !== FALSE) {
         return $cacheResult;
      } 
      
      // we didnt find our comment in the cache, so now we will get 
      // it from the database, this example is using Propel ORM to run
      // our query, google PHP Propel for more info
      $commentList = tblPostCommentQuery::create()
         ->filterByPostID($postID)
         ->setFormatter('PropelArrayFormatter')
         ->find();
  
      // update the cache, from now on we wont have to look in the database
      // since we are saving a valid cache result.  The parameters here are 
      // first, a unique key, second, our actual data, third, false to tell 
      // memcache not to compress the data, and last our MCEXPIRE constant is 
      // set to the expiration time in seconds up to 2592000 (30 days).
      $this->myCache->set('postcomments:'.$postID, $commentList, false, MCEXPIRE);
  
      // return the result
      return $commentList; 
   }

   /********************************************************
   ************** End Comment Methods **********************
   *********************************************************/
}

As you can probably guess, since Memcached stores information in memory and uses a single key to grab your data, it will be much more efficient than your MySQL database. Using Memcached this way allows you to retain the advantages of long term storage in a relational database, while utilizing a NoSQL layer for short term performance gains.

In other words, you can have your cake and eat it to.

No comments:

Post a Comment