网上的实现思路问题
目前博客大部分都是使用的hash算法,通过算法把长地址进行压缩,转换为一个很短的字符串。这种实现有什么问题呢?大家都明白,一个短地址不可能完全匹配所有的长地址,MD5在大运算下都会产生碰撞,更何况很短的几个字符串(本人就是用这种方法,数据在一万多条的时候发生了碰撞)。后参考一遍博客,决定使用本文的方式进行实现,将短地址的碰撞的可能性降至更低,本文实现使用md5作为匹配字段,在日常应用中基本不会发生碰撞。
说明
目前项目存在一个缺陷,浏览器创建短地址,url后面的参数无法接收,暂时请大家使用ajax的方式创建,这样可以保存完整的url(包括参数)
欢迎大家在博客留言,共同讨论附加的功能
暂时代码为开源,等项目完善后开源
已经搭建公共的短地址服务器,供各位使用
接口文档
- 创建短地址:http://urlzz.cn/create
- 参数:url:原地址完整的URL
- 返回:短地址链接。例:http://urlzz.cn/wn
- 短地址使用:在浏览器输入http://urlzz.cn/wn短地址,即可转跳原地址
短地址实现思路
本博文参考网上的一些博客,以及实现思路,最终确定的一个实现方法
- 生成:
- 长url进行md5加密,获得64位字符串
- 将加密串和原地址写入数据库,并获得自增id
- 将id的十进制数字转为62位进制字符串,得到短地址key
- 将key作为标识,组合短地址域名前缀,返回短地址
- 查询:
- 将key转回10进制
- 根据id进行查询
测试用到的工具类性能
-
md5加密性能
- 性能 1000000/秒 (测试环境,mac pro 15.5 2015 i7 16G)
- 数据长度几乎无影响,1-100个字符,1000000/秒
- 数据长度几乎无影响,100-200个字符,800000/秒
- 数据长度几乎无影响,200-400个字符,500000/秒
-
10进制转62进制
- 性能:20000000/秒 (测试环境,mac pro 15.5 2015 i7 16G)
- 数据大小,几乎对性能无影响(1000000000000L)(转换结果为:hBxM5A4)
-
62进制转10进制
- 性能:5000000/秒 (测试环境,mac pro 15.5 2015 i7 16G)
- 数据大小,几乎对性能无影响(hBxM5A4)(转换结果为:1000000000000)
通过测试得出,最终的性能瓶颈还是在数据库
未来考虑的优化方案
- 查询使用redis缓存
- 布隆过滤器过滤无效key
- 插入使用redis暂存,使用mq做削峰填谷(需要保证服务器的可靠性)
- 做限流,禁止同一台设备短时间大批量创建短地址
NGINX跨域设置
# 指定允许跨域的方法,*代表所有
add_header Access-Control-Allow-Methods *;
# 预检命令的缓存,如果不缓存每次会发送两次请求
add_header Access-Control-Max-Age 3600;
# 带cookie请求需要加上这个字段,并设置为true
add_header Access-Control-Allow-Credentials true;
# 表示允许这个域跨域调用(客户端发送请求的域名和端口)
# $http_origin动态获取请求客户端请求的域 不用*的原因是带cookie的请求不支持*号
add_header Access-Control-Allow-Origin $http_origin;
# 表示请求头的字段 动态获取
add_header Access-Control-Allow-Headers
$http_access_control_request_headers;
# OPTIONS预检命令,预检命令通过时才发送请求
# 检查请求的类型是不是预检命令
if ($request_method = OPTIONS){
return 200;
}
前端代码
前端代码可直接执行,后台nginx做了跨域处理
请注意,为了项目更高的并发,没有做任何多余的封装,所以短地址返回的只要一个字符串,ajax接收时,dataType要设置为text
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>短地址生成</title>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
</head>
<body>
</body>
<script type="text/javascript">
$(function(){
$.ajax({
type: 'get',
url: "http://urlzz.cn/create",
data: {"url": "http://www.byshop.ren?test=test&test1=test1"},
dataType: 'text',
timeout: 60000,
success: function(res) {
console.log(res)
}
})
})
</script>
</html>