Category Archives: Development

Memcache Access From PostgreSQL

A big part of my job is to spend time figuring out how new technologies work, build on it, and then figure out new and inventive ways of merging it into new and existing systems- so I spent a lot of time “playing” around with stuff.

One thing I recently threw together, was some simple stored procedures for PostgreSQL, to give us built-in access to our memcached cluster, using the PL/PERL procedural language, and the Cache::Memcached module. None of this is rocket science, but might be useful for somebody out there that is looking to implement something similar.

First off, you need to build PostgreSQL with PERL support, and create the plperlu (un-trusted) language in our database; you need to use the “un-trusted” language, as we need to “use” the Cache::Memcached module;

postgres=# create language plperlu ;
CREATE LANGUAGE

Then you need to install the Cache::Memcached PERL module; I’ll assume you know how to do that; you can either install it through CPAN, or get it from the cpan.org site.

You also need at least one instance of memcached running somewhere; it doesn’t have to be on your local network, it just needs to be accessible by your database.

Then create the following procedures; I’ve only listed the “set” and “get” procedures, but you could easily follow the Cache::Memcached module man page, and create a “replace” and “delete” (and any other) procedures you needed.

So first the “set” procedure:

create or replace function memcache_set(_key text, _value bytea) returns int as $$

        use Cache::Memcached;

        my ($_key, $_value) = @_;

        $m = new Cache::Memcached {
                'debug'	=> 0
        };

        my @list = ("127.0.0.1:9996", "127.0.0.1:9997");
        my $servers = \@list;

        $m->set_servers($servers);
        $m->enable_compress(0);

        if ($m->set($_key, $_value))
        {
                return 0;
        } else
        {
                return 1;
        }

$$ language plperlu;

And then a “get” procedure:

create or replace function memcache_get(_key text) returns bytea as $$

        use Cache::Memcached;       

        my ($_key) = @_;

        $m = new Cache::Memcached {
                'debug'	=> 0
        };

	my @list = ("127.0.0.1:9996", "127.0.0.1:9997");
        my $servers = \@list;       

        $m->set_servers($servers);
        $m->enable_compress(0);

        my $val = $m->get($_key);
        if (defined($val))
        {
                return $val;
        } else
        {
                return undef;
        }

$$ language plperlu;

Now, in this case, I used a list of two different servers, both running on localhost, one on port 9996 and the other on port 9997; these servers could be anywhere, and you could only list one- but a really important thing to remember: if you do list more than one server, make sure you always list it in the same order, between all your procedures and all applications that may use this same data.

memcached calculates which server to store the data on, based on the order of this list; so you’ll get un-expected results if you list these servers differently between your applications.

A Simple Test

Now that you have the functions defined, you can use them to do some really interesting caching, directly from your database. Starting off with a simple test:

postgres=# select memcache_set('foo', 'bar');
 memcache_set 
---------------
               0
(1 row)

Then do a “get” to retrieve the data

postgres=# select memcache_get('foo');
 memcache_get
---------------
 bar
(1 row)

Database Session Handler

Now, lets say you had a database-backed session handler for your website; say maybe a PHP site, using something like this, which simply uses the PHP session_set_save_handler() method. Assume a simple session table like this:

create table sessions (
	session_id char(32) not null,
	data bytea not null default ''
);

“session_id” is the PHP session id (an MD5 string in this case), and “data” is the serialized contents of the PHP session.

Then add two rules- one for insert and one for update; this triggers the new memcache_set() procedure, so that new session data is always pushed out to your memcached servers

create rule session_insert_rule as on insert to sessions
	do also select memcache_set(NEW.session_id::text, NEW.data);

create rule session_update_rule as on update to sessions
	do also select memcache_set(NEW.session_id::text, NEW.data);

Testing this is simple:

postgres=# insert into sessions values ('5cc27b0285c9d2e6dc4125456d308548', 
     'This would be the session data');
INSERT 0 1

postgres=# select memcache_get('5cc27b0285c9d2e6dc4125456d308548');
              memcache_get
--------------------------------
 This would be the session data
(1 row)

And then subsequent updates

postgres=# update sessions set data = 'This is the new data' where
   session_id = '5cc27b0285c9d2e6dc4125456d308548';
UPDATE 1

postgres=# select memcache_get('5cc27b0285c9d2e6dc4125456d308548');
   memcache_get
