Tiny URL - System Design Interview Question (URL shortener)

TechPrep
6 Feb 202409:38

Summary

TLDRThe video covers the TinyURL system design interview question, exploring a robust approach to solving it. The key focus is on creating a short URL from a long URL and redirecting users back to the original URL. The speaker explains API design, schema, scalability concerns, and the use of tools like Zookeeper for distributed synchronization. It also touches on caching strategies, database considerations, and optional features like analytics, rate limiting, and security enhancements. The video emphasizes scalability and performance, aiming to address typical interviewer expectations in such design challenges.

Takeaways

  • 😀 The Tiny URL system requires both functional (URL shortening and redirection) and non-functional requirements (low latency, high availability).
  • 📊 A simple REST API with a POST endpoint for URL creation and a GET endpoint for redirection is proposed.
  • 🔢 Key decisions involve determining the length of the short URL based on expected scale, like 1,000 URLs per second, leading to 31 billion URLs annually.
  • 🧮 By using a character set of 62 (a-z, A-Z, 0-9), a seven-character URL can handle up to 3.5 trillion URLs, making it scalable enough for large applications.
  • 🌐 A naive approach would involve a load balancer distributing requests to web servers, fetching long URLs from a database and caching them for scalability.
  • ⚠️ To avoid the single point of failure and collision issues with a caching system, a distributed Zookeeper is introduced to manage URL ranges assigned to web servers.
  • 🛠️ Web servers request unique ranges from Zookeeper, ensuring that even if one web server fails, it won’t result in URL collisions.
  • 🗄️ Database choices include SQL (Postgres with sharding) or NoSQL (Cassandra) based on trade-offs, with distributed caching like Redis or Memcached to reduce load.
  • 📈 Analytics, like counting URL hits and storing IP addresses, can optimize performance and provide location-based cache distribution.
  • 🔐 Security concerns include adding random suffixes to URLs to prevent predictability, with a trade-off between URL length and security.

Q & A

  • What are the functional requirements of the Tiny URL system design?

    -The functional requirements are to create a short URL when provided with a long URL and to redirect the user to the long URL when given the short URL.

  • What are the non-functional requirements for the system?

    -The non-functional requirements include very low latency and high availability.

  • Why is the API design important in this system, and what endpoints are proposed?

    -API design is crucial because it defines how the system will interact with users. The system proposes two endpoints: a POST endpoint to create a short URL and a GET endpoint to redirect users to the long URL.

  • What is the purpose of choosing a short URL length, and how is it determined?

    -The short URL length is determined based on the scale of the application. The system needs to handle billions of URLs, so using a seven-character string is ideal, allowing for 3.5 trillion unique combinations.

  • How does the system handle scalability issues in the proposed design?

    -Scalability is addressed by horizontally scaling both web servers and cache systems, using a range allocation technique through Zookeeper to prevent collisions between web servers.

  • What role does Zookeeper play in the system, and how does it help prevent collisions?

    -Zookeeper provides distributed synchronization by assigning each web server a unique range of values for URL generation. This prevents collisions by ensuring no two web servers generate the same short URL.

  • What are the potential drawbacks of using Zookeeper, and how can they be mitigated?

    -One drawback is that if a web server dies after obtaining a range, that range of URLs will be lost. However, given the 3.5 trillion possible combinations, losing a few million URLs is not critical. Additionally, running multiple Zookeeper instances can prevent it from being a single point of failure.

  • Why might a NoSQL database like Cassandra be better suited for this system?

    -Cassandra is better suited due to its ability to handle large-scale data, and it supports horizontal scaling which fits the high read/write demands of this URL shortening system.

  • How does the system optimize performance using caching?

    -The system uses a distributed cache like Redis or Memcached to store frequently accessed short URLs, reducing the load on the database and improving response times.

  • What additional features or enhancements could be considered for the system?

    -Additional features include analytics (tracking popular URLs), IP address logging for optimization, rate limiting to prevent DDoS attacks, and security measures such as adding a random suffix to short URLs to avoid predictability.

Outlines

00:00

🔧 Introduction to TinyURL System Design

