user1954544
user1954544

Reputation: 1687

Continuous deployment and db migration

This question is like " What was first, chicken or egg?".

Let's imagine we have some source code. Written using symfony or yii. It has db migration code that hadle some database changes.

Now, we have some commits that updates our code (for example new classes) and some db changes (change old columns or add new tables).

When we developing at localhost or update our dev servers it's ok to have time to stop services\any actions and update server. But when we tries to do it on production server we will crash everything for a while and this is not an option.

Why this will happen - when we pull it (git\mercurial) our code will be updated, but NOT database, and when code will be executed - it will throw exceptions of database. To fix it we should run build-in framework migrations. So in the end our server will be crashed until migrations will be called.

Code and migrations should be updated "in one time".

What is the best practice to handle it?

ADDED: Solution like "run pull then run migrations in one call" - not an option in highload project. Because on highload even in second some entries\calls can be borken.

Stop server we cannot too.

Upvotes: 3

Views: 1543

Answers (2)

dbrumann
dbrumann

Reputation: 17166

Pulling off a zero downtime deployment can be a bit tricky and there are many ways to achieve this.

As for the database it is recommended to do changes in a backwards compatible fashion. So for example adding a nullable column or new table will not affect your existing code base and can be done safely. So if you want to add a new non-nullable column you would do it in 3 steps:

  1. Add new column as nullable
  2. Populate with data to make sure there are no null-values
  3. Make the column NOT NULL

You will need a new deployment for 1 & 3 at the very least. When modifying a column it's pretty much the same, you create a new column, transfer the data over, release the code that uses the new column (optionally with the old column as fallback) and then remove the old column (plus fallback code) in a 3rd deployment.

This way you make sure that your database changes will not cause a downtime in your existing application. This takes great care and obviously requires you to have a good deployment pipeline allowing for fast releases. If it takes hours to get a release out this method will not be fun.

You could copy the database (or even the whole system), do a migration and then switch to that instance, but in most applications this is not feasible because it will make it a pain to keep both instances in sync between deployments. I cannot recommend investing too much time in that, but I might be biased from my experience.

When it comes to switching the current version of your code with a newer one you have multiple options. The fancy cloud based solutions like kubernetes make this kind of easy. You create a second cluster with your new version and then slowly route traffic from the old cluster to the new one. If you have a single server it is quite common to deploy a new release to a separate folder, do all the management tasks like warming caches and then when the release is ready to be used you switch a symlink to the newest release. Both methods require meticulous planning and tweaking if you really want them to be zero downtime. There are all kinds of thing that can cause issues like a shared cache being accidentally cleared to sessions not being transferred over correctly to the new release. Whenever something that's stored in a session changes you have to take a similar approach as with the database and basically slow move the state over to the new one while running the code or having a fallback to still handle the old data otherwise you might get errors when reading the session, causing 500 pages for your customers.

They key to deploy with as few outages and glitches as possible is good monitoring of the systems and the application to see where things go wrong during a deployment to make it more stable over time.

Upvotes: 4

Eddy0007
Eddy0007

Reputation: 11

You can create a backup server with content that mirrors your current server. Then do some error detection. If an error is detected on your primary server, update your DNS record to divert your traffic to your secondary server. Once primary back up and running, traffic moves back to primary and then sync the changes in your secondary. These are called failover servers.

Upvotes: 1

Related Questions