/shorten - input is long url, it will return new url in format: urlShortener.io/
/:hash - this will take the hash of long url and redirect user from the original requested url to the long url.
Describe the overall system architecture. Identify the main components needed to solve the problem end-to-end. Use the diagramming tool to create a block diagram.
client - sends input to app
api - retrieves data, app logic:
Write path- user sends a long url to /shorten - internally app calls hasning service which will create a hash and lookup this hash in database to check if provided long url already exists. Returns that url or create a new record with this hash and return the newly created hash.
Read path - user calls /:hash of our service the redirect service will get the long-url from database based on the hash provided and return res.redirect to the long-url.
queue - if we want to scale we can introduce later a queue that will switch our architecture into event-driven. User will then pool for the url shortener a couple of seconds I think its still not a problem to wait couple of seconds for reply to create url shortener.
database - noSql database that keeps track of what hashes we already used and what short_url/long_url is it associated with.
basically dynamoDB or any key-value database should handle the scale effortlessly.
cache - we can cache the data based on the hashed key.
load-balancer - we will use load balancer when we need to scale to more servers and event driven architecture to scale this solution.
queue - could be any queue that will accept the same input and call the hashing and database write etc in separate call no asynchronous calling. If we miss cache we first look to database and create a new record, cache will have TTL 1 hour.
database - key value dynamoDB which will have 1(O) return time even on scale. It automatically handles partitioning under the hood by adding a global indexes and sortKeys.
hashing - We will first hash the original_url with secret key on the BE side and then we take the first 6-7bytes and create a base62 decoded hash. this way we will have not guessable sequence of keys and only our server can actually decode it.
HMAC-SHA256(secret_key, original_url) → get a 256-bit (32-byte) hash.+ and /). load balancing - we will have a queue and event-driven architecture. So what we can do is to jut use a load-balancer to use 3 servers that will create the context for generation of short url and we will have workers to take care of the generation that will be subscribed to the queue.
high availability - we have a lot of small workers and scaling rules in our infrastructure provider - for example http based scaling for the message context creators and then queue message count based scaling for the generators of hash. Database is dynamoDB which is geo-replicated and has automatic sync between the regions.
low-latency - is satisfied with the horizontal scaling we have separate workers for the hash generation and load balancer to send the context input of user to the context message creators. Low latency for redirecting is simply done by more smaller workers that will return the res.redirect based on the shorten-url hash given on the /:hash route.
rate-limiter - to /:hash for 10requests per minute per IP. I think we dont have to be concern about anything more as long as the urls are public. if they are private