This paragraph introduces the TinyURL system design interview question. It highlights that this is one of many possible solutions but emphasizes that the approach is robust, addressing common concerns. The problem is broken down into two main functional requirements: creating a short URL from a long URL and redirecting a short URL to the long one. Non-functional requirements like low latency and high availability are also essential, along with scalability, which interviewers expect candidates to explore deeply. The speaker starts with the design of a simple REST API, involving a POST endpoint to create the URL and a GET endpoint to handle redirection.

05:01

📊 Handling Scalability with Character Sets and URL Length

Here, the speaker begins addressing scalability, particularly in terms of the number of URLs the system must handle over time. Assuming a scale of 1,000 URLs per second, they estimate the system would need to handle over 31 billion URLs annually. The speaker discusses the character sets that can be used for short URLs, including lowercase and uppercase letters (a-z, A-Z) and digits (0-9), providing 62 characters in total. They then calculate how many unique combinations can be created with different numbers of characters, ultimately concluding that a seven-character URL would suffice to handle trillions of URLs over many years.

⚙️ High-Level System Design and Scaling Solutions

The paragraph outlines a simple high-level system architecture where a load balancer distributes requests to web servers that interact with a database to retrieve long URLs and redirect users. However, this approach won't scale well for billions of URLs. A caching mechanism is introduced to optimize URL generation, but the issue of having a single point of failure with the cache is raised. Horizontally scaling both web servers and the cache helps address this, but new problems such as collisions arise when multiple servers generate the same short URL simultaneously.

🛠 Improving Scalability with Zookeeper and Range Technique

This paragraph introduces a more advanced solution to solve scalability and collision issues by replacing the cache with Zookeeper. Zookeeper assigns ranges of values to web servers for URL generation, ensuring unique short URLs are created by servers operating within different ranges. If a server fails, the range of URLs it was working on will be lost, but since the system generates billions of URLs, losing some values is not a major concern. To prevent Zookeeper from becoming a single point of failure, multiple instances can be deployed, though it handles relatively few requests compared to the previous caching solution.

📚 Database Choices and Distributed Caching

In this section, the focus shifts to database scaling. The speaker discusses using either a traditional SQL database with sharding, like PostgreSQL, or a NoSQL database like Cassandra, which is better suited for large-scale applications. A distributed cache like Memcached or Redis could also be implemented to reduce database load, particularly for frequently requested URLs. The web server can first check the cache before querying the database, optimizing the system's performance under heavy traffic.

📬 Request Flow and URL Creation Process

This paragraph walks through the end-to-end flow of a post request for creating a URL. The request hits a load balancer, is routed to a web server, and the server interacts with Zookeeper to get a range of numbers. A base-62 encoded short URL is generated from this range, stored in the database (and possibly the cache), and finally returned to the user. For GET requests, the web server first checks the cache for the short URL, and if not found, retrieves it from the database before redirecting the user to the long URL.

📈 Additional Considerations: Analytics, Rate Limiting, and Security

In this concluding section, the speaker touches on extra features that may be required, such as analytics for tracking URL usage and improving caching by identifying popular URLs. Other enhancements include adding rate limiting to prevent Denial of Service (DoS) attacks and securing the URL generation process by introducing random suffixes to avoid sequential prediction. The trade-off between URL length and security is also briefly mentioned, as interviewers might expect deeper exploration into balancing these aspects.

Mindmap

Keywords

💡Tiny URL

Tiny URL refers to the system that shortens long URLs into shorter, more manageable URLs. This is the central concept of the video, where the process of creating these short URLs and then redirecting users to the original long URLs is discussed. The system's design revolves around maintaining scalability and availability while efficiently shortening URLs.

💡Functional Requirements

Functional requirements refer to what the system must do—namely, creating short URLs from long URLs and redirecting users from short URLs to long URLs. These requirements form the basic functionality the Tiny URL system needs to meet.

💡Non-functional Requirements

Non-functional requirements are performance-based aspects of the system, such as low latency and high availability. These are critical for ensuring that the Tiny URL system can handle a large number of requests quickly and without failure, especially under high demand or traffic.

