- given a long url, create a shortened url (as short as possible) and redirect to original url:
https://abc.xyz/...->https://tinyUrl.com/{shortUrl}- 2 endpoints
[POST] /shorten-> shorten url[GET] /{shortUrl}-> redirect shortened url to original url (status code 301)- code 301 (to GET), 308 (use original method) (permanent redirect): browser sends subsequent requests to original url servers directly instead of shortenUrl service
- code 303 (to GET), 307 (use original method) (temporary redirect): browser keep sending subsequent requests to shortenUrl service first and redirect to original url servers
- 2 endpoints
- store in DB: {unique id, shortened url (hashed from unique id), original url}
solution
encoding (encode token to readable shortened url)
base62
- convert number to base-62 representation. if length of shortened url is 7, it produces 62^7~3.5 trillion urls
- pros:
- collision is impossible (because id is unique)
- cons:
- length of shortened url is not fixed (increasing)
- depends on unique id generator
- can guess next available shortened url
write path (write long url to shortened url/token)
random id generator solution
- stateless for scaling -> not use random id generator solution: higher of collision, and predictable due to overlapping bits
hash & collision
- use well-known hash functions like CRC32, MD5, SHA-1, … and get X first characters
- collision can be solved by append predefined string to original url and re-hash -> use bloom filter to improve performance when searching in DB
- pros:
- fixed shortened url length
- doesn’t need a unique id generator
- cannot find next available shortened url
- cons:
- may yield same prefix for urls, result in collision -> have to solve collision -> not use hash function
token range solution
-
token is generated by token service (from given token range - integer number range) and it is monotonically increasing
-
maximum range of token range depends on length of shortened url
- eg. 7-length url with base62 -> 62^7 combinations -> range is [1…62
-
the output of token service must be non-overlapping to prevent collision -> token-range service: returns range of token to token service
-
use high quorum for key-value storage -> keep strong consistency to prevent collision -> collision-free and scalable
-
find shortened url of used long url
- use bloom filter for data lookup on url shortening
- use additional data storage (inverted index) to map long url -> shortened url. this additional storage is partitioned with consistent hashing

read path (read long url from shortened url and redirect)
- use cache (cache-aside) to map shortened url to long url
- use bloom filter to reduce load on cache and data storage (filter before query cache and storage), return 404 error if bloom filter returns not found
- cache/data storage can be partitioned by shortened url (primary key) to improve availability (loader-followers pattern)
- when shortened url is required in a short time, these requests may be collapsed and a single request will be forwarded to target server

concurrency
- token service uses lock mechanism to prevent distribute same shortened url to distinct requests from key generation service (lead to collision)

- all clients send a same long url to KGS at the same time must receive same shortened url
- use message queue and group all duplicate requests (same long url?)
- use reverse proxy (collapsed forwarding)
- use distributed lock (acquired on long url) with TTL -> slight degradation of latency
