摘#8195;要:本文介紹將資源地址轉(zhuǎn)換成6位不重復(fù)的短地址,在高并發(fā)情況下的海量數(shù)據(jù)存儲(chǔ)及高速讀寫(xiě)的實(shí)現(xiàn)方案。
關(guān)鍵詞:二維碼#8195;短地址#8195;實(shí)現(xiàn)方案
一、背景分析
二維碼的出現(xiàn)使資源傳輸由原來(lái)的USB拷貝轉(zhuǎn)變?yōu)槎S碼掃描訪問(wèn)或下載。為下載資源提供短地址服務(wù),需將短地址生成二維碼。資源數(shù)據(jù)量預(yù)計(jì)可達(dá)10億級(jí)別,日新增數(shù)據(jù)1000萬(wàn)左右,每秒并發(fā)訪問(wèn)數(shù)預(yù)計(jì)2000個(gè)連接,響應(yīng)時(shí)間在0.1秒以?xún)?nèi)。
二、基本原理
1.將原始地址轉(zhuǎn)換為短地址
2.將短地址轉(zhuǎn)換為原始地址
3.關(guān)鍵問(wèn)題
將原始地址轉(zhuǎn)換為不重復(fù)的6位地址標(biāo)志,海量數(shù)據(jù)的高并發(fā)讀寫(xiě)。
三、項(xiàng)目實(shí)現(xiàn)
1.地址實(shí)現(xiàn)方案
實(shí)現(xiàn)短地址服務(wù),首先要將海量的鏈接數(shù)據(jù)轉(zhuǎn)化為不重復(fù)的6位字符。
(1)哈希算法。哈希算法相對(duì)簡(jiǎn)單,具體算法如下:
①將原地址md5轉(zhuǎn)換成32位哈希碼,分為4段,每段8字節(jié)。
②對(duì)這四段地址進(jìn)行循環(huán)處理,取8個(gè)字節(jié),將其看成16進(jìn)制串與0x3fffffff(30位1)與操作,即超過(guò)30位的忽略處理。
③將30位生成6段,每5位數(shù)字作為字母表在索引取得特定字符,依次進(jìn)行獲取6位字符串。
④總的md5串可以獲得4個(gè)6位串,取任意一個(gè)就可作為這個(gè)長(zhǎng)url的短url地址。
這種方法實(shí)現(xiàn)起來(lái)簡(jiǎn)單,但是有較高的重復(fù)度。
(2)62位字符表示。把數(shù)字和字符組合成一定的映射,就可以產(chǎn)生唯一的字符串,再利用洗牌算法,把原字符串打亂后保存,對(duì)應(yīng)位置的組合字符串就會(huì)是無(wú)序的組合。
2.大數(shù)據(jù)存儲(chǔ)解決方案
在本項(xiàng)目中,主要存儲(chǔ)數(shù)據(jù)有資源下載地址及引用頁(yè)地址,預(yù)估資源下載地址長(zhǎng)度為150個(gè)字符,引用頁(yè)地址長(zhǎng)度為50字符,兩者存起來(lái)共200字符,再加上數(shù)據(jù)庫(kù)自身結(jié)構(gòu)占用的空間及其他信息,如時(shí)間、ID等,存儲(chǔ)一條數(shù)據(jù)最少需要250個(gè)字節(jié)。從當(dāng)前訪問(wèn)量來(lái)看,預(yù)計(jì)數(shù)據(jù)將達(dá)到10億條。
總數(shù)據(jù)量=250 * 10^9 /(1024*1024*1024)= 230G
當(dāng)前采用的是mysql架構(gòu), 10億條數(shù)據(jù)遠(yuǎn)遠(yuǎn)超過(guò)了其處理能力。因此要對(duì)數(shù)據(jù)庫(kù)進(jìn)行分庫(kù)分表,將表大小限定為10萬(wàn)條數(shù)據(jù),每個(gè)數(shù)據(jù)庫(kù)1000張表,數(shù)據(jù)庫(kù)隨著數(shù)據(jù)的增長(zhǎng)而擴(kuò)展,表中的ID進(jìn)行自增長(zhǎng),通過(guò)數(shù)據(jù)庫(kù)ID、表ID、數(shù)據(jù)ID三者就可以唯一確定條數(shù)據(jù),將這個(gè)值轉(zhuǎn)換成62進(jìn)制就得出了唯一的短鏈接地址。
合成ID算法代碼:
($database_id*self::database_tables*self::table_rows)+$row_id+ ($table_id*self::table_rows);
每個(gè)數(shù)據(jù)庫(kù)將存儲(chǔ)1000*100000=1億條數(shù)據(jù),數(shù)據(jù)將分布在10臺(tái)機(jī)器上,10臺(tái)機(jī)器將分解高峰階段的每秒2000個(gè)并發(fā)讀寫(xiě)操作。這種算法在初期可能會(huì)對(duì)單臺(tái)機(jī)器造成過(guò)載,可采用逐步加壓的方式,當(dāng)數(shù)據(jù)庫(kù)服務(wù)器增多后可全部開(kāi)放。
3.高并發(fā)解決方案
應(yīng)對(duì)每秒2000次的并發(fā)訪問(wèn)需要服務(wù)器具有快速的讀寫(xiě)及負(fù)載均衡能力,主要需要解決兩方面的問(wèn)題:用戶(hù)在創(chuàng)建短地址時(shí),需確認(rèn)該資源沒(méi)有創(chuàng)建過(guò);當(dāng)用戶(hù)在訪問(wèn)一個(gè)短地址時(shí),服務(wù)器需快速響應(yīng)。從數(shù)據(jù)庫(kù)直接讀取無(wú)法滿(mǎn)足速度需求,同時(shí)會(huì)造成服務(wù)器過(guò)載導(dǎo)致系統(tǒng)崩潰。因此,需要將資源url放到內(nèi)存中,使用內(nèi)快進(jìn)行快速讀取。
4.關(guān)鍵問(wèn)題解決方式
(1)問(wèn)題一解決方案。由于數(shù)據(jù)是先有ID后有短地址,無(wú)法通過(guò)資源地址反查到短地址,因此,需要使用一個(gè)內(nèi)存映射,將資源與短地址(數(shù)據(jù)ID)聯(lián)系起來(lái)。
操作流程:原始地址→16字節(jié)長(zhǎng)度的原始二進(jìn)制md5→從redis中查找是否存在數(shù)據(jù)ID→從內(nèi)存緩存或數(shù)據(jù)庫(kù)中取出數(shù)據(jù)→判斷數(shù)據(jù)庫(kù)中的地址是否與原地址相同→不同則插入數(shù)據(jù)庫(kù)中,建立16字節(jié)長(zhǎng)度原始二進(jìn)制md5與數(shù)據(jù)ID建立聯(lián)系存入redis中。
(2)問(wèn)題二解決方案。將熱數(shù)據(jù)放入緩存中,減輕數(shù)據(jù)庫(kù)負(fù)載,限制一天過(guò)期時(shí)間,可以防止內(nèi)存使用過(guò)大。
操作流程:短地址→查找內(nèi)存→未找到將短址轉(zhuǎn)為ID→從數(shù)據(jù)庫(kù)中查找→存入緩存→返回?cái)?shù)據(jù)。
四、小結(jié)
短地址服務(wù)是一個(gè)比較復(fù)雜的項(xiàng)目,生成短6位短碼是關(guān)鍵點(diǎn),采用數(shù)據(jù)ID遞增進(jìn)行62位轉(zhuǎn)換的方式,可簡(jiǎn)單有效地實(shí)現(xiàn)需求。
(作者單位:廣東省高級(jí)技工學(xué)校 )