💡API Design

API Design involves creating endpoints for interacting with the Tiny URL system. In this video, a REST API is proposed with two endpoints: one to create short URLs using a POST request, and another to redirect users to the long URL using a GET request. This simplifies interaction between users and the system.

💡Scalability

Scalability refers to the system's ability to handle an increasing number of requests and data over time. The video emphasizes the importance of scalability in the Tiny URL system, especially when anticipating millions or even billions of URLs being created yearly, requiring careful consideration of storage and retrieval.

💡Zookeeper

Zookeeper is a centralized service that manages configurations and provides distributed synchronization in the system. In the video, Zookeeper is introduced to allocate unique ranges of numbers to different web servers, preventing collisions in short URL creation and allowing for horizontal scaling of the system.

💡Base 62 Encoding

Base 62 encoding is the method of encoding numbers into a set of 62 characters (a-z, A-Z, and 0-9) to create short URLs. This encoding ensures that the generated short URLs are compact while still supporting a large number of unique URLs, which is important for handling billions of short URLs as mentioned in the video.

💡Distributed Cache

A distributed cache, such as Memcached or Redis, is a system used to store frequently accessed data in memory, reducing the load on the main database. In the Tiny URL system, it’s used to store the most popular URLs, allowing faster access for users and helping improve system performance by offloading database queries.

💡Collision

Collision refers to a scenario where two web servers generate the same short URL, which is problematic as each URL should be unique. In the video, this issue is addressed by allocating unique ranges of numbers to each web server using Zookeeper, preventing collisions during the URL creation process.

💡Rate Limiting

Rate limiting is a technique to control the number of requests a user or service can make to a system. In the Tiny URL system, rate limiting could prevent Denial of Service (DoS) attacks or abuse by restricting the number of requests that can be made in a given timeframe, ensuring the system remains operational under heavy load.

Highlights

Introduction of Tiny URL system design, emphasizing that there are multiple ways to approach the problem, but this solution is robust and covers key concerns for interviewers.

Functional requirements include creating a short URL from a long URL and redirecting from the short URL to the long URL.

Non-functional requirements highlight the need for low latency and high availability.

API design consists of a simple REST API with two endpoints: POST for creating a short URL and GET for redirecting the user to the long URL.

Schema design includes fields like long URL, short URL, and created timestamp, with potential for additional fields later on.

To determine the length of the short URL, the scale of the application must be considered (e.g., 1,000 URLs per second would require handling 31 billion URLs annually).

The short URL character set is made up of 62 characters (a-z, A-Z, 0-9), which provides 3.5 trillion unique combinations with 7-character URLs.

Simple system architecture includes a load balancer, web servers, and a database, with initial caching to reduce load, but issues like single points of failure must be addressed.

Introduction of horizontally scaling the web servers and cache to avoid single points of failure, though this introduces potential collision issues.

Solution to collision problem involves using a Zookeeper for distributed synchronization, allocating unique ranges of URL values to each web server.

Zookeeper manages URL ranges to avoid collisions, though web servers that crash may waste some ranges, which is acceptable due to the large available character space.

NoSQL databases like Cassandra are suggested for their ability to handle high-scale read/write demands, potentially coupled with caching mechanisms like Redis or Memcached.

A sample workflow includes a POST request generating a short URL, storing it in the database, and possibly caching it, while GET requests check the cache first before querying the database.

Discussion of analytics, including tracking the number of hits per short URL and IP addresses for regional optimization and reduced latency.

Additional considerations include rate-limiting to prevent DoS attacks and security measures like randomizing URLs to make them harder to predict.

Transcripts

play00:00

okay so today we're going to be solving

play00:02

the tiny URL system design interview

play00:05

question uh and before we start I just

play00:07

think it's important to note that this

play00:08

is one way of solving the interview

play00:09

question there's many other ways but I

play00:11

think this is a really robust way of

play00:13

solving the problem that addresses the

play00:14

main concerns that many interviewers

play00:16

would be looking to be solved so with

play00:18

