scenario:
分享链接长度过长,字数限制
google url shortener, bitly
根据long url生成一个short url
根据short url还原long url。访问http://bit.ly/跳转到
确认的问题:
long url和short url之间必须是一一对应的关系吗
short url长时间没人用需要释放吗?X
QPS+storage:
QPS:微博日活跃用户100M,average write qps = 100M * 0.1/86400 ~ 100, peak 200
average read qps = 100M * 1 / 86400 ~1k peak 2k
2k QPS一台ssd支持的mysql
推算每天产生新的url所占存储: 100M*0.1 ~10M条,每一条url长度平均100算,共1G, 1T的硬盘可以用3年
service:
TinyUrl只有一个UrlService
函数设计:
UrlService.encode(long_url)
UrlService.decode(short_url)
访问端口设计:
GET/<short_url>
return a http redirect response
POST/data/shorten
data = {url:http://xxx}
return a short url
storage:
select选存储结构
schema细化数据表
sql or nosql
- 是否支持transaction x nosql+1
- 是否需要sql query x nosql+1
- 是否想偷懒 x nosql+1
- 2kQPS, cache优化 sql+1
- scaliability 存储和qps要求不高,单机可以搞定 sql+1
- sequential id 取决于用什么算法,sql提供
算法是什么?
算法1:hash function
long url的MD5的最后6位, 有冲突
算法2:随机生成shorturl + 数据库去重
随机一个6位url,如果没被用过,就绑定longurl。优点:实现简单。缺点:生成速度随着短地址越来越多变得越来越慢。
算法3: 进制转换base62
base62:
将6位的short url看作一个62进制数(0-9,a-z, A-Z)
每个short url对应到一个整数
该整数对应数据库表的primary key - sequential id - id to short url
6位可以表示的不同的url:62^6 = 57B = 570亿
int shortURLtoID(String shortURL) {
int id = 0;
for (int i = 0; i < shortURL.length(); i++) {
id = id * 62 + toBase62(shortURL.charAt(i));
}
return id;
}
String idToShortURL(int id) {
String chars = "0123..9abcd..zABCD..Z";
String short_url = "";
while (id > 0) {
short_url = chars.charAt(id % 62) + short_url;
id = id / 62;
}
while (short_url.length() < 6) {
short_url = "0" + short_url;
}
return short_url;
}
优点:效率高,缺点:依赖于全局的自增id
随机生成🆚禁止转换
基于随机生成:选用nosql,cassandra, 需要建立两张表(大多数nosql不支持多重索引multi-index)
第一张表:根据long查short
row_key=longUrl, column_key=shortUrl, value=null or timestamp
第二张表:根据short查long
row_key=longUrl, column_key=shortUrl, value=null or timestamp
对于禁止转换:
需要用到自增id,只能用sql型数据库
id longUrl(inded = true)
shortUrl可以不存储在表单里,因为可以根据id来进行换算。
scale:
how to reduce response time?
读多写少
利用cache aside
缓存里需要存两类数据: long to short, short to long
利用地理位置信息提速
优化服务器访问速度:不同地区,使用不同的web服务器,通过dns解析不同地区的用户到不同的服务器
优化数据访问速度:使用centrailized mysql + distributed memcache。一个mysql配多个memcached,memcahced跨地区分布
usa 分配不同的ip地址
client ->DNS->web server<->memcached(hit rate高)
<---
||
shared db(比较快)
||
cn client ->DNS->web server<->memcached
<---
不适用于用户1次请求会产生多次数据库需求。不如访问远端的web server(延迟1次),web server和db不会延迟。
How to scale? 分布式架构
什么时候需要多台数据库服务器?cache资源不够(hit rate低),写操作越来越多(没法通过cache优化)
增加多台数据库服务器的好处:解决存不下-storage,解决忙不过-QPS。
怎么拆分数据将数据分配到多台服务器
vertical sharding: 将多张数据表分别分配给多台机器。
只有两个column不适用
horizontal sharding:
用id/shortUrl做sharding key: long to short的时候为了查重,广播给n台数据库查询
用longUrl做sharding key: short to long查询时,广播给n台数据库查询
如果一个long可以对应多个short:
使用cache缓存所有的long to short
创建short url时候,如果cache miss则去之介创建新的short url
如果一个long只能对应一个short:
随机生成算法: 两张表单一张long to short, 一张short to long。
base62进制转换法:多台机器之间如何维护一个全局自增的id??一般mysql只支持一台机器实现全局自增id。专门一台数据库只负责自增id服务。不存储真实数据。避免single point failure 可能需要多台数据库(master slave) 另一种方法用zookeeper
使用hash(long_url) % 62 作为sharding key, 并放到short url(7位)。可以同时通过short_url和long_url得到sharding key。
usa 分配不同的ip地址
client ->DNS->web server<->memcached(hit rate高)
<---
||
shared db0 shared db1 shared db2 shared db3
||
cn client ->DNS->web server<->memcached
<---
进一步优化:
web server与db之间的通信。centralized db set中心化的服务器集群与跨地域的web server之间通信较慢。
中国用户一般访问中国的网站。可以按照地域信息进行sharding。