范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

面试官如何设计一个高并发的短链接系统?

  1 Scenario 场景
  根据一个 long url 生成一个short url。
  如 http://www.javadaily.cn => http://bit.ly/1ULoQB6
  根据 short url 还原 long url,并跳转:
  需和面试官确认的问题:
  long url和short url必须一一对应吗?
  Short url长时间没人用,需要释放吗?  1.1 QPS 分析问日活,如微博100M  推算产生一条 tiny url 的 qps  假设每个用户平均每天 0.1(发10 条,有一条有链接) 条带 URL 的微博  平均写 QPS = 100M * 0.1 / 86400 = 100  峰值写 qps = 100 * 2 = 200  推算点击一条tiny url的 qps  假设每个用户平均点 1 个tiny url  平均写 QPS = 100M * 1 / 86400 = 1k  峰值读 qps = 1k * 2 = 2k  deduce 每天产生的新 URL 所占存储  100M * 0.1 = 10M 条  每条 URL 长度平均按 100 算,共 1G  1T 硬盘能用 3 年
  由2、3 分析可知,并不需要分布式或者 sharding,支持 2k QPS,一台 SSD MySQL 即可。  2 Service 服务 - 逻辑块聚类与接口设计
  该系统其实很简单,只需要有一个 service即可:URL Service。由于 tiny url只有一个 UrlService:  本身其实就是个小的独立应用  也无需关心其他任何业务功能  方法设计:
  UrlService.encode(long_url):编码方法
  UrlService.decode(long_url):解码方法
  访问端口设计,当前有如下两种常用主流风格:  GET / REST 风格
  Return a http redirect resonse  POST /data/shorten(不太推荐,不符合 REST 设计风格,但也有人在用)
  Return a short url
  那么,你们公司的短链系统是选择哪种服务设计呢?  3 Storage 数据存取(最能体现实践经验)select 选存储结构  scheme 细化数据表  3.1 SQL V.S NoSQL
  需要事务吗?No,nosql+1
  需要丰富的 sql query 吗?no,nosql+1
  想偷懒吗?tiny url需要写的代码不复杂,nosql+1
  qps高吗?2k,不高。sql+1
  scalability 要求多高?存储和 qps 都不高,单机都能搞定。sql+1  - sql 需要自己写代码来 scale - nosql,这些都帮你做了
  是否需要 sequential ID?取决于你的算法  sql 提供 auto_increment 的 sequencetial ID,即 1,2,3  nosql 的 ID 不是 sequential  3.2 算法
  long ur 转成一个 6 位的 short url。给出一个长网址,返回一个短网址。
  实现两个方法:  longToShort(url)  把一个长网址转换成一个以http://tiny.url/ 开头的短网址 shortToLong(url)  把一个短网址转换成一个长网址
  标准:  短网址的key的长度应为6 (不算域名和反斜杠)。可用字符只有  [a-zA-Z0-9] . 比如: abcD9E  任意两个长的url不会对应成同一个短url,反之亦然。
  用两个哈希表:  一个是短网址映射到长网址  一个是长网址映射到短网址
  短网址是固定的格式: "http://tiny.url/" + 6个字符, 字符可任意。
  为避免重复, 我们可以按照字典序依次使用, 或者在随机生成的基础上用一个集合来记录是否使用过。  使用哈希函数(不可行)
  如取 long url的 MD5 的最后 6 位:  快  难以设计一个无哈希冲突的哈希算法  随机生成 shortURL+DB去重
  随机取一个 6 位的 shortURL,若没使用过,就绑定到改 long url。  public String long2Short(String url) {   while(true) {     String shortURL = randomShortURL();     if (!databse.filter(shortURL=shortURL).exists()) {       database.create(shortURL=shortURL, longURL=url);       return shortURL;     }   }    }  public class TinyUrl {          public TinyUrl() {         long2Short = new HashMap();         short2Long = new HashMap();     }      /**      * @param url a long url      * @return a short url starts with http://tiny.url/      */     public String longToShort(String url) {         if (long2Short.containsKey(url)) {             return long2Short.get(url);         }          while (true) {             String shortURL = generateShortURL();             if (!short2Long.containsKey(shortURL)) {                 short2Long.put(shortURL, url);                 long2Short.put(url, shortURL);                 return shortURL;             }         }     }      /**      * @param url a short url starts with http://tiny.url/      * @return a long url      */     public String shortToLong(String url) {         if (!short2Long.containsKey(url)) {             return null;         }          return short2Long.get(url);     }      private String generateShortURL() {         String allowedChars = "0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ";          Random rand = new Random();         String shortURL = "http://tiny.url/";         for (int i = 0; i < 6; i++) {             int index = rand.nextInt(62);             shortURL += allowedChars.charAt(index);         }          return shortURL;     } }
  优点:实现简单
  缺点:生成短链接的速度,随着短链接越多而越慢
  关系型数据库表:只需Short key和 long url两列,并分别建立索引
  也可使用 nosql,但需要建立两张表:  根据 long 查询 short key=longurl 列=shorturl value=null or timestamp  根据 short 查询 long key=shorturl 列=longurl value=null or timestamp  进制转换 Base32(微博实现方案)
  Base62:  将 6 位 short url 看做一个 62 进制数(0-9,a-z,A-Z)  每个 short url 对应到一个整数  该整数对应 DB 表的主键
  6 位可表示的不同 URL:  5 位 = 62^5=0.9B= 9亿  6 位 = 62^6=57B= 570亿  7 位 = 62^7=3.5T= 35000亿
  优点:效率高
  缺点:强依赖于全局的自增 id  public class TinyUrl {     public static int GLOBAL_ID = 0;     private HashMap id2url = new HashMap();     private HashMap url2id = new HashMap();      private String getShortKey(String url) {         return url.substring("http://tiny.url/".length());     }      private int toBase62(char c) {         if (c >= "0" && c <= "9") {             return c - "0";         }         if (c >= "a" && c <= "z") {             return c - "a" + 10;         }         return c - "A" + 36;     }      private int shortKeytoID(String short_key) {         int id = 0;         for (int i = 0; i < short_key.length(); ++i) {             id = id * 62 + toBase62(short_key.charAt(i));         }         return id;     }      private String idToShortKey(int id) {         String chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";         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;     }      /**      * @param url a long url      * @return a short url starts with http://tiny.url/      */     public String longToShort(String url) {         if (url2id.containsKey(url)) {             return "http://tiny.url/" + idToShortKey(url2id.get(url));         }         GLOBAL_ID++;         url2id.put(url, GLOBAL_ID);         id2url.put(GLOBAL_ID, url);         return "http://tiny.url/" + idToShortKey(GLOBAL_ID);     }      /**      * @param url a short url starts with http://tiny.url/      * @return a long url      */     public String shortToLong(String url) {         String short_key = getShortKey(url);         int id = shortKeytoID(short_key);         return id2url.get(id);     } }
  因为要用到自增 id,所以只能用关系型 DB 表:
  id主键、long url(索引)  4 Scale
  如何提高响应速度,和直接打开原链接一样的效率。
  明确,这是个读多写少业务。  4.1 缓存提速(Cache Aside)
  缓存需存储两类数据:  long2short(生成新 short url 需要)  short2long(查询 short url 时需要)
  4.2 CDN
  利用地理位置信息提速。
  优化服务器访问速度:  不同地区,使用通不同 web 服务器  通过 dns 解析不同地区用户到不同服务器
  优化数据访问速度  使用中心化的 MySQL+分布式的 Redis  一个 MySQL 配多个 Redis,Redis 跨地区分布
  4.3 何时需要多台 DB 服务器
  cache 资源不够或命中率低
  写操作过多
  越来越多请求无法通过 cache 满足
  多台DB服务器可以优化什么?  解决存不下:存储  解决忙不过:qps
  那么 tiny url 的主要问题是啥?存储是没问题的,重点是 qps。那么,如何 sharding 呢?
  垂直拆分:将多张表分别分配给多台机器。对此不适用,只有两列,无法再拆分。
  横向拆分:
  若id、shortURL 做分片键:  long2short 查询时,只能广播给 N 台 db 都去查询  为何要查 long2short?避免重复创建呀  若不需要避免重复创建,则这样可行
  用 long url 做分片键:
  short2long 查询时,只能广播给 N 台 DB 查询。  4.3.1 分片键选择若一个 long 可对应多个 short使用 cache 缓存所有 long2short  在为一个 long url 创建 short url 时,若 cache miss,则创建新 short  若一个 long 只能对应一个 short若使用随机生成算法  两张表,一张存储 long2short,一张存储short2long  每个映射关系存两份,则能同时支持 long2short short2long 查询  若使用 base62 进制转换法  有个严重问题,多台机器之间如何维护一个全局自增的 id?  一般关系型DB只支持在一台机器上实现这台机器上全局自增的 id  4.4 全局自增 id4.4.1 专用一台 DB 做自增服务
  该 DB不存储真实数据,也不负责其他查询。
  为避免单点故障,可能需要多台 DB。  4.4.2 使用 zk
  但使用全局自增 id 不是解决 tiny url最佳方案。Generating a Distributed Sequence Number  4.5 基于 base62 的分片策略
  Hash(long_url)%62作为分片键
  并将 hash(long_url)%62直接放到 short url
  若原来的 short key 是 AB1234,则现在的 short key 是  hash(long_url) % 62 + AB1234  若 hash(long_url)%62=0,那就是0AB1234
  这样,就能同时通过 short、long 得到分片键。
  缺点:DB 的机器数目不能超过 62。
  所以,最后最佳架构:
  4.6 还能优化吗?
  web server 和 database 之间的通信。
  中心化的服务器集群和跨地域的 web server 之间通信较慢:如中国的 Server 需访问美国的 DB。
  为何不让中国的 Server 访问中国的 DB 呢?
  若数据重复写到中国 DB,如何解决一致性问题?很难解决!
  思考用户的习惯:  中国用户访问时,会被 DNS 分配中国的服务器  中国用户访问的网站一般都是中国的网站  所以可按网站的地域信息来 sharding  如何获得网站的地域信息?只需将用户常访问的网站汇总在一张表。  中国用户访问美国网站咋办?  就中国 server 访问美国 db,也不会慢太多  中访中是用户主流,优化系统就是针对主要需求
  于是,得到最终架构:
  还可以维护一份域名白名单,访问对应地域的 DB。  5 用户自定义短链接
  实现一个顾客短网址,使得顾客能创立他们自己的短网址。即你需要在前文基础上再实现一个  createCustom 。
  需实现三个方法:  long2Short(url)  把一个长网址转换成一个以http://tiny.url/ 开头的短网址 short2Long(url)  把一个短网址转换成一个长网址 createCustom(url, key)  设定一个长网址的短网址为 http://tiny.url/  + key
  注意:  long2Short  生成的短网址的key的长度应该等于6 (不算域名和反斜杠)。可以使用的字符只有 [a-zA-Z0-9] 。如: abcD9E  任意两个长的url不会对应成同一个短url,反之亦然  如果  createCustom  不能完成用户期望的设定, 那么应该返回 "error" , 反之如果成功将长网址与短网址对应,应该返回这个短网址 5.1 基于 Base62
  在URLTable里,直接新增一列custom_url记录对应的custom url是否可行?
  不可行!对于大部分数据,该列其实都为空,就会浪费存储空间。
  新增一个表,存储自定义 URL:CustomURLTable。
  创建自定义短链接:在 CustomURLTable 中查询和插入
  根据长链接创建普通短链接:  先查询CustomURLTable是否存在  再在URLTable查询和插入
  同前文一样,用两个哈希表处理长网址和短网址之间的相互映射关系。需额外处理的是用户设定的网址与已有冲突时,需返回 "error"。注意:若用户设定的和已有恰好相同,则同样应该返回短网址。  public class TinyUrl2 {     private HashMap s2l = new HashMap();     private HashMap l2s = new HashMap();     private int cnt = 0;     private final StringBuffer tinyUrl = new StringBuffer("http://tiny.url/");     private final String charset = "qwertyuiopasdfghjklzxcvbnm1234567890QWERTYUIOPASDFGHJKLZXCVBNM";          private String newShortUrl() {         StringBuffer res = new StringBuffer();         for (int i = 0, j = cnt; i < 6; i++, j /= 62)             res.append(charset.charAt(j % 62));         cnt++;         return tinyUrl + res.toString();     }          /*      * @param long_url: a long url      * @param key: a short key      * @return: a short url starts with http://tiny.url/      */     public String createCustom(String long_url, String key) {         String short_url = tinyUrl + key;         if (l2s.containsKey(long_url)) {             if (l2s.get(long_url).equals(short_url))                 return short_url;             else                 return "error";         }         if (s2l.containsKey(short_url))             return "error";         l2s.put(long_url, short_url);          s2l.put(short_url, long_url);         return short_url;     }      /*      * @param long_url: a long url      * @return: a short url starts with http://tiny.url/      */     public String longToShort(String long_url) {         if (l2s.containsKey(long_url))             return l2s.get(long_url);         String short_url = newShortUrl();          l2s.put(long_url, short_url);          s2l.put(short_url, long_url);         return short_url;      }      /*      * @param short_url: a short url starts with http://tiny.url/      * @return: a long url      */     public String shortToLong(String short_url) {         if (s2l.containsKey(short_url))             return s2l.get(short_url);         return "error";     } } 5.2 基于随机生成算法
  无需做任何改动,直接把custom url当short url创建即可!

岳阳君山精心打造文旅IP倾情回报父老乡亲艳阳高照,云淡风轻。12月10日,位于君山区钱粮湖镇分路口社区的逸馨生态度假村迎来了数百名游客,有帅哥靓妹成双成对骑行过来的,有一家周末自驾游的,他们在这里登山采摘烧烤美食打糍粑,丽江机场安检人文明热情服务保障旅客安全出行国际民航日丽江三义国际机场于1995年正式建成通航,分别于1998年和2008年先后两次开展改扩建,目前丽江三义国际机场运行等级为4D,国内候机楼3。3万,国际候机楼5300,跑道让孩子学习很难?能全科学习的喵喵机学习笔S1来助力相信不少父母为了孩子的学习,真心投入了不少精力和金钱,可能很多时候收效甚微,但我们依然毫不吝啬地一掷千金,毕竟这关乎着孩子的一生,所以作为父母的千万不能拖了后腿,该辅导的辅导,该买2022年末,看一看香港两位李氏富豪开发的新地标建筑,最新进展前言香港两位李氏富豪是指李嘉诚家族和李兆基家族,两都是世界级的富翁,资产超千亿。其中李兆基在19961997连续两年成为福布斯全球富豪榜第4名,这是至今为止全球华人拿到过的最高排名偏爱富豪的关之琳,不仅恋过男模,还和刘德华有一段往事文阅栀编辑阅栀2010年,关之琳在人民大会堂的慈善活动现场正式宣布息影,虽然香江美人隐退了,但是关于她多情的传说一直在江湖上飘荡。退休还不到一年,关之琳就在刘德华在演唱会上被揪了出北京毒株凶广州毒株弱,河南及三门峡是啥毒株?头条创作挑战赛近日,中国疾控中心病毒所所长许文波介绍,我国现阶段流行的新冠病毒以奥密克戎变异株BA。5的亚分支BA。5。2和BF。7为主,其中BA。5。2在我国31个省份流行BF。阳了个阳,不要再慌了,将贩卖焦虑的那些人都推走!目前这一场全民大阳,看来是锁死了,任何人都逃不过。真像人们说的,空气中都弥漫着奥密克戎的味道。药店被抢空了,酒精没货了,连花清瘟胶囊价格翻好几倍还缺货,甚至连黄桃罐头都一罐难求!甚月河小学教育集团劳动最光荣育人谱新章近日,2022年浙江省小学劳动教学活动评审及劳动新教材培训活动在月河小学教育集团湖东校区举行。本次培训通过线上线下的形式举办,全省各市区教育局劳动教育领导全省小学劳动教育专家指导委卡塔尔世界杯阿根廷对克罗地亚谁会胜出?我对足球的兴趣不大,但架不住平台近段时间总是推送与世界杯和足彩相关的文章给我,我也就顺带看了看这方面的资料。明日凌晨三点的四分之一比赛是阿根廷对克罗地亚,网上有很多大神说阿根廷后防中证财富夜读省到就是赚到云烟散,山依然。最近市场日渐回暖,不少投资者喜上眉梢摩拳擦掌,调仓换股,想要把握住反弹的行情。在这个过程中,除了要深入研究选好投资标的,如何以更低的成本获取收益也是一门重要的学问。马航机长故意坠机?新证据表明起落架已放下以使航班更快沉没马来西亚政府12月12日宣布,上个月在马达加斯加一名渔民家里发现了失踪MH370航班的起落架门耳轴门,它可能穿透了客机解体的发动机内部。专家表示,航班的起落架是放下的,这表明马航机
南季湾芦苇荡下午的天气稍微凉爽,我便骑着电动车车朝南季湾孤岛出发了。一路上除了茂盛的庄稼葱葱郁郁的绿树,便是道旁生机勃勃青青的小草了。缕缕乡风携着泥土清新的气息扑面而来,沁人心脾。当来到一个三10年后最富裕的24个城市为何柳州上榜南宁桂林无缘?最近社科院发布了10年后我国最富裕的24个城市,除了上海北京天津重庆苏州成都等一些知名度较高的城市外,柳州东营等名气较小的城市也榜上有名。有些广西的朋友不太明白,为什么柳州作为一个她50多岁出国,边打工边旅行,没花一分积蓄游玩16国,近百座城市这是走吧网推送的第263个与众不同的旅者故事本期嘉宾边写作边旅行肖女士,网名边写作边旅行,退休后随女儿前往澳洲,边打工边旅行,边写作边旅行,没有花一分钱积蓄,游玩了大洋洲亚洲欧洲等广西桂林留下一座明代王府,比故宫还早30年100元门票游客嫌贵桂林山水甲天下,阳朔山水甲桂林桂林是一个自然风光与人文历史合二为一一个历史文化名城,如果单一看了桂林山水风光不足以说了解桂林。如果到桂林旅游不到靖江王城等于没到桂林,当地流传一句名广东男篮又输了,放走两人酿苦果,马尚无能为力,杜锋面临抉择9596,广东男篮又输了,1分惜败山东男篮,遭遇两连败!四场比赛1胜3负,让他们排名倒数第二,仅高于四场全败的宁波男篮。真是没想到广东队也有这么一天,这应该是广东队近些年来最差的开CBA最新积分榜广东惜败山东,排名倒数第二,上海惨遭天津爆冷北京时间10月18日,CBA常规赛第四轮的比赛全部结束,在最后三场比赛中,上海99105爆冷不敌天津,广东9596惜败山东,四川7381不敌青岛,目前在最新的积分榜上,山东轰3连胜坎坷的女排奥运冠军丁霞妈妈,我的婚事您别牵挂头条创作挑战赛点击关注,每天都有名人故事感动您!丁霞2022年9月,世界女排锦标赛在荷兰波兰举行。10月13日,在与意大利队争进4强的生死战中,第一局中国女排以13比25落败。第二慕田峪长城巴士旅游攻略,发车点时间费用看这里一慕田峪长城巴士简介二慕田峪长城巴士的时间三慕田峪长城巴士的费用四慕田峪长城的游览攻略五慕田峪长城如何订票六慕田峪长城的用餐攻略慕田峪长城位于北京市怀柔区渤海镇慕田峪村,距离北京市游记太湖船游(一)沿水路游览太湖,我们都尚属第一次,这是无锡太湖游览区新开辟的旅游线路。七月十四日早晨,天空飘着几条雨丝,我们所坐的湖越号游艇从工运桥出发,进京杭运河,然后进梁溪,驶向太湖,此也谈弥勒宜居的理由那一潭青绿,惊艳了谁的目光下午2点左右,抵达弥勒火车站,乘公交车进市区,找到在网上预订的酒店住下时,已差不多3点。稍事休息,即外出前往湖泉生态园游玩。所住的酒店离湖泉生态园不远,步行十来分钟即可到达。刚进园如何正确快速地乘坐火车,避免尴尬,详细的流程来了首先,欢迎友友们的加入,在讲述这个问题的时候,我想问一下友友们,你们曾经是否向往过远方,向往过不一样的风景,向往过不曾见过的美好来?是否有那种冲动,那种用自己的心去感悟不一样风景的