that said let's jump straight into it so

play00:20

for the functional requirements it's

play00:21

really simple when we're given a long

play00:23

URL we have to create a short URL and

play00:25

then when we're given a short URL we

play00:27

have to redirect the user to the long

play00:29

URL and for the non-functional

play00:30

requirements we're going to require very

play00:32

low latency and very high availability

play00:34

so it's a really simple concept but

play00:36

there are some nice areas where you can

play00:37

go super deep on the scalability issues

play00:39

which many interviewers will expect you

play00:41

to to really know so starting off I

play00:43

always like to look at the API design so

play00:45

for this I think a simple rest API will

play00:47

do so we'll have one endpoint which will

play00:48

be the the post endpoint which will be

play00:50

the create URL and here the parameters

play00:53

will take a long URL and then once we've

play00:55

created the short URL we can just simply

play00:56

return with a status code of 2011

play00:58

indicating that that's being created and

play01:00

then we'll have a second endpoint which

play01:02

will be the get endpoint uh where in the

play01:04

URL we provided with the short URL and

play01:06

then what we'll do is we will then

play01:08

redirect the user we'll do a 3 hour1

play01:10

permanent redirect for the user to the

play01:12

uh previously provided long URL so super

play01:14

simple rest API here then for the schema

play01:17

again really simple we'll have a long

play01:19

URL which will be a string a short URL

play01:20

which will be a string and then a creat

play01:22

that which would be a time stamp but we

play01:24

could also add additional Fields here

play01:25

which I'll touch on later on so the

play01:27

first key question we have to ask the

play01:29

interor is how long should the URL be

play01:31

and to to answer that we kind of need to

play01:33

know what what is the scale of the

play01:35

application so let's say for example the

play01:37

interviewer said okay it's required that

play01:39

the application can create 1,000 URLs

play01:41

per second so then we know that every

play01:44

year so if we multiply 1,000 time 60

play01:46

seconds time 60 Minutes time 24 hours

play01:48

time 365 days that we're going to be

play01:51

required to have roughly 3.5 billion or

play01:54

31 billion URLs created each year and

play01:57

then if we anticipate a kind of r right

play02:00

request ratio of 10:1 that means we're

play02:02

going to be doing roughly 300 billion

play02:04

reads per year so again it kind of is

play02:06

something to keep in mind when thinking

play02:08

about the kind of uh scalability of this

play02:10

application so then the next question

play02:12

then is well what characters can we use

play02:14

and so typically most interviewers and

play02:16

it's fairly safe to assume that we'll

play02:17

we'll be able to use a to z lowercase A

play02:19

to Z uppercase and 0 to9 and that means

play02:22

then we'll have a total of 62 characters

play02:24

to use so then with that information we

play02:27

can then look at how many unique short

play02:29

your can be created so if we've got one

play02:32

character if we put that to the power of

play02:34

62 that means we'll have 62 unique

play02:36

combinations which makes sense because

play02:37

there's only you know 62 characters to

play02:39

choose from uh and then similarly two to

play02:42

the pirate so we've used uh two

play02:43

characters then we've got two to power

play02:45

62 which is

play02:47

3,800 and so if we skip on down to six

play02:49

to the power of 62 so for six characters

play02:51

we've got 56 billion and then for 7even

play02:54

we've got uh seven characters we've got

play02:55

3.5 trillion and so if you look here if

play02:58

we've got you know if we're going to be

play02:59

expected to generate you know 31.5

play03:01

billion URLs each year if we look over

play03:03

the span of 10 years well that's maybe

play03:05

300 billion and so you can see here well

play03:07

56 billion won't kind of you know it's

play03:10

kind of it won't be enough but you know

play03:11

seven characters at 3.5 trillion will be

play03:13

so that's why we're going to go with

play03:15

seven characters okay so now that we

play03:17

have all the information we need from

play03:18

the interviewer we can kind of start

play03:19

putting together a really simple

play03:21

highlevel um system design so here we've

play03:24

got a user makes a request to load

play03:25

balancer that will then distribute it to

play03:27

a web server and the web server will

play03:29

