业务场景
简单分析一下短链接的业务场景。参照百度短链接http://dwz.cn/ 。
- 根据长链接生成一个短链接。
- 根据短链接解析出长链接。
简单实现
如何实现这个功能呢?也许你会考虑实现一个算法,将长链接转成短链接,实现长短的一一对应。然后再实现逆运算,将短链接换算回长链接。当然这种算法是不可能存在的。如果有那你就发现了世界上最牛的压缩算法了。
其实短链接的实现并没有一个固定的算法,主要的原理就是把长链接通过一定的规则得到一个短链接,然后把长链接和短链接的关系记录在数据库中(你可以使用关系型数据库或者非关系型数据库NoSql)。当用户访问短链接时,短链接服务根据短链接查找到对应的长链接,然后进行重定向。
那么我们通过什么规则来生成短链接呢?你可以通过发号策略,给每一个过来的长地址,发一个号即可,你可以用分布式key-value系统做发号器或者利用mysql的自增主键ID实现甚至你可以用NoSql实现,这都可以。这里我使用的是mysql的自增主键ID实现的。
根据上边的原理我们可以设计如下表结构:
CREATE TABLE IF NOT EXISTS `shortlink` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主键ID',
`short_link` varchar(30) NOT NULL COMMENT '短链接内容',
`long_link` varchar(255) NOT NULL COMMENT '长链接内容',
`long_link_sign` char(32) NOT NULL COMMENT '长链接MD5加密后的字符串',
`visit_count` int(11) NOT NULL DEFAULT '0' COMMENT '访问次数',
`created_at` datetime NOT NULL COMMENT '创建时间',
`last_visit_at` datetime NOT NULL COMMENT '最后访问时间',
PRIMARY KEY (`id`),
UNIQUE KEY `long_link_sign` (`long_link_sign`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
生成短链接的逻辑就是:
- 判断是否为合法的长链接地址。
- 把长链接做md5加密。
- 根据长链接加密串查询一下是否已经生成过短链接,如果有则直接返回短链接。
- 如果不存在则把长链接、长链接加密串插入数据库并返回自增主键ID。
- 把自增主键ID更新到short_link字段作为短链接的值。
分库分表实现
当短链接特别多或者并发量高的时候单个表已经不能承受我们的业务了。单个表或者单个数据库的数据存储能力和并发能力都是有限的。这个时候就我们要考虑分库分表了。
短链接分库分表需要考虑的几个问题。
- 怎么根据长链接找到需要查询和插入的数据库和表?
- 怎么根据短链接找到需要查询的数据库和表?
问题一我们可以根据长链接生成的md5值通过某种算法算出所在的数据库和数据表。
问题二当我们写入当前长链接对应的短链接的时候可以把数据库位和数据表位组合到生成的短链接中。下图是短链接字符串的组合方式。
根据上述方式,假设我们用一位数据库位和一位数据表位,而数据库和数据表位由0123456789abcdefghijklmnopqrstuvwxyz字符表示那么一共可以组成36个数据库,每个数据库中有36张表,一共可以组成1296张短链接表。假设每张表有1000万条数据,则可以支撑129亿条短链接数据。当然你也可以用其他组合支撑更大的数据量。
代码实现大致如下:
<?php
/**
* Created by PhpStorm.
* User: duxiaokong
* Date: 2016/08/24
*/
use Cache;
use Redis;
class Shortlink
{
protected $table = 'shortlink';
/**
* 根据长链接生成短链接
*
* @param string $long_link 长链接
* @return bool|string
*/
public function createShortLink($long_link)
{
$long_link = trim($long_link);
//判断长链接是否为合法的url
$parts = parse_url($long_link);
if (!isset($parts['scheme']) || !isset($parts[