1. 程式人生 > >系統設計面試題 之 如何設計Pastebin.com

系統設計面試題 之 如何設計Pastebin.com

原文連結:https://github.com/donnemartin/system-design-primer/blob/master/solutions/system_design/pastebin/README.md

第一步:蒐集用例和約束
在面試過程中,我們需要向面試官詢問需求以設計用例,但是在本文中我們自己設計用例因為沒有面試官。

1.用例
本文只解決以下用例:

1)使用者輸入一個文字塊,獲得一個隨機生成的連結;
過期:
a.預設設定是不過期(譯者注:但這樣資料庫會越來越大,所以我覺得應該有一個預設的過期時間)
b.能夠可選的設定一個過期時間
2)使用者輸入一個貼上板url,就能檢視對應的內容
3)使用者可以是匿名的
4)我們需要有一個服務來跟蹤頁面的使用狀況
5)我們需要有一個服務來刪除過期的貼上板
6)我們的服務要有高可靠性

本文不解決以下用例:
1)使用者註冊一個賬號以及郵箱確認
2)使用者登入一個註冊賬號以及修改貼上板
3)使用者能設定可見性
4)使用者能設定短連結

2.約束和假設
狀態假設:

1)流量是不均勻分佈的
2)Following a short link should be fast(譯者注:沒看明白啥意思)
3)只能粘帖純文字
4)頁面使用狀況的分析不需要實時
5)1000萬用戶
6)每個月有1000萬用戶寫操作
7)每個月有1億使用者讀操作
8)讀寫比率是10:1

計算使用率
如果你被要求估計使用率的話,請和麵試官先討論。

1)每個剪貼簿的size
a.每個剪貼簿1kb的size
b.shortlink - 7位元組
c.一分鐘為單位的過期時間 - 4位元組
d.建立時間 - 5位元組
e.貼上板路徑 - 255位元組
f.總計 =~ 1.27kb
2)每個月新增12.7GB的貼上板內容
a.每個貼上板1.27kb的size乘以每個月1000萬用戶
b.3年內需要大約450GB空間
c.3年內3600萬短連結
d.假設大部分貼上板都是新建的,而不是對舊貼上板的修改
3)平均每秒4個寫操作
4)平均每秒40個讀操作

一些方便計算的提示:
1)每個月有250萬秒
2)每秒1個請求 = 每個月250萬個請求
3)每秒40個請求 = 每個月1億個請求
4)每秒400個請求 = 每個月10億個請求

第二步:本文的頂層設計如下圖

第三步:設計核心元件

1. 使用者輸入一個文字塊,獲得一個隨機生成的連結
我們可以把關係資料庫當作一個巨大的雜湊表來使用,這個雜湊表可以把生成的url對映到檔案伺服器以及貼上板檔案的路徑上。
相對於使用檔案伺服器,我們也可以使用例如Amazon S3或者NoSql document之類的面向物件儲存。
另外,我們也可以使用NoSql key-value來取代關係資料庫作為雜湊表的方法。以下討論基於關係資料的方法:
1)客戶傳送一個建立貼上板的請求給web伺服器,該web伺服器實際上是一個反向代理
2)web伺服器把請求轉發給Write API伺服器;
3)Write API伺服器做以下操作:
a.通過查詢sql資料庫檢查url是否唯一
b.如果url不唯一,就會生成另一個url
c.如果我們支援自定義url的話,那麼我們可以使用使用者提供的url
4)儲存資料到sql資料庫的pastes表
5)儲存貼上板資料到面向物件儲存
6)返回url
pastes表如下:

shortlink char(7) NOT NULL
expiration_length_in_minutes int NOT NULL
created_at datetime NOT NULL
paste_path varchar(255) NOT NULL
PRIMARY KEY(shortlink)

我們將會為shortlink和created_at建立索引以加速查詢(log-time instead of scanning the entire table)(譯者注:沒看明白這句話)並且把資料儲存在記憶體中。
為了生成唯一的url,我們可以:
1)使用md5演算法對使用者ip和時間戳計算hash:
md5是一個使用廣泛地128位雜湊演算法。md5均勻分佈。我們可以用md5演算法生成隨機url。
2)使用base62編碼hash
base62對雜湊值的編碼是確定唯一的。base62使用[a-zA-Z0-9]編碼適用於url;base64多了兩個字元+和/,所以不適用於url生成。以下是base62偽碼:

def base_encode(num, base=62):
    digits = []
    while num > 0
      remainder = modulo(num, base)
      digits.push(remainder)
      num = divide(num, base)
    digits = digits.reverse

3)我們只取輸出結果的前7個字元,這樣就有62^{^{7}}種可能的值;應該足夠處理我們三年中的3.6億個短連結:

url = base_encode(md5(ip_address+timestamp))[:URL_LENGTH]

我們還需要一個公有的REST API:

$ curl -X POST --data '{ "expiration_length_in_minutes": "60", \
    "paste_contents": "Hello World!" }' https://pastebin.com/api/v1/paste

返回結果:

{
    "shortlink": "foobar"
}

2.使用者輸入一個貼上板url,就能檢視對應的內容

1)使用者傳送一個獲取貼上板的請求給web伺服器;
2)web伺服器轉發請求給Read API伺服器;
3)Read API伺服器做以下操作:
檢查sql資料庫是否存在對應於url的資料。如果url已經存在於資料庫中的話,就從面向物件儲存中獲取貼上板的內容;否則的話,返回錯誤。
REST API:

$ curl https://pastebin.com/api/v1/paste?shortlink=foobar

響應值:

{
    "paste_contents": "Hello World"
    "created_at": "YYYY-MM-DD HH:MM:SS"
    "expiration_length_in_minutes": "60"
}

3.我們需要有一個服務來跟蹤頁面的使用狀況由於我們不需要實時分析頁面使用情況,所以我們可以簡單地使用mapreduce來分析頁面使用情況。

class HitCounts(MRJob):

    def extract_url(self, line):
        """Extract the generated url from the log line."""
        ...

    def extract_year_month(self, line):
        """Return the year and month portions of the timestamp."""
        ...

    def mapper(self, _, line):
        """Parse each log line, extract and transform relevant lines.

        Emit key value pairs of the form:

        (2016-01, url0), 1
        (2016-01, url0), 1
        (2016-01, url1), 1
        """
        url = self.extract_url(line)
        period = self.extract_year_month(line)
        yield (period, url), 1

    def reducer(self, key, values):
        """Sum values for each key.

        (2016-01, url0), 2
        (2016-01, url1), 1
        """
        yield key, sum(values)

4)我們需要有一個服務來刪除過期的貼上板

為了刪除過期的貼上板,我們可以掃描sql資料庫:只要過期時間戳比當前時間舊,我們就可以直接刪除。

第四步:擴充套件我們的設計

先找到瓶頸再解決問題。以下是我們的擴充套件設計圖。

分析資料庫可以使用例如Amazon Redshift或者Google BigQuery之類的資料倉庫。
Amazon S3之類的面向物件儲存可以輕鬆處理每個月12.7 GB的新增內容。
為了處理每秒40個讀請求(峰值可能會略高),流行內容的讀請求應該由記憶體快取來處理而非資料庫。記憶體快取在處理不均勻的流量時也很有效。 The SQL Read Replicas should be able to handle the cache misses, as long as the replicas are not bogged down with replicating writes.(譯者注:沒看明白)
平均每秒的寫操作對於 SQL Write Master-Slave是能夠應付的。
(譯者注:第四部分包含大量的連結以及面試技巧,此處不翻譯,有需要的請看原文)