then uh get the information it needs

play03:31

from the database and then redirect uh

play03:33

the user to the to the long URL so while

play03:36

this technically Works obviously you

play03:38

know it's not going to be able to handle

play03:39

the scale that we've previously talked

play03:41

about so the first naive solution could

play03:42

be able uh could be to introduce a c

play03:45

cach which means that every time a web

play03:47

server is given a long URL it goes to

play03:50

the campcash and it asks for a number

play03:52

the campcash will then return a number a

play03:55

base 10 number and the web server will

play03:57

then convert that into a base 62 which

play03:58

will then be used as the short Euro and

play04:01

so while this technically Works we've

play04:02

introduced a single point of failure

play04:03

here with the campcash which is

play04:05

something we never want to do and so

play04:06

we've kind of got to come up with a uh a

play04:08

more nuanced

play04:10

solution so here what we've done is

play04:12

we've hor horizontally scaled both the

play04:14

web servers and the Countach so that

play04:15

we've got multiple instances of each so

play04:17

that we can handle if certain nodes go

play04:20

down however now we've introduced a new

play04:22

problem so let's say for instance one of

play04:24

the web servers makes a request to the

play04:26

campcash and it gives back a value of 10

play04:28

and then simultaneously another web

play04:29

server makes a request to the count cash

play04:31

and it also uh gives a value of 10 well

play04:35

then now we've got a collision and this

play04:37

is something that we cannot have in our

play04:38

system we want it to be kind of uh

play04:40

highly available so what we're going to

play04:42

do now is we're going to move it on to

play04:43

the next level okay so looking at this

play04:45

next iteration what we're going to

play04:47

introduce now is we're going to get rid

play04:48

of our camp cach and we're going to

play04:50

introduce a zookeeper and so Z zookeeper

play04:52

is really good uh to be used as a kind

play04:55

of centralized service for maintaining

play04:57

you know configuration information and

play04:58

kind of providing distributed

play05:01

synchronization and so we're going to

play05:02

use a range technique here so what will

play05:04

happen is each web server will reach out

play05:06

to the Zookeeper and the Zookeeper will

play05:08

give it a range of values from which it

play05:10

can create URLs and so for instance the

play05:12

first web server might come over and

play05:14

it'll give it the range of zero to 1

play05:16

million and the next range will then be

play05:18

1 million to two uh 1 million one to 2

play05:20

million so what this means is that each

play05:22

server will be creating uh unique short

play05:24

URLs as they're all operating in

play05:26

different ranges and so when a a new web

play05:29

server comes on it'll reach out to the

play05:30

Zookeeper and it will then ask okay what

play05:32

ranges can I have and it'll give it a

play05:34

new range and then similarly when a web

play05:37

server completes its range it will then

play05:38

reach out to zookeeper which will then

play05:39

provide it a new unused range and then

play05:43

you may be asking well okay well what if

play05:44

a web server reaches out to zookeeper

play05:47

it's given a range but then it instantly

play05:48

dies well what that happens with that is

play05:50

that range will no longer be used and

play05:52

that those 1 million values will never

play05:53

be used so we've kind of wasted a

play05:55

million values but again because we

play05:57

chose seven characters um we've got you

play06:00

know 3.5 trillion so losing a million

play06:02

here and there actually isn't that much

play06:04

of a problem at all but you could also

play06:06

say that the Zookeeper is also a single

play06:07

point of failure so what we could do is

play06:09

we could have multiple instances of it

play06:11

um and you have to remember that the

play06:13

Zookeeper does not get that many uh read

play06:15

requests because you know unlike the

play06:17

count cach which every single time a web

play06:20

server wanted a number it went to it the

play06:21

web servers only go here to get its

play06:23

range of values and then unless it

play06:25

finishes the range it will not come back

play06:27

to thato keer service so this is a

play06:28

really rub solution that kind of scales

play06:31

really well the next step we can do then

play06:33

is to scale our databases so again here

play06:36

we can look at the classic you know SQL

play06:38

nosql asset based tradeoff so you know

play06:40

you could make an argument we could use

play06:43

