System design: TinyURL + PasteBin

Bear熊
4 min readApr 2, 2024

--

主要是這個人的影片 Jordan has no life

1: TinyURL + PasteBin | Systems Design Interview Questions With Ex-Google SWE (youtube.com)

針對這個議題來寫一下心得。

總之要設計一個 tinyURL + PasteBin

URL hash 方式設計

因為題目要求 1 trillion = 1,000,000,000,000 只要用 a-z0–9 -> 36⁸ 次方 所以 8 個位元可以代表

然後 因為是隨機,如果隨機到碰撞之後,可以直接使用類似 取下一位

例如 aaaaaaaa 碰撞 → aaaaaab 直到找到可以塞入的部分為止

為了增進寫進的效率,我們可以用 multi-leader/leaderless replication 嗎?

不行,有可能因為某個人同時碰撞,並且她本來的 url 網址被更改,就算我們發現這件事情。提醒使用者,而且因為網址通常都會貼上,那些被貼上的網址很難一一更改。(e.g. 貼到簡報上或是發送短網址給他人

同理,快取也是,不能用 write back,因為兩邊可能不知道是誰寫入 (write conflict)

Partion by hash ID

因為我們 url 已經被hash過一次了,所以分布應該是相對平均的,所以不用太擔心某個 shard 資料量特別多。consistent hash

網址寫入衝突如何解決

  1. Predicate locks 總之就是兩個人都寫看看,失敗那個人會,退回來再加一 (store procegure 可以避免兩次query
  2. materlizing conflict,總之就是類似把所有的 id 都寫進去然後設定 NULL 之類的,這樣就可以保證大家拿的時候,會是有LOCK。(因為本來沒有這個機制的話,你不能對一個空的東西拿LOCK)

影片提到兩個方法都可以解決,應該是採用方法 1

INDEX 結構選擇

  1. hash index 使用過多的memory 應該不可能採用。(hash index 必須要把所有的 key 存進 memory 裡面)
  2. LSM Tree → 寫入快,讀取慢
  3. B-Tree → 寫入慢 讀取快

Database選擇 → MYSQL

  1. Single leader replication
  2. Partition
  3. B-Tree Based

可以減少 loading 藉由 Replicas + multiple partitions

如果 replica 裡面沒有資料,可以考慮去 master 詢問,可是這樣有可能 overloading master,因為有人可能亂打 id。

cache 機制

  1. write back 剛剛提到過,不可能,有可能會有 conflict
  2. write through 有機會,可是可能會降低速度。因為需要讓 cache/db consisten 會有點麻煩
  3. write around,等 read cache miss,並且去 db 拿之後,再寫進 cache 並且用 LRU 機制來過期他

Click 數量 儲存🖱️🖱️🖱️🖱️🖱️🖱️🖱️

如果用 naive situation 會有 race condition 的狀況存在。

Stream Processing

  • In memory message broker → super fast , not durable
  • Log message borker → kafka (Write Ahead Log 讓他寫很快) , rabbitMQ

Conusumer Choose

  1. HDFS + Spark → Batch job to aggregate, click may be to infrequent。太慢不選擇 (不即時的意思
  2. Flink → Processes each event individualy, may send too many writes to the database.
  3. Spark Streaming → processes events in configurable mini-batch size

如何 確認 Idempontcy

可以在 count 後面加一個 id, e.g. url_id, original_url, count, Idempontcy_key

然後想像應該可以寫類似說

update xxx = xxx + 10 whree url_id = 'a' and Idempontcy_key != 'xxx'

但是這個帶來另外一個問題是。

Q: 如果有多個 worker 怎麼辦?!

A: 只要確認每一個 url 只會被同一個 worker 處理到就行了 (partitioning kafka queu by short url_id) 這樣可以確保 在處理某一個 url_id 的時候,都是同一個 worekr (意義上就是只有一個 worker)

總之用以上的解法,就可以解決 race condition 的問題 + 不用 two phase commit (例如 grab lock)

--

--