短网址系统
文章目錄
- 1. 短網址服務整體介紹
- 2. 如何通過哈希算法生成短網址?
- 2.1 如何讓短網址更短
- 2.2 如何解決哈希沖突?
- 2.3 如何優化哈希算法生成短網址的性能?
- 3. 如何通過ID生成器生成短網址?
- 3.1 相同的原始網址可能會對應不同的短網址
- 3.2 如何實現高性能的 ID 生成器?
- 4. 總結
在微博里發布一條帶網址的信息,微博會把里面的網址轉化成一個更短的網址。只要訪問這個短網址,就相當于訪問原始的網址。
原始網址:https://github.com/wangzheng0822/ratelimiter4j 短網址:http://t.cn/EtR9QEG1. 短網址服務整體介紹
當用戶點擊短網址時,短網址服務會將瀏覽器重定向為原始網址。這個過程是如何實現的呢?
從圖中可看出,瀏覽器會先訪問短網址服務,通過短網址獲取到原始網址,再通過原始網址訪問到頁面。這部分功能今天不講。重點來看,如何將長網址轉化成短網址?
2. 如何通過哈希算法生成短網址?
哈希算法可以將一個不管多長的字符串,轉化成一個長度固定的哈希值。
在生成短網址這個問題上,我們不需要考慮反向解密的難度,只需關心哈希算法的計算速度和沖突概率。
比較著名并且應用廣泛的一個哈希算法,那就是 MurmurHash 算法。盡管這個哈希算法在2008年才被發明出來,但現在它已經廣泛應用到Redis、MemCache、Cassandra、HBase、Lucene等眾多著名的軟件中。
MurmurHash 算法提供了兩種長度的哈希值,一種是32bits,一種是128bits。為了讓最終生成的短網址盡可能短,可以選擇32bits的哈希值。對于開頭那個GitHub網址,經過MurmurHash 計算后,得到的哈希值就是181338494。我們再拼上短網址服務的域名,就變成了最終的短網址 http://t.cn/181338494(其中,http://t.cn是短網址服務的域名)。
2.1 如何讓短網址更短
通過MurmurHash 算法得到的短網址還是很長,而且跟開頭那個網址的格式好像也不一樣。
我們將10進制的哈希值,轉化成更高進制的哈希值,這樣哈希值就變短了。我們知道16進制中,我們用A~E 來表示10~15。在網址URL中,常用的合法字符有0~9、a~z,A ~ Z 這樣62個字符。為了讓哈希值表示起來盡可能短,可以將10進制的哈希值轉化成62進制。計算過程如下。最終用62進制表示的短網址就是http://t.cn/cgSqq。
2.2 如何解決哈希沖突?
盡管 MurmurHash 算法,沖突概率非常低。一旦沖突,會導致兩個原始網址被轉化成同一個短網址。當用戶訪問短網址時,就無從判斷,想要訪問的是哪一個。這個問題該如何解決呢?
一般情況下,我們會保存短網址跟原始網址之間的對應關系,以便后續用戶在訪問短網址的時候,可以根據對應關系,查找到原始網址。存儲這種對應關系的方式有很多,比如自己設計存儲系統或者利用現成的數據庫。前面我們講到的數據庫有MySQL、Redis。就拿MySQL來舉例。假設短網址與原始網址之間的對應關系,就存儲在MySQL 數據庫中。
當有一個新的原始網址需要生成短網址的時候,先利用MurmurHash 算法,生成短網址。然后,拿這個新生成的短網址,在MySQL 數據庫中查找。
-
如果沒有找到相同的短網址,表明,這個新生成的短網址沒有沖突。于是我們就將這個短網址返回給用戶(請求生成短網址的用戶),然后將這個短網址與原始網址之間的對應關系,存儲到MySQL數據庫中。
-
如果找到了相同的短網址,那也并不一定說明就沖突了。我們從數據庫中,將這個短網址對應的原始網址也取出來。
- 如果數據庫中記錄的原始網址,跟正在處理的原始網址一樣,說明已經有人請求過這個原始網址的短網址了。就可以拿這個短網址直接用。
- 如果數據庫中記錄的原始網址,跟正在處理的原始網址不一樣,說明哈希算法發生了沖突。不同的原始網址,經過計算,得到的短網址重復了。這個時候,怎么辦?
可以給原始網址拼接一串特殊字符,比如“[DUPLICATED]",然后再重新計算哈希值,兩次哈希計算都沖突的概率,顯然是非常低的。
假設出現非常極端的情況,又發生沖突了,我們可以再換一個拼接字符串,比如“[OHMYGOD]",再計算哈希值。然后把計算得到的哈希值,跟原始網址拼接了特殊字符串之后的文本,一并存儲在MySQL數據庫中。當用戶訪問短網址的時候,短網址服務先通過短網址,在數據庫中查找到對應的原始網址。如果原始網址有拼接特殊字符(這個很容易通過字符串匹配算法找到),我們就先將特殊字符去掉,然后再將不包含特殊字符的原始網址返回給瀏覽器。
2.3 如何優化哈希算法生成短網址的性能?
為了判斷生成的短網址是否沖突,需要拿生成的短網址,在數據庫中查找。如果數據庫數據非常多,查找會非常慢,影響短網址服務的性能。如何優化?
- 可以給短網址字段添加B+樹索引。這樣通過短網址查詢原始網址的速度就提高了。
- 在短網址生成的過程中,我們會跟數據庫打兩次交道,也就是會執行兩條SQL語句。第一個SQL 語句是通過短網址查詢短網址與原始網址的對應關系,第二個SQL語句是將新生成的短網址和原始網址之間的對應關系存儲到數據庫。
我們知道,一般情況下,數據庫和應用服務(只做計算不存儲數據的業務邏輯部分)會部署在兩個獨立的服務器或者虛擬服務器上。那兩條SQL 語句的執行就需要兩次網絡通信。這種IO通信耗時以及SQL 語句的執行,才是整個短網址服務的性能瓶頸所在。所以,為了提高性能,需要盡量減少SQL 語句。如何減少SQL 語句呢?
- 可以給數據庫中的短網址字段,添加一個唯一索引(不止是索引,還要求表中不能有重復的數據)。當有新的原始網址需要生成短網址的時候,我們并不會先拿生成的短網址,在數據庫中查找判重,而是直接將生成的短網址與對應的原始網址,嘗試存儲到數據庫中。如果數據庫能夠將數據正常寫入,那說明并沒有違反唯一索引,也就是說,這個新生成的短網址并沒有沖突。
- 如果數據庫反饋違反唯一性索引異常,那還得重新執行剛剛講過的“查詢、寫入”過程,SQL語句執行的次數不減反增。但是,在大部分情況下,我們把新生成的短網址和對應的原始網址,插入到數據庫的時候,并不會出現沖突。所以,大部分情況下,只需要執行一條寫入的SQL語句就可以了。所以,從整體上看,總的SQL語句執行次數會大大減少。
我們還有另外一個優化SQL語句次數的方法,那就是借助布隆過濾器。
-
把已經生成的短網址,構建成布隆過濾器。我們知道,布隆過濾器是比較節省內存的一種存儲結構,長度是10億的布隆過濾器,也只需要125MB左右的內存。
-
當有新的短網址生成的時候,先拿這個新生成的短網址,在布隆過濾器中查找。如果查找不存在,說明這個新生成的短網址沒有沖突。再執行寫入短網址和對應原始網頁的SQL語句就可以了。通過先查詢布隆過濾器,總的SQL語句的執行次數減少了。
3. 如何通過ID生成器生成短網址?
可以維護一個ID自增生成器。它可以生成1、2、3…這樣自增的整數ID。當短網址服務接收到一個原始網址轉化成短網址的請求之后,它先從ID生成器中取一個號碼,然后將其轉化成62進制表示法,拼接到短網址服務的域名(比如http://t.cn/)后面,就形成了最終的短網址。最后,我們還是會把生成的短網址和對應的原始網址存儲到數據庫中。
理論非常簡單好理解。有幾個細節需要處理。
3.1 相同的原始網址可能會對應不同的短網址
每次新來一個原始網址,就生成一個新的短網址,會導致兩個相同的原始網址生成了不同的短網址。如何處理呢?
-
第一種思路是不做處理。相同的原始網址對應不同的短網址,用戶是可以接受的。用戶只關心短網址能否正確地跳轉到原始網址。短網址長什么樣,他根本就不關心。
-
第二種思路是借助哈希算法生成短網址的處理思想,當要給一個原始網址生成短網址的時候,要先拿原始網址在數據庫中查找,看數據庫中是否已經存在相同的原始網址了。如果數據庫中存在,那我們就取出對應的短網址,直接返回給用戶。
不過,這種處理思路有個問題,我們需要給數據庫中的短網址和原始網址這兩個字段,都添加索引。短網址上加索引是為了提高用戶查詢短網址對應的原始網頁的速度,原始網址上加索引是為了加快剛剛講的通過原始網址查詢短網址的速度。這種解決思路雖然能滿足“相同原始網址對應相同短網址”這樣一個需求,但是是有代價的:一方面兩個索引會占用更多的存儲空間,另一方面索引還會導致插入、刪除等操作性能的下降。
3.2 如何實現高性能的 ID 生成器?
實現ID生成器的方法有很多,比如利用數據庫自增字段。當然我們也可以自己維護一個計數器,不停地加一加一。但是,一個計數器來應對頻繁的短網址生成請求,顯然是有點吃力的(因為計數器必須保證生成的ID不重復,籠統概念上講,就是需要加鎖)。如何提高ID生成器的性能呢?
- 第一種思路,可以給ID生成器裝多個前置發號器。我們批量地給每個前置發號器發送ID號碼。當我們接受到短網址生成請求的時候,就選擇一個前置發號器來取號碼。這樣通過多個前置發號器,明顯提高了并發發號的能力。
- 第二種思路跟第一種差不多。不再使用一個ID生成器和多個前置發號器這樣的架構,直接實現多個ID生成器同時服務。為了保證每個ID生成器生成的ID不重復。我們要求每個ID生成器按照一定的規則,來生成ID號碼。比如,第一個ID生成器只能生成尾號為0的,第二個只能生成尾號為1的,以此類推。通過多個ID生成器同時工作,也提高了ID生成的效率。
4. 總結
短網址服務的兩種實現方法。
通過哈希算法生成短網址。采用計算速度快、沖突概率小的MurmurHash算法,并將計算得到的10進制數,轉化成62進制表示法,進一步縮短短網址的長度。對于哈希算法的哈希沖突問題,通過給原始網址添加特殊前綴字符,重新計算哈希值的方法來解決。
通過ID生成器生成短網址。維護一個ID自增的ID生成器,給每個原始網址分配一個ID號碼,并且同樣轉成62進制表示法,拼接到短網址服務的域名之后,形成最終的短網址。
總結
- 上一篇: 公需科目必须学吗_专业技术人员一般公需科
- 下一篇: 数据结构--图 Graph