uh you know an SQL database like

play06:44

postgress and then use sharding to

play06:45

handle the scale but I think you know

play06:47

maybe a slightly better approach might

play06:49

be to go with maybe column orientated

play06:50

database like Cassandra which could you

play06:52

know really handle the scale that that

play06:54

we're dealing with here so typically I'd

play06:56

go with a nosql kind of Cassandra

play06:58

approach here and then to kind of reduce

play07:00

the load even more on the database I'd

play07:01

also use maybe a distributed cache like

play07:03

mcash or reddis uh and here I'd store

play07:06

maybe the most popular short URL so that

play07:08

the web servers would first check the

play07:09

the cache uh to kind of reduce the load

play07:12

on the databases as well so if we walk

play07:14

through an example so let's say we've

play07:15

got a post request so we're going to

play07:16

send a post request to the create URL

play07:18

endpoint that'll come to the load

play07:20

balancer which will then distribute it

play07:21

to the web servers one of the web

play07:23

servers will then if it doesn't have a

play07:25

range it'll go to the Zookeeper and get

play07:27

its range and then it will generate the

play07:28

short your Ur L uh from that number

play07:31

using the B 62

play07:32

encoding The Next Step then will be to

play07:35

save the long URL and short URL in the

play07:37

data base uh and it could also store it

play07:39

in the distributed cache depending on

play07:40

what the you know caching logic is for

play07:42

the application uh and then finally the

play07:44

web server will just respond to the user

play07:46

with the uh the newly created short

play07:49

URL and then for the get request what

play07:51

will happen is a get request will come

play07:53

in with the short URL uh in the actual

play07:55

URL itself uh the web server will first

play07:58

check the cache uh and see if it's in

play08:00

there if it's not in there well then it

play08:01

will retrieve it from the the long URL

play08:04

from the database and then it will

play08:06

simply uh redirect the user to the long

play08:08

URL so really simple but again it's this

play08:11

kind of scalability uh issue that you

play08:13

know uh interviewers are really expect

play08:15

you to to go deeper and then finally

play08:17

there's there may be some additional

play08:18

talking points which you may or may not

play08:20

be required to know so one of them may

play08:22

be analytics so what we could do is we

play08:24

could also maybe maintain counts for

play08:26

each of the URLs to determine you know

play08:28

which short URLs are most popular and

play08:31

then cach them and this kind of again

play08:32

can help us with the short the hotkey

play08:34

problem like uh like that Twitter has

play08:37

and then similar we also can store maybe

play08:39

IP address information to get location

play08:41

info which can help us determine where

play08:43

to locate our caches to just again

play08:45

reduce that latency and improve the

play08:46

overall

play08:48

performance we can also introduce rate

play08:50

limiting and so this can help prevent

play08:51

against dos attacks whereby users try

play08:53

and flood our servers with request to

play08:55

kind of uh try and make them fail and so

play08:57

rate limiting could be an interesting

play08:58

talking point there uh and then finally

play09:01

there's you know security consideration

play09:02

so you know if you look at our uh range

play09:05

Theory we are sequentially in

play09:08

incrementing and so therefore

play09:09

potentially we might want to add a

play09:11

random suffix to the short URL to

play09:13

prevent hackers being able to predict

play09:14

URLs but then it we'll be making a

play09:16

trade-off between the length of the URL

play09:18

uh and you know the predictability so

play09:21

that trade-off between length and

play09:22

security is maybe a good talking point

play09:24

uh that you can have with the

play09:26

interviewer so this is just one way of

play09:27

solving the problem if you got any other

play09:29

ways definitely leave a comment below be

play09:30

very interested to see you know how

play09:32

other people solve it uh and look if you

play09:34

liked it please like And subscribe it

play09:35

helps the channel out a lot and I'll see

play09:37

you in the next one

Rate This

5.0 / 5 (0 votes)

Etiquetas Relacionadas
System DesignTinyURLScalabilityAPI DesignDatabase ChoicesCachingZookeeperDistributed SystemsNoSQLTech Interview
¿Necesitas un resumen en inglés?