使用場景(Scenario)
微博和Twitter都有140字數的限制,如果分享一個長網址,很容易就超出限制,發佈出去。短網址服務可以把一個長網址變成短網址,方便在社交網絡上傳播。
需求(Needs)
- 將長連接變成短連接
- 用戶訪問短連接,會跳轉到正確的長連接上
短網址的長度
當前互聯網上的網頁總數大概是 45 億,45億 超過了 2^32 ,但遠遠小於64位整數的上限值,那麼用一個64位整數足夠了。微博的短網址服務用的是長度爲 7
的字符串,這個字符串可以看做是 62 進制的數,那麼最大能表示 62^7 個網址,遠遠大於 45 億。所以長度爲 7 就足夠了。這個量級遠遠超過互聯網上的 URL 總數了,絕對夠用了。現代的 web 服務器(例如Apache, Nginx)大部分都區分 URL 裏的大小寫了,所以用大小寫字母來區分不同的 URL 是沒問題的。
[a-z,A-Z,0-9] 這62個字母或數字組成的7位的字符串。
一對多映射
一個長網址,對應一個短網址,還是可以對應多個短網址?
一般而言,一個長網址,在不同的地點,不同的用戶等情況下,生成的短網址應該不一樣。這樣,在後端數據庫中,可以更好的進行數據分析。如果一個長網址與一個短網址一一對應,那麼在數據庫中,僅有一行數據,無法區分不同的來源,就無法做數據分析。
以這個7位長度的短網址作爲唯一ID,這個ID下可以掛各種信息,比如生成該網址的用戶名,所在網站,HTTP頭部的 User Agent等信息,收集了這些信息,纔有可能在後面做大數據分析,挖掘數據的價值。短網址服務商的一大盈利來源就是這些數據。
如何計算短網址
現在我們設定了短網址是一個長度爲7的字符串,如何計算得到這個短網址呢?
-
自增id
- 無碰撞的方法,沒新增一個短碼,就在上次的短碼id上加1,然後把這個10進制的數,轉成一個62進制的字符串。
- 可以利用數據庫表中的自增id來完成,每次先查數據庫表中自增id最大值max,然後max+1轉成62進制數
- 短碼id是從一位長度遞增的,長度不固定,可以指定id從某個數字開始,確保所有短碼長度一致。同事短碼是有序的,可能有安全問題,所以將生成的短碼id結合長網址等其他關鍵字,進行MD5運算生成最後的短碼。
-
普通隨機數
- 利用Math.round()生成隨機數,如果庫中存在這個id就重複生成隨機數。
- 這種情況下,發生碰撞的可能性不小,可能要多次循環纔可以生成一個不衝突的短碼。
-
摘要算法(哈希算法)
- 輸入任意長度的數據,輸出固定長度的數據,相同的輸入對應相同的輸出,不同的輸入儘量拿到不同的輸出。
- (1)將長網址md5生成32位簽名串,分爲4段, 每段8個字節;
- (2)對這四段循環處理, 取8個字節, 將他看成16進制串與0x3fffffff(30位1)與操作, 即超過30位的忽略處理;
- (3)這30位分成6段, 每5位的數字作爲字母表的索引取得特定字符, 依次進行獲得6位字符串;
- (4)總的md5串可以獲得4個6位串;取裏面的任意一個就可作爲這個長url的短url地址;
- 也會發生碰撞,但是碰撞機率小,一單發生碰撞的話解決衝突比較麻煩。
-
利用Redis號段模式
- 將 62^7的 ID 進行分段,比如分爲 N 段,前 K 位一致。那麼剩下的位就可以通過 Redis 來進行生成,防止重複。
- 假設要獲取一個號段,比如(1,1000]的,只需要在本地利用redis自增一個id就可以,
如何存儲
-
數據庫存儲
- 域名,鏈接除域名外的後綴,完成鏈接,生成的短連接,短鏈接失效時間,當前鏈接總的點擊次數。
- 因爲短鏈接需求可能是相關活動或者熱點數據,所以過濾一定時間熱潮會持續衰退,沒必要永久保存增加每次查詢的負擔。
-
數據庫分表
- 如果一條數據是10b的話,總容量是45億×10b,單表肯定無法支撐,所以要分表。
- 假設分成100張表的話,每張表名通過數字區分。可以通過短鏈接做encoding編碼生成數字類型,然後做路由找到表。
-
緩存存儲
- 查詢需求:如果是幾百G的數據量放緩存是不合適的,可以將近3個月的查詢或者新增URL放入緩存,使用LRU算法進行熱點更新。這樣,最近使用的命中緩存概率會高,查不到在查庫更新緩存。
- 新增需求:新增的就先查緩存是否存在,緩存沒有再查庫,庫的話可以分表,查詢率不會很低。
- 緩存設計:用戶用短鏈接查真是地址,緩存key是短鏈接,使用KV存就可以。
如何跳轉
當我們在瀏覽器裏輸入 http://bit.ly/a3300 時
- DNS首先解析獲得 http://bit.ly的
IP
地址 - 當
DNS
獲得IP
地址以後(比如:12.34.5.32),會向這個地址發送HTTP
GET
請求,查詢短碼a3300
- [http://bit.ly 服務器會通過短碼
a3300
獲取對應的長 URL - 請求通過
HTTP
301
轉到對應的長 URL http://www.theaustralian.news.com.au/story/0,25197,26089617-5013871,00.html。
301是永久重定向,302是臨時重定向。短地址一經生成就不會變化,所以用301是符合http語義的。但是如果用了301, Google
,百度
等搜索引擎,搜索的時候會直接展示真實地址,那我們就無法統計到短地址被點擊的次數了,也無法收集用戶的Cookie
, User Agent
等信息,這些信息可以用來做很多有意思的大數據分析,也是短網址服務商的主要盈利來源。
所以,正確答案是302重定向。
可以抓包看看mrw.so的短網址是怎麼做的,使用 Chrome 瀏覽器,訪問這個URL http://mrw.so/4UD39p
,是我事先發微博自動生成的短網址。來抓包看看返回的結果是啥,可見新浪微博用的就是302臨時重定向。