Creation: Convert a full URL to a short URL.
Redirection: Be able to redirect the browser to the full URL.
Scailability: Around 10,000 URL shortenings per second at peak times.
Performance: The redirection time should be around 100ms.
Availability: The service should have high availability, at around 99.99%.
Reliability: We will have redundant connections at each level to make sure our clients stay online
Each full URL should be about 100 characters which is 200 bytes. 200 bytes is .2 KB. .2 KB * 10,000 URL's is around 2 MB. Lets go up and say 5 MB max per second our system should be able to handle
/createURL: {
id: unique id,
user_id: the id of the user,
short_URL: the shortening of the URL (the id will be part of the suffix),
full_URL: the entire URL,
Index: we will index by the id
},
/redirect: {
short_URL: the shortening of the URL
}
NOSQL database
This will be a Key Value store.
id: unique id,
user_id: the id of the user,
short_URL: the shortening of the URL (the id will be part of the suffix),
full_URL: the entire URL,
Index: we will index by the id
We will have a creation service and a redirection service. The creation service with create the short url and store it in the database.
The redirection service will be responsible for redirecting traffic from the browser
The client goes to the URL where the creation service lives. The Load balancer routes the client to the appropriate creation service. The creation service is responsible for creating the short url. The Creation service communicates with the database to store the information before it returns back to the user.
The client goes to the URL with the short URL. The browser communicates with the load balancer. The Load balancer routes the traffic to the appropriate redirection service. The redirection service communicates with the appropriate cache. If the cache has the key it returns the full url otherwise it gets it from the database , stores it, and then sends it back to the browser.
Both databases are replicas. One is a master and the other is the slave. We do this to ensure we repsect Atomicity and isolation...we do not want both the databases to write to the same object concurrently. We use a NOSQL database since their is no type of extensive relationship in our application. This allows us to be highly efficient and scalable.
We use two caches for redundancy purposes. Each entry in the cache has a property called Time To Live. We set this property to twelve hours to ensure that our data doesn't go stale, but at the same time serves our purpose of speeding up our application. Because of the cache our latency is 50% less and creates a better client experience, this is partly because querying from the database can be expensive. If the data does not live in the cache it communicates with the databases to save the latest information before it returns it to the client.
We're not adding a cache between the creation service and the database since there isn't really anything to cache.
We're not using a service like zoo keeper since it is expensive.
We chose NOSQL over SQL because there isn't much relational data.
Since we don't have a monitoring service, if an issue arrises we could have a harder time finding and fixing issues.
Adding a message queue between the creation service and the database could be good a good improvement.
Adding a monitoring service could be useful for debugging difficult issues.