Christian Burger
Aug 20 · 4 min read
Photo by Hans Vivek on Unsplash

Session handling is one of the first aspects to consider when designing web applications to run in multi-server, load-balanced, high availability environments.

The problem

As soon as an application has multiple instances running simultaneously (as is the case for applications behind load balancers), the state of the sessions created need to be managed between all the instances. While the client (the browser) remains constant during every request, the responding server may differ for every request. However, the browser expects its session to be honoured during every single request.

A simple use case that illustrates the problem is user login sessions… Once a user is authenticated and a session is established by Server 1, the user’s session will go missing for any subsequent requests passed to Server 2 and 3 in the cluster. Thus resulting in prompts to sign in again.

The fact that sessions are stored on disk poses a problem in this scenario as each server’s sessions files are siloed and inaccessible to the other servers in the cluster.

The same problem occurs when a session is changed, only one server will be aware of that and the session will be out of date on all the other servers.

Sticky sessions

One solution to this problem is called “Sticky sessions”. With this approach, a load balancer will remember a user’s server and keep directing the user’s requests back to the same server.

However, the problem with this approach is when a server suddenly becomes unavailable to the cluster. All users “assigned” to it will immediately lose their session data and will have to start a new session to continue, i.e. sign in again.

This could be especially costly in shopping applications, as the user’s basket will be lost and will have to add all his/her items again.

Shared sessions

The better approach would be one where all active sessions are accessible by all servers in the cluster. There are various tools that could provide this, i.e. Redis, Memcache, MySQL, NFS, etc. But the one we’ll discuss today is DynamoDB.

DynamoDB is one of the simplest ways to set up and maintain a shared session store. Especially for small teams already on AWS and looking to keep infrastructure and maintenance as simple as possible…

With DynamoDB, one could have a highly available session store up running in minutes. It’s serverless so virtually zero maintenance is required to keep it running and it is highly scalable.

Getting set up

We need to create a DynamoDB table. The required structure is very simple with just a partition key of ‘id’ needed.

Note: For production environments, it’s important to use the AWS Management Console to create the table. This is to ensure that the correct billing and throughput settings are selected.

Tip: to make DynamoDB handle the garbage collection for you, simply set your table’s TTL attribute to ‘expires’.

For dev environments using a local instance of the DynamoDB engine, the following script should create the table for you (assuming DynamoDB is running on your localhost on port 8000):

use Aws\DynamoDb;$client = new DynamoDb\DynamoDbClient([
'version' => '2012-08-10',
'region' => 'eu-west-1',
'credentials' => [
'key' => 'test',
'secret' => 'test',
],
'endpoint' => 'http://localhost:8000'
]);
$client->createTable([
'TableName' => 'My-Sessions-Table',
'AttributeDefinitions' => [
[
'AttributeName' => 'id',
'AttributeType' => 'S',
],
],
'KeySchema' => [
[
'AttributeName' => 'id',
'KeyType' => 'HASH',
],
],
'ProvisionedThroughput' => [
'ReadCapacityUnits' => 1,
'WriteCapacityUnits' => 1,
]
]);

Allowing the session handler access to the table requires the following IAM permissions:

{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"dynamodb:GetItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem",
"dynamodb:Scan",
"dynamodb:BatchWriteItem"
],
"Effect": "Allow",
"Resource": "arn:aws:dynamodb:<region>:<account-id>:table/<table-name>"
}
]
}

Implementation

Now that we have a table for our session store, all that’s left to do is implement the session handler in our application.

For vanilla PHP projects

We need to pull in the AWS SDK into our project. We can do this using the composer package provided by AWS:

composer require aws/aws-sdk-php

The AWS SDK makes it super easy to register the session handler, below is an example:

use Aws\DynamoDb;$client = new DynamoDb\DynamoDbClient($config['aws']);$handler = DynamoDb\SessionHandler::fromClient($client, [
'table_name' => 'My-Sessions-Table',
'hash_key' => 'id',
'session_lifetime' => 86400, // 24 hours
]);
$handler->register();session_start();

The above needs to be part of our application’s bootstrap and should be executed before the session is started.

Once the session handler is registered, we can assign session variables as we normally would:

$_SESSION['name'] = 'Jack Sparrow';

Now when you perform a scan on your table, you should see one record corresponding to the session you have just initiated.

For Laravel 5 projects

In Laravel 5.8 it was announced that a DynamoDB session driver is baked into the framework itself, so there are no additional libraries that need to be added to your project and implementation should simply entail a few tweaks to your .env file.

For implementations running Laravel versions prior to 5.8, one can use the AWS SDK Laravel package provided by AWS and create your session provider as proposed here.

Alternatively, the Jam package conveniently provides a ready to ship Laravel session provider.

composer require fivesqrd/jam-laravel

Fine-tuning and best practices

For more config options and fine tuning see the AWS PHP SDK documentation.

Wrapping up

In a nutshell, the solution proposed here offers a highly available, scalable and centralised store for session data that allows multiple instances of a web application running simultaneously from multiple servers access to realtime session data.

Five Words

High availability for PHP and Laravel

Christian Burger

Written by

Maker @ fivesqrd.com

Five Words

High availability for PHP and Laravel

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade