Scoping the problem well, asking clarifying questions, make high-level design question such as:
- What are the use cases?
- What is the goal?
- What does success look like in this system?
- What are the constraints?
- It’s important to have fast reads, fast writes, or both?
- Reliability
- Redundant
- Stable
- Security
- Availability 100 up-time?
- Simplicity vs Complexity
- Maintainability
- Consistency, or eventual consistency
Keep in mind the Cap Theorem.
Once the Component that we needed came up from the previous answers,
- Be wisely at the moment to choose the component, like WebServer, Load balancer, these could introduce a single point of failure into your application.
For Mobile system design, it is important to think about:
- Offline access
- Caching
- Page refresh happens if, for example, a page needs to be refresh after another page updates the information.
- Important to optimize round-trips.
How to scale web servers? -> Load Balancers
- You can use one or multiple load balancers in parallel.
- You could configure the way that load balancer by custom scripts or use a well know algorithms like Round Robin or least load.
- Another way to manual load balance is by Application level, like app.myapp.com / email.myapp.com, web.myapp.com, or chest.myapp.com, db.myapp.com. Just split the application by features. In this way, you could balance manually each feature for a group of servers.
These are a kind of strategy that you could use to distribute the load of a web server.
How to scale database? -> Caching
So now that we have some ideas on how to scale web servers, you will need to think about the next bottleneck, which is…. Database!
One of the first things we could use is to Cache the DB results adding an extra caching layer between the servers and the database:
You could use an in-memory cache or just save it on disk. For instance, Redis allows saving the cache values from memory into the disk (Disk is far slower than in-memory). There are two basic approaches to follow: Write-back vs write-through caching?.
Another way to scale the database is vertically and horizontally, for more detail, please take a look here.
How to prepare our assets to deliver faster across the world? -> CDNs
The CDN is pretty well for delivering assets (js, png, mpeg4, etc) really fast because generally will be delivered closer to the user.
There are two basic strategies of CDNs, PULL or PUSH.
PULL Strategy:
In this technique, the user hits the CDN URL, the CDN server checks if the server's near server has the asset; if not, the near server will hit your server to load the asset and then save it in their cache. So next time, your server will not be requested, and it will be used the asset cached in the near server.
PUSH Strategy:
In this technique the files are upload into the CDN Server instead, so the very first request will be faster, but it will cost more because you will need to pay for the storage uploaded.
A common technique is to use custom domains like cdn.myapp/
or image.myapp
when you deal with CDN. What you will need to do is set you are CDN.myapp
to hit your CDN provider. At the moment to pay for an SSL certificate, you could pay for *.myapp
it to be ready to deal with different subdomains, to avoid CORS problems, and also act as a manual balancer to your requests.
Update content in your CDN
A common technique to update your content in your CDN is to append a query parameter to your asset to version it, like for example:
cnd.myapp.com/scripts/app.js?version=1
in this case, as soon you need to update your files, you could increase the version of your asset.
Also, you could want to use an automated auto versioning approach, is up to you which approach to use it.
API design tips
What are the communication patterns between client and backend?
There are different strategies and approaches, the client could be a web browser, and IOS, or Andriod. And these clients could be communicated to your web server backend.
The goal of the APIs is to make as much as clean & simple as possible to be simple to understand for everybody. A simple common way is making CRUDs.
Here you have a set of best practice designs about Rest API.
Also, you need to think about your I/O, like how you pass your parameter into your APIs. Remember to use always a key for secure authentication, a really common mechanism is using JWT tokens.
Another consideration is to decide if our application will be Client Driver or Server Driver. For instance, if our APP it’s a very important UX or care performance needs, the apps become more responsive. But the limitation with that is you will need to duplicate logic code for each future native app you needed it. For instance, in case that you need to port to Android, or IOs, etc. Also, another limitation is for Mobile App, generally, you may want a Server Driver application because in mobile our memory and CPU resources are really limited.
Another consideration how do we want to split our requests, for instance, we could do a single big request which asks the server and takes several milliseconds/seconds or do we want to split that giant request into multiple small, to do a progressive loading.