您的位置:首页 > 其它

一看就懂系列之 高并发的短链接替换实现方案

2017-07-23 01:55 302 查看
转载请附上本文地址:http://blog.csdn.net/u011957758/article/details/75810039

前言

是的,相信只要是社交类的app,或多或少会涉及到描述。那么当存在链接的时候,我们不知道链接有多长,所以描述字段就没法准确的用varchar(140)了。

难道用text?好像不行,两方面原因:1.描述肯定要有限制的。2.dba不推荐text,效率你懂的。

所以对于高并发下的短链如何实现,做一个总结,用于日后留恋。

正文

简述

需求:

1.描述需要限制140字,链接按照固定的字数算比如10字。

2.收集链接,用于额外的分析。

思路:

1.需要拆分出链接,便于计算字数,同时描述里头必须以短链形式替换不知长度的链接,这样描述落地到数据库时候,设置比140字稍长一点的字段即可。

2.需要将链接进行收集并入库存储,方便取出分析。

3.考虑线上数据量超级大,需要进行分析将尽可能非必要的操作异步化,让短链实现时候基本处在内存中操作。

流程图



注意点

1.短链替换完后,先会在redis缓存中设定对应的链接,目的是防止数据积压导致异步任务延时进行,导致描述输出的时候,短链没地方进行替换。

2.先是{短链id},后面为[L]{短链id}[/L],目的是为了区分出链接是否有真的落到数据库了,并且这样可以更直观的在数据库的描述中识别出来。

3.如果量级不大,也可以用此套方案,将t2的实现直接在t1中完成,异步增加了复杂度与更多不确定因素。

4.存储链接的数据库字段需要设置为“CHARACTER SET utf8mb4 COLLATE utf8mb4_bin”,兼容emoji的表情。

重点实现

1.去除特定的字符标记

public function stripUrls($des) {
$des = preg_replace('/\[(U|L)\].+?\[\/(U|L)\]/i', '', $des);
$des = str_ireplace('', '', $des);
$des = str_ireplace('', '', $des);
$des = str_ireplace('[L]', '', $des);
$des = str_ireplace('[/L]', '', $des);
return $des;
}


2.匹配出链接

public function pregURL($content) {
$pattern = '/(http|https):\/\/[a-zA-Z0-9\-]+(\.[a-zA-Z0-9]+)+([-A-Z0-9a-z_\$\.\+\!\*\(\)\/\,\:;@&=\?~#%]*)*/i';
preg_match_all($pattern, $content, $result);

return $result;
}


3.按照长度对匹配出的链接重新排序

public function reorderUrlsByLen($urls) {
$shorted_urls = $short_by = array();
foreach ($urls as $url){
$shorted_urls[] = $url;
$short_by[] = strlen($url);
}
array_multisort($short_by , SORT_DESC ,$shorted_urls);
return $shorted_urls;
}


短链接的生成

方法1

算法原理

1.通过维护redis的一个key,进行自增id的维护。(64或32位的id生成器更佳)

2.将自增的id,转成62进制输出成短链识别。

3.解析的时候进行62进行反解,得到id后进行数据库查找出准确的链接(需要多一层mc缓存)

public function getShortUrl($url) {
return ''.$this->getIncrID($url).''
}

public function getIncrID() {
$key = $this->getIncrIDKey();
$id  = $this->redis->get($key);

//从999开始,防止太短了
if(!$id || !is_numeric($id)) {
$id = 999;
}

$next_id = $id + 1;
$this->redis->set($key, $next_id);

return dec2s2($id);
}

//十进制转62进制
function dec2s2($dec) {
$base = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$result = '';

do {
$result = $base[$dec % 62] . $result;
$dec = intval($dec / 62);
} while ($dec != 0);

return $result;
}

//62进制转十进制
function  s22dec($sixty_two) {
$base_map = array (
'0' => 0,
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
'6' => 6,
'7' => 7,
'8' => 8,
'9' => 9,
'a' => 10,
'b' => 11,
'c' => 12,
'd' => 13,
'e' => 14,
'f' => 15,
'g' => 16,
'h' => 17,
'i' => 18,
'j' => 19,
'k' => 20,
'l' => 21,
'm' => 22,
'n' => 23,
'o' => 24,
'p' => 25,
'q' => 26,
'r' => 27,
's' => 28,
't' => 29,
'u' => 30,
'v' => 31,
'w' => 32,
'x' => 33,
'y' => 34,
'z' => 35,
'A' => 36,
'B' => 37,
'C' => 38,
'D' => 39,
'E' => 40,
'F' => 41,
'G' => 42,
'H' => 43,
'I' => 44,
'J' => 45,
'K' => 46,
'L' => 47,
'M' => 48,
'N' => 49,
'O' => 50,
'P' => 51,
'Q' => 52,
'R' => 53,
'S' => 54,
'T' => 55,
'U' => 56,
'V' => 57,
'W' => 58,
'X' => 59,
'Y' => 60,
'Z' => 61,
);
$result = 0;
$len = strlen($sixty_two);

for ($n = 0; $n < $len; $n++) {
$result *= 62;
$result += $base_map[$sixty_two{$n}];
}

return $result;
}


优点:试用redis或id生成器产生自增id,直接解决了高并发下id的产出问题,并且进行数据存储的读取的时候,由于是数字的id所以sql查询效率更高。

不足:依赖资源。

方法2

来自博客:URL短网址生成算法原理和php实现案例

算法原理

1)将长网址md5生成32位签名串,分为4段, 每段8个字节;

2)对这四段循环处理, 取8个字节, 将他看成16进制串与0x3fffffff(30位1)与操作, 即超过30位的忽略处理;

3)这30位分成6段, 每5位的数字作为字母表的索引取得特定字符, 依次进行获得6位字符串;

4)总的md5串可以获得4个6位串; 取里面的任意一个就可作为这个长url的短url地址;

public function getShortUrl($url) {
return ''.$this->getShortUrlKey($url).''
}

function getShortUrlKey($input) {
$base32 = array (
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5'
);

$hex = md5($input);
$hexLen = strlen($hex);
$subHexLen = $hexLen / 8;
$output = array();

for ($i = 0; $i < $subHexLen; $i++) {
//把加密字符按照8位一组16进制与0x3FFFFFFF(30位1)进行位与运算
$subHex = substr ($hex, $i * 8, 8);
$int = 0x3FFFFFFF & (1 * ('0x'.$subHex));
$out = '';

for ($j = 0; $j < 6; $j++) {
//把得到的值与0x0000001F进行位与运算,取得字符数组chars索引
$val = 0x0000001F & $int;
$out .= $base32[$val];
$int = $int >> 5;
}
$output[] = $out;
}
return $output;
}
?>


优点:直接基于链接进行转换,不需要依赖于额外的资源

不足:存数据库的时候反查起来,由于非数字所以有优化空间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: