很久没更新了,加入了创业公司,从无到有的构建一套产品,从一开始的码框架到现在思考如何优化产品架构,适应更多的弹性需求和更大的数据量。时间真的是不够用,几乎快半年没有更新博客。近期产品慢慢走上正轨,又有小伙伴加入,所以抽出点时间总结一下这小半年内遇到的坑和走过的路。
说一说最近做的一个短链服务,短链服务其实很简单,其实就是一张表或者说是一个map:
+——-+———————–+
| 短链 | 长链 |
+——-+———————–+
| 7Y65s | https://www.google.com |
+——-+———————–+
就是这样一个结构,当用户访问 your-domain/7Y65s, 去表里查询一下对应的长链,301到该链接就可以了。
优化
基本的思路确定后,我们一点一点来优化。
首先分析大量查询肯定会出现在通过短链找长链这段逻辑中,如果用数据库肯定影响效率,缓存势在必行,而且一旦短链生成基本是不会变的,所以也不存在失效问题(这里可能会有个批量Archive的处理)。在我的项目中,我选择了redis作为缓存,反正是key-value的其他缓存组件肯定也能做。选用redis的原因是还可以用INCR来统计访问量。
1 | redisTemplate.opsForHash().put("short-urls:" + slug, "long_url", url); |
查询这一侧做完,到了生成短链这一块,这里实际上是刚刚说的那张表的create操作。这里有个基本逻辑是:当一个长链还没有短链的时候,我们生成它并返回,如果已经存在,直接获取返回。
生成的算法直接贴代码:
1 | package io.naza.urlshortener.generator; |
项目中按照长链生成一个固定长度为6位的短链接,只要长链是一样的,那么每次生成的短链也一样。
考虑到每次生成短链前要查询一下长链是不是存在,继续加一个小缓存,这次反过来,长链作key,短链做value。
1 | redisTemplate.opsForHash().put("short-urls", url, slug); |
尾声
用比较简单的方式完成一个短链接服务,在做短链跳转的过程中可以分析用户的各类行为,比如操作系统,浏览器版本,地域等等。最后说两点要注意的:
- redis毕竟是作为缓存使用的,建议数据还是要落一次在DB,比如在生成短链时,写入到DB一份。这样当redis挂了,还可以从DB中全量恢复。
- 对于长时间没有PV的短链,比如超过1年没有PV,需要做批量清理,一般一个月一次就可以了。