This article will go over what DynamoDB is and how we use it to backup our session data. It allows us to failover from one datacenter (AWS region) to another without losing session data and logging people out of our system.
Amazon Web Services (AWS) DynamoDB
DynamoDB is a cloud NoSQL database hosted by Amazon. You simply create a table and set the read/write capacity you want and Amazon takes care of the rest. No servers to manage or scale. Pretty awesome. Actually it’s so awesome that Amazon DynamoDB is the fastest growing new service in the history of AWS.
What’s is DynamoDB good at?
- No hassle data store that is performant, scalable, and reliable.
- Quick reads/writes. You decide the performance you need and pay for that.
- Relatively cheap.
- Access data via a key.
- Store data that is in the 1-10KB range per item (you can store more but it gets expensive).
What’s does DynamoDB suck at?
- It’s not a relational database. You can’t query it with joins or complex selects.
- It’s not as fast as memcache (in our experience).
- For large items or extremely high throughput it can get expensive (compared to running your own memcache service for example).
- There is no simple way to back up your data (they do have a process by which you can get data to S3 but it’s pretty complicated and involves two other totally separate services from AWS).
Where can you read more about DynamoDB?
Using DynamoDB For Session Backup
In the blog post Scalable Session Handling in PHP Using Amazon DynamoDB they cover how to implement session handling for PHP using DynamoDB. I experimented with this, but what I found was it was too slow for our needs. Our session reads with DynamoDB were taking 20+ms. Our memcache session reads are an order of magnitude faster than that. We also already have memcache session handling implemented and working beautifully.
Why Do We Need To Backup Our Sessions?
For some applications it might be acceptable to log everyone out if you failed from one datacenter to another (heck lots of applications run in only one datacenter and don’t have any failover). Our application is mission critical for our customers – if we’re down they’re losing money. We run completely redundant setups in two different AWS regions on EC2.
If there’s a problem we have to switch customers from one datacenter to the other. Not having the sessions backed up in a way that both datacenters can access would mean everyone using our system would be logged out. This is a real hassle for our users because sometimes the stores are operating with a manager login and associates just have PINs to switch to their profile. If they get logged out they have to have the manager come by and log back in. What if the manager is out on lunch? Out of luck.
We previously stored our session backup in our MySQL database. But this became unscalable as the number of concurrent sessions grew. A few months ago we turned off our MySQL session storage and have been running just on memcache sessions. It improved performance, but it meant we might log everyone out if we had to switch datacenters.
DynamoDB To The Rescue
I looked at a number of different NoSQL type solutions for our session backup. DynamoDB made it to the top of the list because of it’s easy of management, scalability and price.
The basic concept is:
- Session are stored and read from Memcache (every page hit)
- Every 15 minutes we write the session to DynamoDB (each session stores its time since last DynamoDB write)
- If we can’t find a session in Memcache (datacenter failure, or Memcache reboot) we look for it in DynamoDB.
- Result: Users aren’t logged out if we switch datacenters or reboot Memcache.
DynamoDB PHP Code Samples
I gleaned a lot of this code from AWS blog post on PHP DynamoDB sessions.
readDynamoDB
This reads our session data out of DynamoDB when we need it. We call this from our custom session reading function (see session_set_save_handler)
function readDynamoDB($ses_id)
{
$this->initDynamoDB();
$result = '';
$response = $this->_dynamodb->get_item(
array( 'TableName' => self::DYNAMODB_TABLE,
'Key' => array('HashKeyElement' => $this->_dynamodb->attribute($ses_id)),
'ConsistentRead' => true, )
);
$node_name = 'Item';
if ($response->isOK())
{
$item = array();
// Get the data from the DynamoDB response
if ($response->body->{$node_name})
{
foreach ($response->body->{$node_name}->children() as $key => $value)
{
$item[$key] = (string) current($value);
}
}
if (isset($item['expires']) && isset($item['data']))
{
// Check the expiration date before using
if ($item['expires'] > time())
{
$result = $item['data'];
}
else
{
$this->deleteDynamoDB($ses_id);
}
}
}
return $result;
}
writeDynamoDB
This reads our session data out of DynamoDB when we need it. We call this from our custom session reading function (see session_set_save_handler)
function writeDynamoDB($ses_id,$data,$expire_minutes)
{
$this->initDynamoDB();
// Write the session data to DynamoDB
$response = $this->_dynamodb->put_item(
array( 'TableName' => self::DYNAMODB_TABLE,
'Item' => $this->_dynamodb->attributes(
array( self::DYNAMODB_HASH => $ses_id,
'expires' => time() + ($expire_minutes*60),
'data' => $data,
)
),
)
);
return $response->isOK();
}
deleteDynamoDB
This delete our session data from DynamoDB when we are done with it. We call this from our custom session destroy and gc function (see session_set_save_handler)
function deleteDynamoDB($ses_id)
{
$this->initDynamoDB();
$delete_options = array( 'TableName' => self::DYNAMODB_TABLE,
'Key' => array('HashKeyElement' => $this->_dynamodb->attribute($ses_id)),
);
// Send the delete request to DynamoDB
$response = $this->_dynamodb->delete_item($delete_options);
return $response->isOK();
}


