基于Node.js的短链接系统

前言

迫于业务需求和某些限制,不得已需要造一个轮子短链接系统。该类系统目前市面上有开源解决方案YOURLS,不过该系统是PHP版本,考虑后期维护的成本,还是决定自己开发。

目前业务需求有:

  1. 长链接转换为短链接
  2. 自定义短链接
  3. 短链接访问量统计

技术

后端:Egg.js + Oracle + redis

前端:暂无(该系统直接输出API,链接创建等操作在其他系统进行)

实现

长链接转换为短链接

这是短链接系统的基本需求,考虑到具体业务需求,长链接和短链接并非一一对应的关系,也就是同一个长链接每次转换都会生成不同的短链接。

数据库中每个链接有5个关键字段:

  1. 短链接前缀(我司目前有不止一个域名)

  2. 短链接ID(自增)

  3. 自定义链接(用户自行填写)

  4. hash(根据ID转换得到)

  5. PV(链接访问量)

  6. STATUS(链接状态,启用/禁用)

在Oracle数据库中创建自增ID,给每一个长链接分配一个ID,然后将ID由10进制转换为62进制得到hash。此时,由于自定义链接的存在,所以需要在数据库中查询该hash值是否和已存在的自定义链接冲突。如果冲突,那么ID继续自增,重新计算hash,直到不再冲突。

注:

  • 如果考虑到保密因素,可以将0-9a-zA-Z顺序打乱。

  • 如果考虑到0Oo1I不易区分,可以把这些字母去掉。

  • 如果不是商用服务,使用6位或者8位数字字母随机编码也是可行的。

自定义短链接

自定义短链接需要考虑的问题就是用户自定义的链接和现有的hash冲突。

解决步骤:

  1. 首先获取当前链接的数字ID,并转换为62进制,比较hash和自定义链接是否一致,在数据库中查询该hash是否和已有的自定义链接冲突。

  2. 在数据库中搜索该自定义链接是否和现有hash冲突,如果冲突,则返回创建失败。

使用redis对链接进行缓存

尽管自定义链接和hash不冲突,都可以作为唯一ID,但是考虑到后期数据统计的唯一性和准确性,还是使用hash作为链接的标识。

在redis中创建哈希表URL_lIST,通过hset将已访问的链接所有数据存入redis,创建哈希表PERSONALIZED_URL_LIST,将自定义链接和对应的hash存入,利用redis的incr给每一个链接创建一个计数器,用于统计PV。

当用户通过链接http://xxx.xxx/abc访问时,首先以在URL_LIST中查询是否存在hash值为abc的信息(情况1),如果没有,那么在PERSONALIZED_URL_LIST查询是否存在值为abc的个性化链接(情况2),如果没有,那么直接到数据库查询数据。

针对情况2,如果查到数据,那么再到URL_LIST中查询对应的数据。

由于现实环境的复杂性,可能存在的情况是,PERSONALIZED_URL_LIST里存在该数据但是URL_LIST中不存在,那么还需要到数据库里查询。不过这些都是同步操作顺序进行,原则上不需要单独处理。

短链接数据统计

初期考虑到后面有数据可视化的需求,希望直接上ELK,解决数据可视化的同时也解决数据统计的问题。不过由于ELK的知识有限,日志传输到ELK后丢失严重,该方案暂时搁置。

由于短链接系统有多节点多线程,所以需要建设一个独立于短链接系统的短链接统计系统,主要工作就是完成数据统计的定时任务。

前面提到利用redis的incr给每一个链接创建一个计数器,这个计数器维护的是当前链接的增量PV。

定时任务的工作就是定时获取URL_LSIT中存在的链接,查找链接对应的PV增量,如果增量大于零,那么将URL_LIST中存在的该链接的PV值与PV增量相加,将PV增量置零,更新URL_LSIT和数据库中的数据。

TODO

  • 基于ELK的数据可视化
  • 链接禁用和启用控制