Aurora Serverless – notes

 

Serverless is the trendy word of 2018 and everything is serverless or wannabe serverless. Aurora is no exception, and it is also reaching towards serverless. Aurora serverless introduced actually last Re:Invent and the preview phase lasted for half a year. Since summer it has been generally available.

Under the hood

Launching Aurora as ‘Serverless’ is no more difficult than launching Aurora to be a ‘traditional’ SQL database. Only a few clicks and Aurora serverless is ready to rock. The most interesting feature is the automatic scaling.  One can set minimum and maximum limits in terms of ACU. Minimum is 2 ACU and scaling steps includes always even amount of ACUs (2,4,6,8..so on). In addition it is possible to go full serverless in terms of scaling to allow 0 ACU if there is no traffic to the database. For budget perspective that sounds great, as the costs can be pressed down during the idle times.  For the budget calculations it is good to remember that even though the price is per ACU, there are always min 2 (or 0 if sleeping). The price for 2 ACUs is slightly greater than smallest ‘traditional’ Aurora, so if the use scenario requires cheap and always on database, maybe Aurora Serverless is not the answer.

And that leads us to the wake-up time of the sleeping database. It seems to be 25s or a bit less for the first request to get the response. Of course after that the database is fast and there is no delays between queries and responses. If that is something that cannot be live with, one can define a long idle time (24h max) before database goes to sleep and maybe some crons to keep the database awake… But Aurora Serverless documentation indicates that it might be excellent fit for development databases as there are typically no red flags for the waking-up delays.

However, it is possible to use CloudWatch Metrics for Aurora Serverless and query whether the database is sleeping or not. Then this information can be used in the application in some novel way, for example hiding the waking up phase from the user…

CLI command example:

$> aws cloudwatch get-metric-statistics --metric-name ServerlessDatabaseCapacity --start-time 2018-09-19T12:19:00Z --end-time 2018-09-19T12:20:00Z --period 60 --namespace AWS/RDS --statistics Maximum --dimensions Name=DBClusterIdentifier,Value=<name> --region <region>

Another difference between Aurora Serverless and traditional Aurora is the amount of cluster endpoints; aurora serverless has only one. There is no dedicated endpoints for writer and reader(s). That indicates automatic scaling to affect also writer instead of only to the amount of readers. However, the performance of such scaling is not yet a widely available. Furthermore, the comparison to Aurora Multi-Master would be highly interesting. Nevertheless, Aurora Serverless is highly interesting product and will be widely used as it will takes away the database scaling from the user. Administrative tasks will be somewhat relieved.

-Tero

Sharing AMI between 2 accounts

Configurate and tune an EC2 could be fun. At least once. At some point is good to have the image of the finalized EC2 at hand to make similar instances  quicker. Amazon calls images as Amazon Machine Images (AMIs). These hand-made and polished AMIs can be used conveniently for example in Launch configurations. The amount of further configuration is decreased during the autoscaling with hand-made AMIs. Even though AMIs are regional and private by default, it is possible to share those between two accounts. If the AMI is required on the other region, it have to be copied first to that region.  Nevertheless, the first step is to create the AMI.

Step 1 – Create the image

Even though it is not necessary a must to stop the instance before the image creation, it is highly recommended. At least the reboot should be allowed during the process. Quite often the image is not working due to the creation process that had not included reboot or stopped instance. After the instance is stopped, just go to Actions and select Create Image (figures 1 & 2).

 

Figure 1. Stop the instance and go to Actions

Figure 2. Create image

Step 2. – Share the image

The image creation status can be found on Images -> AMIs right after the image creation has been started. Image is actually an EBS snapshot and therefore snapshot creation status can be found on Elastic Block Storage -> Snapshots. After a few minutes the image creation status reaches available status.

Sharing the image, select Modify Image Permissions and add permission to the target AWS account id (figure 3).

Figure 3. Add permissions to the AMI

Step 3. Launch the image on the target account

Log in to the target AWS account and select Launch instance. Choose My Amis -> Shared with me and pick just shared created AMI (figure 4).  As a side note, sharing RDS snaphots is a similar & simple task and there are a lot analogues in the RDS-snapshot sharing  process between accounts.

Figure 4. Select & Launch the AMI that is Shared with me

-Tero

Aurora cluster – Writer to handle writes and Reader to handle reads

Aurora cluster is the combination of two kinds of endpoints; writer and reader. Sometimes cluster contains lots of readers. Those read replicas are handy to scale out read performance of the database. Typically, database receives lots of read requests and scarce write requests, so possibility to add new read replicas is a nice feature. As indicated, Aurora cluster contains a cluster endpoint (pointing to writer) and reader endpoint (no surprise here, it points to reader(s) ). Writer is the primary endpoint, so that is used when only one endpoint is preferred. Even though the Writer endpoint can handle both writes and reads, the fundamental idea of the utilizing reader endpoint is to route reads to Reader endpoint…

It is extremely quick to ramp up new Aurora read replicas, and as those are all behind cluster’s Reader endpoint, the utilization is fast. AWS take care of loadbalancing between them. Possibility to scale out read performance is good to have but how about scaling out writes? It has not been possible until just recently AWS announced forthcoming Aurora Multi-master and Aurora serverless -services. Those are going to be available in near future. Meanwhile we focus on read replicas and scaling out the read performance. To utilize separated Writer and Reader one must tell the application those endpoints. For Python/Django the story goes as follows.

File to be tuned: settings.py

File to be generated: dbrouters.py

Yes, only one file to be tuned and only one new file to be generated. Sounds piece of cake.

In settings.py, add new database endpoint to the database section and add an additional line to tell Django how to route database traffic: dbrouters = [path.to.dbrouters].

So settings.py should include something like (Django 2.0):

DATABASE_ROUTERS = ['myapp.dbrouters.DBRouter']
DATABASES = {
    'default': {
        'ENGINE''django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    },
    'Writer': {
        'ENGINE''django.db.backends.mysql',
        'OPTIONS': {
            'read_default_file''myapp/databaseWriter.cnf',
        },
    },
    'Reader': {
        'ENGINE''django.db.backends.mysql',
        'OPTIONS': {
            'read_default_file''myapp/databaseReader.cnf',
        },
    }
}

 

In this example myapp/databaseReader.cnf and myapp/databaseWriter.cnf -files are located in the same folder than settings.py and those contain information for databases, such as database name, endpoints, ports, and authentications. [for example syntax ->Django docs]

And dbrouters.py that is also located in the same folder as settings.py, should include something like: 

from django.conf import settings

class DBRouter(object):
    def db_for_read(self, model, **hints):
        """
        All reads are routed to Reader
        """
    return 'Reader'

    def db_for_write(self, model, **hints):
        """
        All writes are routed to Writer
        """
    return 'Writer'

    def allow_relation(self, obj1, obj2, **hints):
        “””
        Returning None means that no specific routing
        “””
    return None


    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Returning None means that no specific routing
        """

    return None


Please be aware of that in case you have used ‘.using(“<database>”)’ -notation in code, that will overwrites dbrouters.py. Therefore, all database related routings should be in dbrouters.py. One way to get rid of ‘.using(“<database>”)’, could be for example sed-command to trim the code. [something like sed -i /s<source>/<target>/g *.py ]

-Tero