-------------------
 This is the new data
(1 row)

Now just make your PHP session handler (or whatever) checks memcached first, before selecting from the sessions table; if you build it right, and set your expiration times correctly, you should be able to build a system that (almost) *never* reads this data from the database, as the data is always available from memcached.

VoicePHP by TringMe

TringMe, an Indian start-up just released its new VoicePHP service, which allows you to develop voice applications using PHP.

This is definitely cool stuff, though I see quite a few issues with implementation. HTTP, is, by design, a non-persistent transaction, and a phone call requires persistency while the call is in progress; therefore, there is no way for PHP alone, to handle “Voice” requests.

The only way to really make this work, is to have an external server (effectively a PBX of some kind) that handles the call traffic, that is simply polled (in some fashion) by PHP on a per request basis. Those requests could be polled via Ajax, or even a comet-like system, but it’s still not handled directly via PHP. I assume this is where their VoicePHP “Server” comes in.

So, in this sense, it sounds simply like a PHP wrapper around the TringMe REST API, which is something that can already be done in other ways, like accessing the Asterisk Manager interface via PHP using asterisk-php-api, but with one interesting twist-

It looks like (according to their FAQ) you can access the audio streams directly from PHP- which is pretty interesting, depending on how they’ve implemented it. Given the (generally) short transaction lengths of an HTTP request, I’m not sure how you would realistically pull audio from a real-time source (like a phone call), or play-back an audio clip on to a call, unless you used some sort of scheduling system.

ie- use PHP to decode and audio file (say .wav or .mp3), and then send the file to the VoicePHP server, which schedules the audio clip for playback, and returned immediately. It’s then played over the call in “real-time”. PHP could then poll the VoicePHP server to get status about the playback.

I’ve signed up for a beta account to play around with it, hopefully I’ll see something from them soon.

memcached (and facebook)

I’m really impressed that so many big companies, like facebook and google, have taken the time to release patches and source code, back out to the open-source community. Being able to improve memcached throughput from 50,000 requests/s to 200,000 requests/s is an amazing achievement.

The changes that the facebook guys have made to memcache are going to help a lot of people out there, including fonolo. We’re using memcache heavily in-house, not only for web-based caching, but for a lot of the back-end VoIP and speech recognition applications.

We, obviously, don’t require the throughput that facebook does- given they just recently released data that showed they were adding more than 600,000 new users per day, more than 70% of which are coming from outside the USA. That’s growth at a staggering rate!

I have to say, that I’m a fan of facebook, and what they’ve managed to achieve, in a relatively short amount of time- I just have to wonder how long it will all last? Increasing your user-base by 600,000 users per-day; where is the plateau? Will it all eventually just topple over on itself?

Imagine when the next big social networking app comes out; will there be a mass-exodus from one to the other? or will facebook be so far in-grained in it’s users, that they won’t have any other choice but to stay?

No matter what happens,  it’s nice to know facebook is working out all the bugs for us.

Net::fonolo 1.3 Released

I justed released the latest and greatest version of Net::fonolo, a PERL module for accessing the fonolo.com developer program.

This release was pretty basic; just added support for the new API method company_list(), which returns a list of all the companies in the fonolo database, either by page, or by a date (so you can do incremental updates of a local cache).

If you’re interested in signing up for the fonolo developer program, click here.

The Net::fonolo module is available on CPAN , or here:

[download#2]

Worst Browser Ever

Even Microsoft doesn’t want you to use Internet Explorer; 

There was a pretty severe bug found, that apparently affects all versions on IE (even the yet-to-be-released IE8 was affected)- what’s even more surprising to me, is that so many people are still using IE6. I guess it’s simply because it came with XP, and because of the enormous flop of Vista, there’s probably even more people using XP than pre-vista-gate.

I’ve been using Chrome as my primary browser ever since (almost) it came out; it has quite a few bugs in it,  and the bookmarks support is terrible, but it’s fast and light- and doesn’t seem to eat memory like Firefox likes to (for no apparent reason.)

… if only the google guys would get on a plug-ins system of some kind- I hate having to switch back to firefox all the time for firebug.

But seriously- IE6? with all the CSS and Javascript “issues”? and not being able to render transparent gradients properly?

Maybe this exploit and all the press it’s getting is really a blessing is disguise for all us developers out there; maybe this will force a large percentage of the IE6 users over to the “other” pile.