技术干货 | 高性能短链设计与实现
URL 短鏈,就是把原來較長的網址,轉換成比較短的網址。以下面這條短信為例:
上圖中,https://dx.10086.cn/looGDg 就是一條短鏈。用戶點擊藍色的鏈接,就可以在瀏覽器中看到它對應的原網址:
http://wap.zj.10086.cn/case/mould/produce/9b032ecfcb9b42f6a8fc411d160d91e320200722001_750.html?chid_code=9c6d64&WT.mc_id=20210205zthgcsdx
為何要使用短鏈?先來看看短鏈能帶來哪些好處:
-
內容平臺上(如微博、Twitter、小紅書等),往往發文有長度限制,短鏈帶來的好處不言而喻: 網址短、美觀、便于發布、傳播,能寫更多正文了;
-
短信,如果超過字數限制,就會被拆成多條發送,如果短信量大也可以省下不少錢;
-
二維碼,本質上也是一串 URL,長鏈的話二維碼密集難識別,而短鏈則不會存在這種問題;
-
安全性,不想過于直觀的暴露原始網址;
-
統一經過平臺重定向,能對數據進行運營分析。
我們還是以上面的短鏈為例,原理如圖:
流程可以分為三步:
第一步:瀏覽器發起請求,請求地址:https://dx.10086.cn/looGDg
第二步: 短鏈服務器收到請求后,通過短鏈接地址找到原始長鏈接。返回http狀態碼是301或302,同時也通過 location 響應頭告知客戶端:你要訪問的其實是下面這個長網址:http://wap.zj.10086.cn/case/mould/produce/9b032ecfcb9b42f6a8fc411d160d91e320200722001_750.html?chid_code=9c6d64&WT.mc_id=20210205zthgcsdx
第三步: 客戶端收到短鏈服務器的應答后,再跳轉至長網址:http://wap.zj.10086.cn/case/mould/produce/9b032ecfcb9b42f6a8fc411d160d91e320200722001_750.html?chid_code=9c6d64&WT.mc_id=20210205zthgcsdx
實際瀏覽器中的網絡請求如下圖
?
這里簡單回顧一下http狀態碼301和302的區別:
-
301,代表 永久重定向,也就是說第一次請求拿到長鏈接后,下次瀏覽器再去請求短鏈的話,不會向短網址服務器請求了,而是直接從瀏覽器的緩存里拿,在 server 層面就無法獲取到短網址的點擊數了,如果這個鏈接剛好是某個活動需要統計點擊率,那結果只可能是0或1了。所以一般不采用 301。
-
302,代表 臨時重定向,也就是說每次去請求短鏈都會去請求短網址服務器,便于 server 統計點擊數。雖然用 302 會給 server 增加一點壓力,但是更符合業務需要,所以推薦使用 302。
短鏈服務需求分析:
功能性需求:
- 原始URL轉短鏈
- 訪問短鏈跳轉到原始URL
- 短URL訪問過期
- 短URL非法失效
- 自定義短鏈接
- 短鏈的批處理
- 訪問統計
- 支持B端多租戶
非功能性需求:
- 高可用:支持分布式服務下的高可用
- 高性能:無論是生成短鏈,還是訪問短鏈,服務都要支持高并發、低延時
- 安全性:短鏈不可被預測,避免接口被輪詢導致數據泄露等風險
讀寫估算、存儲估算、帶寬估算、內存估算、緩存估算、總體估算:
存儲預估:
讀寫預估:
假設這一百萬數據需要在一小時內發完,那么我們單機能承受負載可以這么來估算:
- 每秒寫請求:
1000000 / 1 hour* 60 min * 60 sec = 278(Req/S)
- 每秒讀請求(讀多寫少,我們按照讀寫100 : 1 來考慮):
278 * 100 = 27800 (Req/S)
緩存預估:
緩存這部分計算可以參照讀寫請求的預估值,考慮業務的集中訪問時間進行衡量。另外,如上文所提的場景,讀遠高于寫的請求可以考慮加內存緩存,命中率會非常的高,這樣對讀性能又是一個顯著提升。
短鏈長度預估:6位,可使用 短鏈 568億
詳細設計短鏈生成算法
設計短鏈生成算法,本質就是找到f(x),尋找“長”、“短”之間的映射關系,這就是短鏈算法的根本。
?
方案1:Hash 算法
首先,最容易想到的就是MD5、SHA等算法。
輸入的長 URL 經過 MD5 算法的處理,會輸出一串長度為 128 bit 的字符串。128 bit 的 MD5 通過 Base62的規則編碼(A-Za-z0-9),會生成22位的字符串。顯然22位還是太長了。那么如何拿到6位短鏈呢?
首先想到截取,假設按照轉換出來截取它的前六位或者后六位,兩個完全不一樣的長鏈轉換出來的字符它的前6位或者后6位一樣的概率還是很高的。就會導致上面的“關系”錯亂,兩個長鏈對應了一個短鏈上。
另外有同學會說,在發現沖突的時候加隨機或者加時間戳,或者加IP等等。方案改進可以降低沖突概率,但是還是會存在。如果沖突一直在,就要重復執行這段邏輯。
可以看出MD5這種方式不是很優雅,而且在效率上也不高。
方案2:自增序列算法
區別于Hash算法,全局自增ID方案的好處是不需要關心原始長鏈接。天然支持一對一這種映射關系。不會存在之前Hash方案中一對多這種問題。
所以初步的想法通過一個ID自增生成器,可以通過數據庫ID自增、zookeeper計數或者 redis的 incby或者自己實現一個自增計數器都行。程序收到請求后去拿一個ID,然后將這個ID通過Base62轉換成短鏈,然后插入這個映射關系。
但是方案2會存在以下幾個問題。
問題1:每次來一個請求,比如說長鏈是一樣的。那勢必也會生成一個ID。那如果有人刷接口或者重復提交,那很快ID資源將會耗盡。
問題2:如果是自增的ID,規律性太強,很容易被人預測,導致信息泄露。
該如何解決這些問題呢。
首先是問題1,可以通過對長鏈加唯一索引解決,但是會加大存儲空間,另一面因字段內容過多會導致數據庫page記錄減少,當發生插入或者刪除等操作很容易產生分頁,影響性能。所以可以考慮用 布隆過濾器(Bloom Filter),當長鏈不存在時程序才給分配。
問題2相對容易一點,可以增加一些隨機性,在規則上做一些操作。比如加上數據中心,機器IP等,而不是簡單的加一加二。
所以綜上考慮使用 Snowflake + Bloom Filter 來解決核心算法問題。篇幅有限,如果不清楚細節的可以自行深入了解下。
架構設計
?
整體架構如圖。自上而下,首先網絡層,在Nginx做讀寫域名分離,考慮到響應、安全等問題,創建、訪問統計、詳情等請求走內網域名,訪問短鏈跳轉走公網域名。
整個短鏈中心結構大體分為三層,系統安全、應用安全及業務處理。首先請求進入限流中心,規則基于服務流控、業務線流控及租戶維度流控,當系統發生異常時我們可動態調節系統流控,保證整體系統的穩定,提供能力。當某個業務線或者某個租戶出現異常流量或者被刷等情況之后,我們可以考慮對某個租戶限制訪問,限制該租戶的請求,避免連鎖反應,導致系統崩盤。安全中心將對進入的短鏈進行一些規則校驗,比如長度、字符內容等,如一些非法惡意的請求直接做攔截處理。
如果該請求是創建等接口,將會對傳入的Appkey和AppSecret進行鑒權校驗,如果校驗通過,基于短鏈生成算法,生成短鏈接,存儲到數據庫,完成數據主從集群備份,同時異步更新到Redis緩存集群并且加載到內存緩存,同時更新到過濾中心服務。如果該請求是訪問查詢請求,程序將先判斷該短鏈是否在布隆過濾器內。若存在,則先走內存緩存然后Redis最終到DB,中間存在則立即返回;若不存在,則直接認定為非法短鏈。所以過濾中心非常重要,是維穩下層中間件安全的核心能力,防止異常流量對緩存或者數據庫造成壓力,進而引起雪崩。
數據庫表結構設計
短鏈表設計核心字段如下:
保障系統穩定性作為一個基礎組件,必須要保證高并發的同時,還要考慮服務的穩定性及高可用。
首先是安全:
在服務上線之初,需要考慮幾點。接口分類上大體分成兩類,第一類是用戶可以訪問的短鏈接,另一類是用戶無需感知且不能被感知的比如創建、查看詳情、訪問統計等等。首先要做的就是做好網絡隔離,將用戶可以訪問的提供公網訪問,不可訪問的將網絡限制機房或者辦公網訪問等。其次,接入的業務方需要分配指定的Appkey和AppSercert,核心接口調用進行必要的簽名校驗。防止一些惡意攻擊流量對系統造成影響。
其次是限流:
為了讓系統更加的健壯,這個時候就要考慮一些限流策略。可以針對整個服務或者接口做一些限流策略,可以基于Guava的 RateLimiter或者在網關層做一些限制。防止業務流量飆升的時候,保證服務是穩定可用的。
最后就是防刷:
首先過濾掉一批非法請求,將傳入的短鏈進行正則檢驗,不滿足直接過濾。滿足校驗規則,通過布隆過濾器,如果外部請求某個短鏈不存在系統中,那直接過濾掉,避免一些惡意的請求進入到系統造成影響。短鏈需要考慮接入一些安全服務,對長鏈內容進行一些檢測,防止涉黃涉暴等內容發生,封禁之后影響整個域名的可用性。所以需要在設計之初,考慮快速拉黑失效短鏈的能力。
總結
本文詳細介紹了短鏈的設計方案,闡述了短鏈設計原理、容量評估、具體設計方案及穩定性等方面的內容。我們基于業務場景需求分析,針對如何設計一款基礎好用的短鏈服務這一話題進行了討論。筆者基于文中原理使用Go語言編寫了一套短鏈服務,在性能及穩定性上都有很強的表現。目前該服務已接入多個業務,線上運行穩定,逐步取代原先的單體服務。
想要開發一款基礎服務,在功能、性能和安全上都必須進行多方位考慮。文中簡要提到了 布隆過濾器、SnowFlake、Mysql 頁分裂等技術,有興趣的開發者們可以持續關注。
本文對短鏈服務設計做了詳細地剖析,旨在給大家提供短鏈設計思路。如果你正在設計或者考慮設計一款短鏈服務,希望本文對你有所幫助。
總結
以上是生活随笔為你收集整理的技术干货 | 高性能短链设计与实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 艾媒咨询:泛娱乐「体验共享」报告发布,网
- 下一篇: 技术干货 | 为高音质保驾护航 - 通信