Let’s say you have a relatively simple software architecture:
If you’re just trying to get your product up and running, this can all be done on a single machine or EC2 instance.
Time passes and you’re starting to get some traction, you’ve got your friends and family using the service, and you realize that you need to put in some caching layers and maybe use a NoSQL store for some of your data. At this point, the logical infrastructure might have evolved to this:
Again, this is just the logical architecture – some of these services may still be doubled up on instances – for example, memcached might be running directly on your app servers, or you might be using nginx with proxy_buffering for both web cache and web server.
Now, let’s get into the physical. Let’s assume you’ve already assigned every logical function to a separate instance or group of instances, so each one of the blue boxes in the above diagram corresponds to a group of instances. Now the trick is to be able to modify those groups quickly, while automatically taking care of any interdependencies. For example, if you want to add an app server, your steps might be:
- spin up the server
- confirm that the server is up and running
- confirm that the current version of the app is deployed on the new server
- add the app server to all required configurations on the web cache and web servers
- set up monitoring on the new app server.
Being able to have this happen quickly, automatically, and reliably is no small task, and this is one of the main reasons DevOps staff are in such high demand lately.
The earlier in your product lifecycle you start thinking about scalability, the faster you can react to increased usage.