接下啦, 打算研究一下短链接
1. 如何设计短链接系统
2. 短链接系统的盈利模式
3. 设计方案
今天开始第一部分: 如何设计短链接系统
1. 短链接有什么好处?
a. 微博推文, 每次限制只能有140个字,如果连接字符很多, 那么可编辑的文字就少了
b. 公司推广短信, 本来一条短信就可以搞定, 但是由于短信连接过长, 导致要发两条甚至3条. 假设1条短信1分钱, 3条就是3分钱, 假设有一百万用户, 发300万条短信,就是30000块钱, 你可以节省2w块.
2. 短链接跳转的基本原理
客户端-->发出短链接请求--> 302跳转到--->长连接
这里说一下status code. 301和302的区别
- 301: 代表永久重定向. 也就是第一次拿到请求重定向以后, 下次浏览器再次请求短链接的时候, 不会真正的请求短链接服务器, 而是从浏览器本地的缓存拿到长链接. 这样一来, 通过浏览器本地缓存可以减少服务器的压力, 但是也会带来新的问题, 我们如果想要统计这个入口链接可以带来多少的连接量. 使用301返回, 在server层就无法统计访问量. 所以一般不使用301
- 302: 代表临时重定向, 每次断连请求都会请求锻炼服务器, 除非在响应头标识了cache control expire ,这样浏览器才会缓存, 这样便于server统计点击数.虽然使用302给短链服务器增加一些压力, 但是数据异常重要的今天, 这点资源还是值得的. 所以,推荐使用302
3. 短链接生成的几种方案
比如这个短链接: http://n0i.cn/4dK5h
它是由域名http://n0i.cn/ 加上一串火星字符4dK5h构成
域名是固定的
火星字符是如何构成的呢?
我们可以使用hash生成, 可以是MD5, SHA. 这里, 我们不关心加密解密的难度. 我们更关心的是
1. 运算速度
2. 冲突概率
这里推荐google的hash算法, marmurhash. marmurhash算法是非加密hash函数. 适用于一般的hash检索操作. 与其他流行的hash函数相比, 对于规律性较强的key, marmurhash的随机分布特征表现更好. 非加密表示marmurhash比md5, sha这样的函数有更高的性能.
hash冲突了怎么办?
虽然marmurhash发生冲突的概率很低, 但还是要考虑, 一旦发生冲突, 怎么办?如何规避调.
短链接和长连接有一个对应关系, 保存这种对应关系有很多方案. 可以放在redis或者mysql. 如果放在mysql,我们的表结构应该是这样的.
id | 自增id |
surl | 短链接url |
lurl | 长链接url |
gmt_create | 时间 |
1. 长链接经过marmurhash算法, 得到短链接
2. 我们根据短链接去db中查询,是否存在这样的记录
3. 如果不存在, 就进行存储, 如果存在,说明已经有相关的记录了. 取出长串, 在加上一个固定的字符串,比如bywind. 进行marmurhash, 获得短链接地址
marmurhash(lurl + bywind)
4. 在对整个字符串进行第一步的操作. 如果这个字符串还是重复, 那就在拼接一个字符串.
5. 我们在最终获取长连接的时候, 把追加的字符串移除, 就得到原本的长连接了
以上操作, 一个操作需要两次查询, 如果出现高并发的情况, 是很容易产生性能瓶颈的. 如何优化呢?
1. 给短链接surl增加一个唯一性索引. 当长链接经过marmurhash得到短链接以后, 我们拿到长链接的映射, 去db里做检索, 如果没有找到就插入, 如果找到了, 就说明违反了唯一性索引. 这是在增加一个bywind字符串, 再次进行marmurhash处理, 然后保存到db.
增加唯一索引, 看上去效率有些低, 但marmurhash发生重复的概率是很低的 所以这种情况是可以接受的.
如果在高并发的情况下, 我们可以使用布隆过滤器来进行优化
长连接经过hash生成短链接, 然后在布隆过滤器中校验, 如果不存在,则保存到数据库, 如果存在, 加上bywind常量字符串, 再次校验. 直到不存在, 保存到数据库.
2. 使用自增序列的方式生成短链接 -- mysql自增主键
优点: 简单, 扩展方便
问题: 在高并发情况下, DB的写压力会过大, 这个时候怎么办呢? 如何优化?
这个时候, 我们可以设置一个专门的发号表. 每插入一条记录为短链id预留(主键id+1000-999) 到 (主键id*1000)的号段.
当长链接转短链接的请求, 达到某台服务器上的时候, 先看这台服务器上是否分配了短链接号段. 如果没有, 就往发号表里插入一条记录, 则这台机为短链分配的范围是start -- end. 如果当前分配的id>end, 说明这个区间段的id分配完了, 再往发号表里增加1条记录
3. 如何防止多次相同的长连接生成不同的短链接. 这样就要每次根据长链接查询db, 看是否有相关的记录, 一般做法是长链接加索引, 这样索引的空间会很多, 这时我们可以对长链接进行适当的压缩, 比如:md5. 在对长链接的md5加索引, 这样索引就会变得很小. 这样只需要根据常量的MD5去数据库里查重就可以了.
4. 数据量比较巨大的话, 后期还可以考虑分库分表.