@tang minyi
的回答,也非常不錯,如果面試者這麼回答,我也會很高興的。
對於我用詞比較激烈的問題,我面試時真實想法既是如此,也懶得潤色了。
這個問題看到就想答。
而這個問題,也是我現在招聘面試題裡面必考的一道,這一道題裡面有很多可考的地方,能夠相對綜合的考察候選人的功力。
最爛的回答實現乙個演算法,將長位址轉成短位址。實現長和短一一對應。然後再實現它的逆運算,將短位址還能換算回長位址。
這個回答看起來挺完美的,然後候選人也會說現在時間比較短,如果給我時間我去找這個演算法就解決問題了。但是稍微有點計算機或者資訊理論常識的人就能發現,這個演算法就跟永動機一樣,是永遠不可能找到的。即使我們定義短位址是100位。那麼它的變化是62的100次方。62=10數字+26大寫字母+26小寫字母。無論這個數多麼大,他也不可能大過世界上可能存在的長位址。所以實現一一對應,本身就是不可能的。
再換乙個說法來反駁,如果真有這麼乙個演算法和逆運算,那麼基本上現在的壓縮軟體都可以歇菜了,而世界上所有的資訊,都可以壓縮到100個字元。這~可能嗎。
另乙個很爛的回答和上面一樣,也找乙個演算法,把長位址轉成短位址,但是不存在逆運算。我們需要把短對長的關係存到db中,在通過短查長時,需要查db。
怎麼說呢,沒有改變本質,如果真有這麼乙個演算法,那必然是會出現碰撞的,也就是多個長位址轉成了同乙個短位址。因為我們無法預知會輸入什麼樣的長位址到這個系統中,所以不可能實現這樣乙個絕對不碰撞的hash函式。
比較爛的回答那我們用乙個hash演算法,我承認它會碰撞,碰撞後我再在後面加1,2,3不就行了。
ok,這樣的話,當通過這個hash演算法算出來之後,可能我們會需要做btree式的大於小於或者like查詢到能知道現在應該在後面加1,2,或3,這個也可能由於輸入的長位址集的不確定性。導致生成短位址時間的不確定性。同樣爛的回答還有隨機生成乙個短位址,去查詢是否用過,用過就再隨機,如此往復,直到隨機到乙個沒用過的短位址。
正確的原理上面是幾種典型的錯誤回答,下面咱們直接說正確的原理。
正確的原理就是通過發號策略,給每乙個過來的長位址,發乙個號即可,小型系統直接用mysql的自增索引就搞定了。如果是大型應用,可以考慮各種分布式key-value系統做發號器。不停的自增就行了。第乙個使用這個服務的人得到的短位址是
第二個是
第11個是
第依次往後,相當於實現了乙個62進製的自增欄位即可。
幾個子問題
1. 62進製如何用資料庫或者kv儲存來做?
其實我們並不需要在儲存中用62進製,用10進製就好了。比如第10000個長位址,我們給它的短位址對應的編號是9999,我們通過儲存自增拿到9999後,再做乙個10進製到62進製的轉換,轉成62進製數即可。這個10~62進製轉換,你完全都可以自己實現。
2. 如何保證同乙個長位址,每次轉出來都是一樣的短位址
過一段時間你再來轉,我還會給你乙個
。這看起來挺不好的,但是不好在**呢?不好在不是一一對應,而一長對多短。這與我們完美主義的基因不符合,那麼除此以外還有什麼不對的地方?
有人說它浪費空間,這是對的。同乙個長位址,產生多條短位址記錄,這明顯是浪費空間的。那麼我們如何避免空間浪費,有人非常迅速的回答我,建立乙個長對短的kv儲存即可。嗯,聽起來有理,但是。。。這個kv儲存本身就是浪費大量空間。所以我們是在用空間換空間,而且貌似是在用大空間換小空間。真的划算嗎?這個問題要考慮一下。當然,也不是沒有辦法解決,我們做不到真正的一一對應,那麼打個折扣是不是可以搞定?這個問題的答案太多種,各有各招,我這就不說了。(由於實在太多人糾結這個問題,請見我最下方的更新)
3. 如何保證發號器的大併發高可用
上面設計看起來有乙個單點,那就是發號器。如果做成分布式的,那麼多節點要保持同步加1,多點同時寫入,這個嘛,以cap理論看,是不可能真正做到的。其實這個問題的解決非常簡單,我們可以退一步考慮,我們是否可以實現兩個發號器,乙個發單號,乙個發雙號,這樣就變單點為多點了?依次類推,我們可以實現1000個邏輯發號器,分別發尾號為0到999的號。每發乙個號,每個發號器加1000,而不是加1。這些發號器獨立工作,互不干擾即可。而且在實現上,也可以先是邏輯的,真的壓力變大了,再拆分成獨立的物理機器單元。1000個節點,估計對人類來說應該夠用了。如果你真的還想更多,理論上也是可以的。
4. 具體儲存如何選擇
這個問題就不展開說了,各有各道,主要考察一下對儲存的理解。對快取原理的理解,和對市面上db、cache系統可用性,併發能力,一致性等方面的理解。
5. 跳轉用301還是302
這也是乙個有意思的話題。首先當然考察乙個候選人對301和302的理解。瀏覽器快取機制的理解。然後是考察他的業務經驗。301是永久重定向,302是臨時重定向。短位址一經生成就不會變化,所以用301是符合http語義的。同時對伺服器壓力也會有一定減少。
但是如果使用了301,我們就無法統計到短位址被點選的次數了。而這個點選次數是乙個非常有意思的大資料分析資料來源。能夠分析出的東西非常非常多。所以選擇302雖然會增加伺服器壓力,但是我想是乙個更好的選擇。
大概就是這樣。
------五一假期後更新-------
我上面其實講到了,這個方案最簡單的是建立乙個長對短的hashtable,這樣相當於用空間來換空間,同時換取乙個設計上的優雅(真正的一對一)。
實際情況是有很多價效比高的打折方案可以用,這個方案設計因人而異了。那我就說一下我的方案吧。
我的方案是:用key-value儲存,儲存「最近」生成的長對短的乙個對應關係。注意是「最近」,也就是說,我並不儲存全量的長對短的關係,而只儲存最近的。比如採用一小時過期的機制來實現lru淘汰。
這樣的話,長轉短的流程變成這樣:
1 在這個「最近」表中檢視一下,看長位址有沒有對應的短位址
1.1 有就直接返回,並且將這個key-value對的過期時間再延長成一小時
1.2 如果沒有,就通過發號器生成乙個短位址,並且將這個「最近」表中,過期時間為1小時
所以當乙個位址被頻繁使用,那麼它會一直在這個key-value表中,總能返回當初生成那個短位址,不會出現重複的問題。如果它使用並不頻繁,那麼長對短的key會過期,lru機制自動就會淘汰掉它。
當然,這不能保證100%的同乙個長位址一定能轉出同乙個短位址,比如你拿乙個生僻的url,每間隔1小時來轉一次,你會得到不同的短位址。但是這真的有關係嗎?
短Url 系統設計
方案一 自己寫演算法,把長url 轉換為短的 1 10,a z,a z 62個元素。這有點難啊,需要跑多久。並且對方輸入的url長度的不固定,所以,很難。方案二 表的對映,使用k v,形式。乙個短的key,去對映長的url,長的url依然還是那個url,只不過起了乙個外號 別名 注意 1.key的唯...
設計短鏈結系統
短鏈結轉換是將任意乙個長的 url 如 轉為乙個固定長度的url,如itlym.cn sd5d1r,並可以通過訪問短 url 來跳轉到長url上。呼叫簡訊服務傳送簡訊時,會有字數限制或因字數長短收取不同費用。如何設計乙個可靠的短鏈結系統 由於url字元限制,推薦為大小寫字母加數字,共62種字元。一般...
系統設計 短鏈結系統 short url
最近看了一些關於短址 short url 方面的一些部落格,有些部落格說到一些好的東西,但是,也不是很全,所以,這篇部落格算是對其它部落格的乙個總結吧 短址,顧名思義,就是把長的 url 轉成短的 url,現在提供這種服務的有很多公司,我們以google家的 url shortener 服務 為例。...