<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          系統(tǒng)設(shè)計(jì)實(shí)踐 (01) - 短鏈服務(wù)

          共 7776字,需瀏覽 16分鐘

           ·

          2021-09-13 00:03

          前言

          系統(tǒng)設(shè)計(jì)實(shí)踐篇的文章將會(huì)根據(jù)系統(tǒng)設(shè)計(jì)面試的萬(wàn)金油[1]為前置模板,講解數(shù)十個(gè)常見(jiàn)系統(tǒng)的設(shè)計(jì)思路。

          設(shè)計(jì)目標(biāo)

          設(shè)計(jì)一個(gè)像TinyURL[2]這樣的URL縮短服務(wù)。該服務(wù)將提供一個(gè)較短的URL,重定向到原本長(zhǎng)的URL。

          一. 為什么我們需要URL短鏈

          URL 縮短用于為長(zhǎng) URL 創(chuàng)建更短的別名。我們稱(chēng)這些縮短的別名為短鏈接。當(dāng)用戶點(diǎn)擊這些短鏈接時(shí),它們會(huì)被重定向到原始URL。短鏈接在展示、打印、發(fā)送或發(fā)推時(shí)可以節(jié)省大量空間,而且便于用戶手動(dòng)輸入。

          例如,如果我們通過(guò) TinyURL 縮短這個(gè) URL

          https://www.educative.io/collection/page/5668639101419520/5649050225344512/5668600916475904/916475904

          可以得到:

          http://tinyurl.com/jlg8zpc

          縮短后的網(wǎng)址幾乎是實(shí)際網(wǎng)址的三分之一大小。

          URL 縮短用于優(yōu)化跨設(shè)備的鏈接,跟蹤單個(gè)鏈接以分析受眾和活動(dòng)表現(xiàn),并隱藏關(guān)聯(lián)的原始 URL。

          如果您以前沒(méi)有使用過(guò)tinyurl.com,請(qǐng)嘗試創(chuàng)建一個(gè)新的短網(wǎng)址,并花一些時(shí)間瀏覽他們提供的各種服務(wù)選項(xiàng),對(duì)你理解有很大幫助。

          二. 系統(tǒng)的需求與目標(biāo)

          你應(yīng)該在面試一開(kāi)始就明確需求。一定要問(wèn)問(wèn)題,找出面試官腦海中系統(tǒng)的確切范圍。

          我們的網(wǎng)址縮短系統(tǒng)應(yīng)該滿足以下要求:

          功能性需求:

          ?給定一個(gè)URL,我們的服務(wù)應(yīng)該生成一個(gè)更短且唯一的別名。?當(dāng)用戶訪問(wèn)一個(gè)短鏈接時(shí),我們的服務(wù)應(yīng)該將他們重定向到原始鏈接。?用戶應(yīng)該能夠選擇一個(gè)自定義的短鏈接為他們的URL。?鏈接將在標(biāo)準(zhǔn)的默認(rèn)時(shí)間間隔之后過(guò)期。用戶應(yīng)該能夠指定過(guò)期時(shí)間。

          非功能性需求:

          ?系統(tǒng)應(yīng)該是高度可用的。這是必須的,因?yàn)槿绻覀兊姆?wù)停止,所有的URL重定向?qū)㈤_(kāi)始失敗。?URL重定向應(yīng)該實(shí)時(shí)發(fā)生,延遲最小。?縮短的鏈接不應(yīng)該是可猜測(cè)的(不可預(yù)測(cè)的)。

          擴(kuò)展性需求:

          ?分析: 例如,發(fā)生了多少次重定向??我們的服務(wù)也應(yīng)該可以通過(guò) REST API 被其他服務(wù)訪問(wèn)。

          三. 容量估算與約束

          短鏈系統(tǒng)從請(qǐng)求讀寫(xiě)量上來(lái)說(shuō),屬于是讀取量很大的。與縮短一個(gè)URL相比,訪問(wèn)短鏈將會(huì)有大量的重定向請(qǐng)求。可以假設(shè)讀和寫(xiě)的比率是100:1。

          流量估算

          假設(shè)我們每個(gè)月有 500M 的新 URL 縮短,讀/寫(xiě)比為 100:1,我們可以預(yù)期在同一時(shí)期有 50B 的重定向。

          100 * 500M => 50B

          我們系統(tǒng)的每秒查詢(QPS)是多少?

          500 million / (30 days * 24 hours * 3600 seconds) = ~200 URLs/s

          考慮到 100:1 的讀/寫(xiě)比率,每秒 URL 重定向?qū)⑹牵?/p>

          100 * 200 URLs/s = 20K/s

          存儲(chǔ)估計(jì)

          假設(shè)我們將每個(gè)URL目標(biāo)鏈接(以及相關(guān)的縮短鏈接)存儲(chǔ)5年。因?yàn)槲覀冾A(yù)計(jì)每個(gè)月有5億個(gè)新url,所以我們預(yù)計(jì)存儲(chǔ)的對(duì)象總數(shù)將達(dá)到300億個(gè)

          500 million * 5 years * 12 months = 30 billion

          讓我們假設(shè)每個(gè)存儲(chǔ)對(duì)象大約為500字節(jié)(這只是一個(gè)粗略的估計(jì),我們稍后將深入研究),我們總共需要15TB的存儲(chǔ)空間。

          帶寬估計(jì)

          對(duì)于寫(xiě)請(qǐng)求,由于我們預(yù)計(jì)每秒有200個(gè)新url,所以我們服務(wù)的總傳入數(shù)據(jù)將是每秒100KB

          200 * 500 bytes = 100 KB/s

          對(duì)于讀請(qǐng)求,由于我們預(yù)計(jì)每秒鐘有大約20K的url重定向,所以我們的服務(wù)的總輸出數(shù)據(jù)將是每秒10MB

          20K * 500 bytes = ~10 MB/s

          內(nèi)存估計(jì)

          如果我們想緩存一些經(jīng)常被訪問(wèn)的熱點(diǎn)url,我們需要多少內(nèi)存來(lái)存儲(chǔ)它們?

          如果我們遵循80-20原則,即20%的url產(chǎn)生80%的流量,我們希望緩存這些20%的熱點(diǎn)url。

          由于我們每秒有2萬(wàn)次請(qǐng)求,我們每天將會(huì)收到17億次請(qǐng)求。

          20K * 3600 seconds * 24 hours = ~1.7 billion

          要緩存20%的請(qǐng)求,我們需要170GB內(nèi)存。

          0.2 * 1.7 billion * 500 bytes = ~170GB

          這里需要注意的一點(diǎn)是,由于會(huì)有很多重復(fù)的請(qǐng)求(相同的URL),因此,我們的實(shí)際內(nèi)存使用量將少于170GB。

          估算概述

          假設(shè)每個(gè)月有5億個(gè)新url,讀:寫(xiě)比率為100:1,下面是對(duì)我們服務(wù)容量估算的總結(jié)。

          ?創(chuàng)建短鏈 200/s?短鏈重定向 20K/s?入口流量 100KB/s?出口流量 10MB/s?五年需要存儲(chǔ)量 15TB?內(nèi)存用量 170GB

          四. 系統(tǒng)API設(shè)計(jì)

          一旦我們確定了需求,定義系統(tǒng)API總是一個(gè)好主意。這時(shí)候應(yīng)該明確說(shuō)明系統(tǒng)期望做到什么。

          我們可以使用SOAP或REST API來(lái)公開(kāi)服務(wù)的功能。下面是用于創(chuàng)建和刪除url的api的定義。

          createURL(api_dev_key, original_url, custom_alias=None, user_name=None, expire_date=None)

          參數(shù)

          ?api_dev_key (string) : 注冊(cè)帳號(hào)的api開(kāi)發(fā)密鑰。此外,這將用于根據(jù)用戶分配的配額限制用戶?original_url (string): 可選的短鏈地址?custom_alias (string) : URL 的可選自定義鍵?user_name (string) : 用于編碼的可選用戶名?? expire_date (string) : 可選的過(guò)期時(shí)間

          返回

          成功將返回縮短的URL。否則,它將返回錯(cuò)誤代碼。

          deleteURL(api_dev_key, url_key)

          其中url鍵是一個(gè)字符串,表示要檢索的縮短的url。成功的刪除返回URL Removed。

          我們?nèi)绾伟l(fā)現(xiàn)和預(yù)防濫用?

          惡意用戶可能會(huì)請(qǐng)求占用當(dāng)前系統(tǒng)中所有URL鍵,從而讓我們的業(yè)務(wù)失去新建短鏈的能力。為了防止濫用,我們可以通過(guò)api_dev_key來(lái)限制用戶。每個(gè)api_dev_key可以被限制在一段時(shí)間特定數(shù)量的URL創(chuàng)建和重定向。

          五. 數(shù)據(jù)庫(kù)設(shè)計(jì)

          在早期階段定義DB模式將有助于理解不同組件之間的數(shù)據(jù)流,并在之后幫助我們處理數(shù)據(jù)分區(qū)。

          關(guān)于我們將要存儲(chǔ)數(shù)據(jù)的性質(zhì)的一些觀察

          ?我們需要存儲(chǔ)數(shù)十億條記錄?我們存儲(chǔ)的每個(gè)對(duì)象都很小(小于1K)。?除了存儲(chǔ)哪個(gè)用戶創(chuàng)建了URL之外,記錄之間沒(méi)有任何關(guān)系。?我們的服務(wù)讀請(qǐng)求量很大。

          數(shù)據(jù)庫(kù)模型

          我們需要兩個(gè)表。一個(gè)用于存儲(chǔ)關(guān)于URL映射的信息,另一個(gè)用于創(chuàng)建短鏈接的用戶數(shù)據(jù)。

          URLUser
          [PK] Hash: varchar(16)[PK] UserID: int
          OriginalURL: varchar(512)Name: varchar(20)
          CreationDate: datetimeEmail: varchar(20)
          ExpirationDate: datatimeCreationDate: datetime

          LastLoginDate: datetime

          我們應(yīng)該使用什么樣的數(shù)據(jù)庫(kù)?

          因?yàn)槲覀冾A(yù)期存儲(chǔ)數(shù)十億行數(shù)據(jù),而且我們不需要使用對(duì)象之間的關(guān)系,像DynamoDB這樣的NoSQL鍵值存儲(chǔ),Cassandra或Riak是一個(gè)更好的選擇。選擇NoSQL也更容易擴(kuò)展。請(qǐng)參閱SQL vs NoSQL[3]了解更多細(xì)節(jié)

          六. 基本系統(tǒng)設(shè)計(jì)與算法

          我們?cè)谶@里要解決的問(wèn)題是,如何為給定的URL生成一個(gè)簡(jiǎn)短且唯一的主鍵。

          在第一節(jié)為什么我們需要URL短鏈示例中,縮短的 URL 是http://tinyurl.com/jlg8zpc。這個(gè) URL 的最后六個(gè)字符就是我們要生成的主鍵。

          我們將在這里探索兩種解決方案。

          方案一. 編碼URL

          我們可以計(jì)算給定URL的唯一哈希值(例如,MD5或SHA256等)。然后可以對(duì)哈希進(jìn)行編碼以用于顯示。

          編碼方式可以是base36 ([a-z,0-9])base62 ([A-Z, a-z, 0-9]),如果加上-.我們可以使用base64編碼。問(wèn)題是,短鍵的長(zhǎng)度應(yīng)該是多少?

          使用 base64 編碼,一個(gè) 6 字母長(zhǎng)的密鑰將產(chǎn)生 64^6 = ~687 億個(gè)可能的字符串,一個(gè) 8 字母長(zhǎng)的密鑰將產(chǎn)生 64^8 = ~281 萬(wàn)億個(gè)可能的字符串。

          68.7B唯一的字符串對(duì)于我們的系統(tǒng)來(lái)說(shuō)就足夠了,所以我們可以使用6個(gè)字母的鍵。

          如果我們使用 MD5 算法作為我們的哈希函數(shù),它將產(chǎn)生一個(gè) 128 位的哈希值。base64 編碼后,我們將得到一個(gè)超過(guò) 21 個(gè)字符的字符串(因?yàn)槊總€(gè) base64 字符編碼 6 位哈希值)。既然我們每個(gè)快捷鍵只有8個(gè)字符的空間,那么我們將如何選擇我們的密鑰呢?我們可以取前 6 個(gè)(或 8 個(gè))字母作為密鑰。不過(guò),這可能會(huì)導(dǎo)致密鑰重復(fù),在此基礎(chǔ)上我們可以從編碼字符串中選擇一些其他字符或交換一些字符。

          該解決方案有哪些不同的問(wèn)題?

          我們的編碼方案有以下幾個(gè)問(wèn)題

          1. 如果多個(gè)用戶輸入相同的URL,他們會(huì)得到相同的縮短URL,這是不可接受的。

          2. 如果 URL 的一部分是 URL 編碼的怎么辦

          例如,http://www.education.io/distributed.php?id=design 和 http://www.education.io/distributed.php%3Fid%3Ddesign

          解決方法

          我們可以向每個(gè)輸入U(xiǎn)RL添加遞增的序列號(hào),使其惟一,然后生成它的散列。我們不需要把這個(gè)序列號(hào)存儲(chǔ)在數(shù)據(jù)庫(kù)中。這種方法可能存在的問(wèn)題是不斷增加的序列號(hào)它會(huì)溢出,附加遞增的序列號(hào)也會(huì)影響服務(wù)的性能。

          另一種解決方案是在輸入U(xiǎn)RL中附加用戶id(它應(yīng)該是唯一的)。但是,如果用戶還沒(méi)有登錄,我們就必須要求用戶選擇唯一密鑰。即使在這之后如果我們有沖突,我們必須不斷生成一個(gè)密鑰,直到我們得到一個(gè)唯一的密鑰。

          方案二. 離線生成密鑰

          我們可以有一個(gè)獨(dú)立的密鑰生成服務(wù)(KGS),它事先生成隨機(jī)的6個(gè)字母字符串,并將它們存儲(chǔ)在一個(gè)數(shù)據(jù)庫(kù)中(我們稱(chēng)之為Key-db)。當(dāng)我們想要縮短一個(gè)URL時(shí),我們只需要一個(gè)已經(jīng)生成的鍵并使用它。這種方法將使事情變得非常簡(jiǎn)單和快速。我們不僅沒(méi)有對(duì)URL進(jìn)行編碼,而且還不必?fù)?dān)心重復(fù)或沖突。KGS將確保插入到key-DB中的所有鍵都是唯一的。

          并發(fā)性問(wèn)題

          一旦密鑰被使用,就應(yīng)該在數(shù)據(jù)庫(kù)中進(jìn)行標(biāo)記,以確保不會(huì)再次使用。如果有多個(gè)服務(wù)器并發(fā)地讀取密鑰,我們可能會(huì)遇到兩個(gè)或更多服務(wù)器試圖從數(shù)據(jù)庫(kù)讀取相同密鑰的場(chǎng)景。我們?nèi)绾谓鉀Q這個(gè)并發(fā)問(wèn)題?

          服務(wù)器可以使用 KGS 讀取/標(biāo)記數(shù)據(jù)庫(kù)中的密鑰。KGS 可以使用兩張表來(lái)存儲(chǔ)密鑰:一張用于存儲(chǔ)尚未使用的密鑰,另一張用于存儲(chǔ)所有使用過(guò)的密鑰。一旦 KGS 將密鑰提供給其中一臺(tái)服務(wù)器,它就可以將它們移動(dòng)到已使用的密鑰表中。KGS 可以始終在內(nèi)存中保留一些密鑰,以便在服務(wù)器需要時(shí)快速提供它們。

          為了簡(jiǎn)單起見(jiàn),一旦KGS在內(nèi)存中加載了一些鍵,它就可以將它們移動(dòng)到所使用的鍵表中。這確保了每個(gè)服務(wù)器獲得唯一的密鑰。如果KGS在將所有加載的密鑰分配給某個(gè)服務(wù)器之前掛掉,這部分密鑰將會(huì)被浪費(fèi),這是可以接受的,因?yàn)槲覀冇写罅康拿荑€。

          KGS還必須確保不向多個(gè)服務(wù)器提供相同的密鑰。為此,它必須同步(或獲得鎖)持有密鑰的數(shù)據(jù)結(jié)構(gòu),然后從該數(shù)據(jù)結(jié)構(gòu)中刪除密鑰并將它們交給服務(wù)器。

          密鑰數(shù)據(jù)庫(kù)大小是多少?

          使用 base64 編碼,我們可以生成 68.7B 個(gè)唯一的六個(gè)字母鍵。如果我們需要一個(gè)字節(jié)來(lái)存儲(chǔ)一個(gè)字母數(shù)字字符,我們可以將所有鍵存儲(chǔ)在412GB的磁盤(pán)。

          6 (characters per key) * 68.7B (unique keys) = 412 GB

          KGS不是單點(diǎn)故障嗎?

          是的。為了解決這個(gè)問(wèn)題,我們可以有一個(gè)備用的KGS副本,當(dāng)主服務(wù)器死亡時(shí),備用服務(wù)器可以接管生成并提供密鑰。

          每個(gè)應(yīng)用服務(wù)器是否可以從key-DB中緩存一些key?

          是的,而且可以加快響應(yīng)速度。盡管在這種情況下,如果應(yīng)用服務(wù)器在使用所有密鑰之前就死掉了,我們最終會(huì)丟失這些密鑰。但這是可以接受的,因?yàn)槲覀冇?8B唯一的6個(gè)字母的key。

          如何執(zhí)行鍵查找?

          我們可以在數(shù)據(jù)庫(kù)或鍵值存儲(chǔ)中查找鍵以獲得完整的URL。如果存在,則向?yàn)g覽器發(fā)出一個(gè)HTTP 302重定向狀態(tài),并在請(qǐng)求的Location字段中傳遞存儲(chǔ)的URL。如果該密鑰不在我們的系統(tǒng)中,則發(fā)出HTTP 404 not Found狀態(tài)或?qū)⒂脩糁囟ㄏ蚧刂黜?yè)。

          我們應(yīng)該對(duì)自定義別名施加大小限制嗎?

          我們的服務(wù)支持自定義別名。用戶可以選擇他們喜歡的任何密鑰,但提供自定義別名不是強(qiáng)制性的。但是,對(duì)自定義別名施加大小限制以確保我們擁有一致的 URL 數(shù)據(jù)庫(kù)是合理的(并且通常是可取的)。假設(shè)用戶可以為每個(gè)客戶鍵指定最多 16 個(gè)字符(如數(shù)據(jù)庫(kù)架構(gòu)所示)

          七. 數(shù)據(jù)分區(qū)與備份

          為了擴(kuò)展我們的數(shù)據(jù)庫(kù),我們需要對(duì)它進(jìn)行分區(qū),以便它能夠存儲(chǔ)數(shù)十億url的信息。我們需要想出一個(gè)分區(qū)方案,將我們的數(shù)據(jù)劃分并存儲(chǔ)到不同的DB服務(wù)器上。

          區(qū)間劃分

          我們可以根據(jù) URL 的第一個(gè)字母或哈希鍵將 URL 存儲(chǔ)在單獨(dú)的分區(qū)中。因此,我們將所有以字母A開(kāi)頭的 URL 保存在一個(gè)分區(qū)中,將那些以字母`B``開(kāi)頭的 URL 保存在另一個(gè)分區(qū)中,依此類(lèi)推。這種方法稱(chēng)為基于范圍的分區(qū)。我們甚至可以將某些不太頻繁出現(xiàn)的字母組合到一個(gè)數(shù)據(jù)庫(kù)分區(qū)中。我們應(yīng)該提供一個(gè)靜態(tài)分區(qū)方案,以便我們可以以可預(yù)測(cè)的方式存儲(chǔ)/查找文件。

          這種方法的主要問(wèn)題是,它可能導(dǎo)致服務(wù)器不平衡。例如: 我們決定將所有以字母E開(kāi)頭的url放到一個(gè)DB分區(qū)中,但后來(lái)我們意識(shí)到有太多的url以字母E開(kāi)頭。

          基于散列分區(qū)

          在這個(gè)方案中,我們?nèi)∷鎯?chǔ)對(duì)象的哈希值。然后根據(jù)散列計(jì)算要使用哪個(gè)分區(qū)。在本例中,我們可以使用鍵或?qū)嶋HURL的哈希值來(lái)確定存儲(chǔ)數(shù)據(jù)對(duì)象的分區(qū)。我們的哈希函數(shù)將隨機(jī)地將url分配到不同的分區(qū)中(例如,我們的哈希函數(shù)總是可以將任意鍵映射到[1…256]之間的一個(gè)數(shù)字),這個(gè)數(shù)字將代表我們存儲(chǔ)對(duì)象的分區(qū)。

          這種方法仍然會(huì)導(dǎo)致重載分區(qū),這個(gè)問(wèn)題可以通過(guò)一致性哈希來(lái)解決。

          八. 緩存

          我們可以緩存頻繁訪問(wèn)的url。可以使用一些現(xiàn)成的解決方案,如Memcache,它可以存儲(chǔ)帶有各自散列的完整url。應(yīng)用服務(wù)器在訪問(wèn)后端存儲(chǔ)之前,可以快速檢查緩存是否具有所需的URL。

          緩存容量應(yīng)該有多大?

          我們緩存每日流量的20%,然后根據(jù)客戶端使用模式調(diào)整我們需要多少緩存服務(wù)器。如上所述,我們需要170GB內(nèi)存來(lái)緩存每日流量的20%。因?yàn)楝F(xiàn)在的服務(wù)器可以有256GB的內(nèi)存,我們可以很容易地把所有的緩存放到一臺(tái)機(jī)器上。或者,我們可以使用一些較小的服務(wù)器來(lái)存儲(chǔ)所有這些熱點(diǎn)URL。

          哪種緩存驅(qū)逐策略最適合我們的需求?

          當(dāng)緩存已滿,而我們想用更新/更熱的 URL 替換鏈接時(shí),我們將如何選擇?最近最少使用 (LRU) 可能是比較合適的。根據(jù)此策略,我們首先丟棄最近最少使用的 URL。我們可以使用 LinkedHashMap 或類(lèi)似的數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)我們的 URL 和 Hash,這也可以跟蹤最近訪問(wèn)過(guò)的 URL。

          為了進(jìn)一步提高效率,我們可以復(fù)制緩存服務(wù)器來(lái)在它們之間分配負(fù)載。

          如何更新每個(gè)緩存副本?

          每當(dāng)緩存丟失時(shí),我們的服務(wù)器就會(huì)擊中后端數(shù)據(jù)庫(kù)。每當(dāng)發(fā)生這種情況時(shí),我們就可以更新緩存并將新條目傳遞給所有緩存副本。每個(gè)副本都可以通過(guò)添加新條目來(lái)更新它們的緩存。如果副本已經(jīng)有該條目,則可以簡(jiǎn)單地忽略它。

          九. 負(fù)載均衡

          我們可以在系統(tǒng)的三個(gè)地方添加負(fù)載均衡

          1.客戶端和應(yīng)用服務(wù)器之間2.應(yīng)用服務(wù)器與數(shù)據(jù)庫(kù)服務(wù)器之間的連接3.應(yīng)用服務(wù)器和緩存服務(wù)器之間

          最初,我們可以使用簡(jiǎn)單的Round Robin方法,將傳入請(qǐng)求平均分配到后端服務(wù)器。這種LB實(shí)現(xiàn)簡(jiǎn)單,而且不引入任何開(kāi)銷(xiāo)。這種方法的另一個(gè)好處是,如果一個(gè)服務(wù)器死機(jī)了,LB將停止向它發(fā)送任何流量。

          輪詢LB的問(wèn)題是沒(méi)有考慮服務(wù)器負(fù)載。如果服務(wù)器負(fù)載過(guò)重或速度變慢,LB不會(huì)停止向該服務(wù)器發(fā)送新的請(qǐng)求。為了解決這個(gè)問(wèn)題,可以放置一個(gè)更智能的LB解決方案,定期查詢后端服務(wù)器的負(fù)載,并基于此調(diào)整流量。

          十. 數(shù)據(jù)清理

          短鏈?zhǔn)菓?yīng)該永久保存還是應(yīng)該到期清除? 如果到達(dá)用戶指定的過(guò)期時(shí)間,該鏈接將發(fā)生什么情況?

          如果我們選擇主動(dòng)搜索過(guò)期鏈接來(lái)刪除它們,這將給我們的數(shù)據(jù)庫(kù)帶來(lái)很大的壓力。相反,我們可以緩慢地刪除過(guò)期鏈接,并進(jìn)行惰性清理。我們的服務(wù)將確保只有過(guò)期的鏈接將被刪除,盡管一些過(guò)期鏈接可以活得更長(zhǎng),但永遠(yuǎn)不會(huì)返回給用戶。

          ?當(dāng)用戶試圖訪問(wèn)過(guò)期鏈接時(shí),我們可以刪除鏈接并向用戶返回一個(gè)錯(cuò)誤?可以定期運(yùn)行一個(gè)單獨(dú)的Cleanup服務(wù),從存儲(chǔ)和緩存中刪除過(guò)期的鏈接。該服務(wù)應(yīng)該是非常輕量級(jí)的,并且只在用戶流量預(yù)期較低時(shí)才可以調(diào)度運(yùn)行?我們可以為每個(gè)鏈接設(shè)置一個(gè)默認(rèn)的過(guò)期時(shí)間(例如,兩年)。?在刪除過(guò)期鏈接之后,我們可以將密鑰放回key-db中以供重用。?應(yīng)該刪除6個(gè)月沒(méi)有訪問(wèn)過(guò)的鏈接嗎? 這可能有點(diǎn)棘手。由于存儲(chǔ)變得越來(lái)越便宜,我們可以決定永遠(yuǎn)保持鏈接。

          十一. 追蹤擴(kuò)展

          一個(gè)短 URL 被使用了多少次,用戶位置是什么,等等?我們將如何存儲(chǔ)這些統(tǒng)計(jì)信息?如果它是在每個(gè)視圖上更新的 DB 行的一部分,那么當(dāng)一個(gè)熱點(diǎn)的 URL 受到大量并發(fā)請(qǐng)求的沖擊時(shí)會(huì)發(fā)生什么?

          一些值得跟蹤的統(tǒng)計(jì)數(shù)據(jù): 訪問(wèn)者的國(guó)家、訪問(wèn)日期和時(shí)間、涉及點(diǎn)擊的網(wǎng)頁(yè)、瀏覽器或訪問(wèn)頁(yè)面的平臺(tái)。

          十二. 安全與權(quán)限

          用戶是否可以創(chuàng)建私有URL或允許特定用戶組訪問(wèn)URL。

          我們可以在數(shù)據(jù)庫(kù)中存儲(chǔ)每個(gè) URL 的權(quán)限級(jí)別(公共/私有)。我們還可以創(chuàng)建一個(gè)單獨(dú)的表來(lái)存儲(chǔ)有權(quán)查看特定 URL 的用戶 ID。如果用戶沒(méi)有權(quán)限并嘗試訪問(wèn) URL,我們可以發(fā)回錯(cuò)誤 (HTTP 401)。鑒于我們將數(shù)據(jù)存儲(chǔ)在像 Cassandra 這樣的 NoSQL 寬列數(shù)據(jù)庫(kù)中,表存儲(chǔ)權(quán)限的密鑰將是哈希(或 KGS 生成的密鑰)。這些列將存儲(chǔ)有權(quán)查看 URL 的那些用戶的用戶 ID。

          References

          [1] 《系統(tǒng)設(shè)計(jì)面試的萬(wàn)金油》: http://antzuhl.cn/archives/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1%E9%9D%A2%E8%AF%95%E7%9A%84%E4%B8%87%E9%87%91%E6%B2%B9
          [2] TinyURL: https://tinyurl.com/app
          [3] SQL vs NoSQL: https://www.educative.io/collection/page/5668639101419520/5649050225344512/5728116278296576/

          瀏覽 50
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  精品无码秘 人妻一区二区媚黑 | 成人三级片网站视频 | 五月丁香之婷婷 | 欧美另类巨大 | 欧美一级黄色电影在线播放 |