短链接跳转功能(缓存击穿)

短链接跳转功能(缓存击穿)

功能描述

实现短链接跳转功能,通过短链接映射到原始链接并完成页面重定向,同时处理缓存与并发问题,避免缓存击穿。


功能流程

  1. 获取完整短链接 URL:

    • 从请求中获取 shortUri 和服务器域名,拼接成完整的短链接 URL,例如:serverName/shortUri
  2. 查询缓存:

    • 从 Redis 缓存中获取短链接对应的原始链接。
    • 如果缓存中存在,则直接重定向到原始链接。
  3. 处理缓存击穿:

    • 如果缓存中不存在,通过 Redisson 分布式锁控制并发查询,避免缓存击穿。
    • 加锁后再检查缓存,防止重复查询。
  4. 查询数据库:

    • 如果缓存仍不存在,从数据库查询短链接对应的原始链接。
    • 查询逻辑:
      • 检查短链接是否存在,且状态有效(未删除且启用)。
      • 如果短链接存在,将原始链接存入缓存,并重定向。
  5. 处理不存在的短链接:

    • 如果数据库中也不存在对应的短链接,可以根据业务需求进行封控或提示。
  6. 释放锁:

    • 最终释放分布式锁,确保并发情况下锁资源正常回收。

核心代码逻辑

1. 获取完整短链接

1
2
String serverName = request.getServerName();
String fullShortUrl = serverName + "/" + shortUri;

2. 查询缓存

1
2
3
4
5
String originalLink = stringRedisTemplate.opsForValue().get(String.format(GOTO_SHORT_LINK_KEY, fullShortUrl));
if (StrUtil.isNotBlank(originalLink)) {
((HttpServletResponse) response).sendRedirect(originalLink);
return;
}

3. 加锁避免缓存击穿

1
2
3
4
5
6
7
8
9
10
11
12
13
RLock lock = redissonClient.getLock(String.format("LOCK_GOTO_SHORT_LINK_KEY", fullShortUrl));
lock.lock();
try {
// 再次检查缓存
originalLink = stringRedisTemplate.opsForValue().get(String.format(GOTO_SHORT_LINK_KEY, fullShortUrl));
if (StrUtil.isNotBlank(originalLink)) {
((HttpServletResponse) response).sendRedirect(originalLink);
return;
}
// 数据库查询逻辑
} finally {
lock.unlock();
}

4. 查询数据库

1
2
3
4
5
6
7
8
9
10
11
12
LambdaQueryWrapper<ShortLinkDO> shortLinkDOLambdaQueryWrapper = Wrappers.lambdaQuery(ShortLinkDO.class)
.eq(ShortLinkDO::getGid, shortLinkGotoDO.getGid())
.eq(ShortLinkDO::getFullShortUrl, fullShortUrl)
.eq(ShortLinkDO::getDelFlag, 0)
.eq(ShortLinkDO::getEnableStatus, 0);

ShortLinkDO shortLinkDO = baseMapper.selectOne(shortLinkDOLambdaQueryWrapper);

if (shortLinkDO != null) {
stringRedisTemplate.opsForValue().set(GOTO_SHORT_LINK_KEY, shortLinkDO.getOriginUrl());
((HttpServletResponse) response).sendRedirect(shortLinkDO.getOriginUrl());
}

输入与输出

输入

  • 短链接部分 URI (shortUri)。
  • 服务器域名 (serverName)。

输出

  • 重定向 到原始链接 URL。
  • 如果短链接不存在,根据业务需求返回封控信息或错误提示。

优点

  1. 高效性:

    • 利用 Redis 缓存显著提升查询效率。
    • 避免每次跳转都直接访问数据库。
  2. 并发控制:

    • 使用 Redisson 分布式锁有效防止缓存击穿。
  3. 灵活性:

    • 支持短链接状态的多条件校验(如删除标记、启用状态)。
  4. 扩展性:

    • 代码结构清晰,方便后续扩展其他功能(如日志记录、访问统计等)。

优化建议

  1. 缓存持久化:

    • 设置 Redis 缓存的过期时间,减少无用缓存占用。
  2. 增加日志:

    • 对短链接的访问记录日志,便于监控和审计。
  3. 异常处理:

    • 增加对短链接不存在或数据库查询异常的处理,返回友好的提示页面。
  4. 批量加载缓存:

    • 可在短链接创建时提前加载缓存,避免首次查询造成延迟。

返回结果示例

成功跳转

  • 输入短链接: http://shortlink.com/abc123
  • 跳转到原始链接: http://example.com/page

短链接不存在

  • 返回错误页面或提示信息:
    1
    短链接不存在或已失效。