Accumulate evidence

Wednesday, September 1, 2010

Apache Spawn Mayhem

Anyone with a cellphone and a neuron could write a PHP framework.  I took my shot at taming the beast at my third professional PHP job.  I cooked up the ORM, scaffold generator, DB objects, caching, templates, validation, authentication modules, MVC, and helper libraries from scratch.  The Model and the Controller were pretty straight forward (<tableName>Model::get, <tableName>Model::getListBy<property>), but the View was atrocious.  This setup was fine since the View was being handled by Flex which communicated to the servers via AMF.  (I had since adapted to Zend's style of View handling for the framework later on)  It was super lightweight.  Initial tests involved sustaining a thousand connections that barely consumed 20% of the servers 8GB memory while returning results in ~300ms.  All in all, the designers were happy with it because they could go into the ModelAPIs (extended from the Model) and write their own custom methods very easily:

public function getPacmanGraphicByUserId() {
  $result = array();
  $user = loginManager::getUser();
  $graphics = contentModel::getListByUserId($user->user_id);
  foreach($graphics as $graphic) {
    if($graphic->type == contentModel::GRAPHIC_TYPE_PACMAN) {
      $result[] = $graphic;
    }
  }
  return $result;
}
Note: Does anyone know how to add a code formatting block for BlogSpot?

The design was heavily influenced by my experience with Symfony.  I thought Symfony was robust and adaptive but overly verbose, especially at the Model layer.  I emphasized making sure that the PHP naming conventions were easy enough for any programmer to read.  While my code generators could whip up a fully-functional administration panel, it wasn't complex enough to reflect the business logic.  My inability to address the problem with the Views layer proved politically venomous when additional PHP coders came into create reports, graphs, and tools.  They rightfully complained about the clunky View implementation that damn-near got the entire Framework replaced.  The Flex guys, on the other hand, found their interaction with the framework easy.

Apache spawns feel left out
of the childhood obesity craze.

The site was an asset-heavy Flex social network site.  It was graphically stunning, but it turned web requests into hordes of Viking marauders who drank the bandwidth of their enemies.  Every time a person came to the site, they downloaded all 12 glorious megabytes of the SWF.  The SWF would make about 30-60 web requests to display the contents of the landing area.  Browsing through pictures unleashed about 200 web requests per page of thumbnails.  Needless to say, the discipline of maintaining asynchronous atomicity was forcing our web heads to file restraining orders against us.  Apache tapped into its Irish heritage and dumped out spawns at an alarming rate.  A constant slush of new users downloading the SWF and established users dumping web requests put the average Apache spawn size at around 12MB.  Worse off, Apache's caching mechanisms were out of the question since all server requests were funneled through a single PHP gateway script that constantly put out dynamic data.  It was getting ugly.

I was delving a little bit into Flex at the time and really wrapped by head around the bubble/target/capture method of handling events.  PHP and its mighty serial processing swag couldn't swing such a concept, but I still did my best to emulate event handling.  The simple act of defining new event(); (which was extendible) would register the event in a central eventManager queue.  I wrapped the MVC phase transitions in a while loop that would only be true if the eventManager queue has events pending.  Additionally, between each MVC phase, I would check the eventManager queue to see if there were pending events.  One such event was the NavEvent.  If a NavEvent was discovered, I would flush the output buffer and continue the loop form the top, essentially rebooting the framework without having to restart everything.  This way, a page redirect would not make another request to the server and would have the added benefit of using the current PHP instance with all of its includes, classes, and connections already in memory.  If a chain of ten NavEvents managed to sneak through, the whole loop broke off, returning a 500 error and emailing a dump/trace detailing everything.

I had found some fundamental code in the framework performing header redirects.  I replaced them all with new NavEvents($uri) calls and, viola, server load dumped dramatically!  I'm not sure if this approach would be good everywhere since the URI in the browser does not change to reflect that a redirect has occurred, but maybe someone somewhere likes that.  (Rule 34?)

All of my engineering smarts were put into a pine box when I walked in one day and all of the furniture, cubicles, and hardware was packed up and shipped out of state.  It was the beginning of the Great Recession and the investor's wife had divorced him.  Convenient timing.  It's very hard to show off your talents at subsequent job interviews when the place you put a year and a half into suddenly ceases to exist.  Such is the life of chasing start-ups...

No comments:

Post a Comment