|
As more and more small-time dynamic websites are seeing increased volumes, one begins to ask: How do I scale out and yet keep costs low? While that can seem to be a very simple questions, there's a magnitude of answers. The one I'll address here is database bottlenecks.
Ultimately there is one thing that is making your website / application / whatever slow, that one item is called the bottleneck. You might have 500 things wrong, but usually you only have 1 bottleneck at a time. What happens when you build your web site/application that scales out by web service but still relies on a single database? Well memcache can really help lower the database hits by caching those results from the database and offloading those to a scalable platform. Let's take a look at how I'm doing www.cheap.net:
Simply install memcached, and memcache-php5 on your favorite *nix distro (sorry, no windows memcache)
I personally like php, so I'll be speaking in terms of php, but you can certainly take these concepts and apply them to any other language with memcache client support.
Since I develop on a windows platform, I'll use some logic to determine if I'm in production or dev and my platform:
if ((isset($_SERVER["OS"]) && $_SERVER["OS"] == 'Windows_NT') || ((isset($_ENV["OS"]) && $_ENV["OS"] == 'Windows_NT'))) { $use_memcache=FALSE; } if ($use_memcache) include("memcache-sessions.php"); //memcache sessions else include("session.php"); //standard database sessions
memcache-sessions.php:
<?php ini_set("session.save_handler", "memcache"); ini_set("session.save_path", "udp://127.0.0.1:11211?persistent=1&weight=1&timeout=1&retry_interval=15");
session_start();
$memcache = new Memcache; //set global object $memcache->addServer('127.0.0.1', 11211); //add one server, or add multiple ones.
Next I wrap all of my mysql calls into an abstraction layer:
//basic realtime query function q($q) { $ret = mysql_query($q) or die("QUERY: q($q) ERROR: ". mysql_error()); return $ret; } //Realtime query that returns all rows into a multi-dim array function qa($q) { $items=array(); $ret = mysql_query($q) or die("QUERY: ($q) ERROR: ". mysql_error()); while($a = mysql_fetch_assoc($ret)) $items[]=$a; return $items; }
// So anytime you want to use a select and pull from cache, let's run it through qc() - querycache function qc($query,$time="30"){ global $use_memcache, $memcache; if (!$use_memcache) { //echo "DEBUG qc(): $query<br>"; return qa($query); } if(stristr($query,"SELECT")) { //it's a select, let's pull from cache if available... $key = md5($query); if ($memcache->get($key)) { echo "from cache... [$key] $query<br>"; return $memcache->get($key); } else { echo "from db...[$key] $query<br>"; // let's grab from db and tuck it into the cache $result = qa($query); $memcache->set($key, $result, 0, $time); return $result; } } else die("Do not call qc with queries other than selects."); }
That's the core in a nutshell, in summary, if your website is database driven, but static information, such as a mfg website that's loaded with products and product info, you can crank up the cache expire time to a few days and once it hits cache, you can literally take the database offline and the website will continue to operate. |