设计 TinyURL:短链接生成与重定向

FreeGuideOnline 最新 2026-06-18

理解短链接系统

短链接服务(如 TinyURL、Bitly)的核心功能是将一个冗长的 URL 转换为简短的别名,并在用户访问该短链接时,将其重定向到原始长 URL。这背后涉及短码生成策略存储方案高并发重定向以及系统可扩展性等关键设计。

核心需求分析

一个成熟的短链接系统需要满足以下功能和非功能需求:

  • 功能需求
    • 用户提交长 URL,系统返回唯一短链接。
    • 用户访问短链接时,系统执行 301/302 重定向至原始 URL。
    • 可选:自定义短码、有效期设置、访问统计。
  • 非功能需求
    • 高可用:重定向服务不能中断。
    • 低延迟:重定向必须在毫秒级完成。
    • 可扩展:支持数百亿链接的存储和每秒百万级查询。
    • 安全性:防止短链接被猜测枚举、恶意利用。

短码生成算法

短码是短链接系统的灵魂。它的长度、唯一性和生成效率直接影响整个系统。常用的生成策略有以下几种。

1. 哈希函数法

对长 URL 进行哈希计算(如 MD5、SHA-256),然后取前 6-8 位作为短码。

  • 示例shortCode = base62(md5(longUrl))[:7]
  • 优点:实现简单,不需要全局计数器,去中心化。
  • 缺点:存在哈希冲突(不同长 URL 可能生成相同短码),需要额外处理冲突(如重试、加盐)。
  • 规避冲突:每次生成后检查数据库是否已存在,若冲突则在长 URL 后拼接随机字符串重新哈希,直到唯一。

2. 分布式 ID 生成器 + Base62

先通过分布式 ID 生成器(如 Snowflake、百度的 UidGenerator)获取全局唯一的 64 位整数,再将这个 64 位整数转换为 Base62 字符串(字符集:0-9, a-z, A-Z)。

  • 示例:ID = 123456789 → Base62 编码为 8m0Kx
  • 优点
    • 完全无冲突,ID 自增。
    • 短码长度随 ID 增长而缓慢增加(10 进制转 62 进制后更短)。
    • 生成效率极高,支持分布式生成。
  • 缺点:生成的短码长度不固定(早期生成的较短,后期变长),且规律可能被预测(但可以通过随机起始偏移或加密 ID 解决)。

3. 预生成键池(Key Pool)

提前在数据库中生成大量唯一的、随机的 Base62 字符串作为“键”,放入键池。当需要创建短链接时,直接从池中取出一个已保证唯一的键分配出去。

  • 预生成方式:使用独立的离线服务批量生成随机 7 位字符串,校验无重复后入库。
  • 优点:生成时几乎零延迟,不存在冲突问题,键的长度固定。
  • 缺点:需要维护键池的可用数量,当池子耗尽时需要及时补充,存在键的“浪费”问题(取出但未使用的键可能永远不被使用)。

推荐方案:初始阶段可使用哈希法快速上线,流量增长后迁移至分布式 ID 或键池方案。

存储设计

短链接系统需要持久化存储“短码 ↔ 长 URL”的映射关系。根据数据规模和访问模式,合理选型至关重要。

数据库表结构

字段 类型 说明
short_code VARCHAR(8) 短码,主键
original_url TEXT 原始长 URL
created_at TIMESTAMP 创建时间
expires_at TIMESTAMP 过期时间(可选)
user_id BIGINT 创建者 ID(可选)
  • 索引short_code 上建立主键/唯一索引,这是重定向查询的唯一入口。
  • 如果需要对用户维度查询,为 user_id 增加二级索引。

缓存加速

短链接的访问流量通常远超生成流量,且读操作极度频繁。必须引入缓存来减轻数据库压力,并降低延迟。

  • 缓存结构:Key = short_code,Value = original_url
  • 缓存策略
    • Cache-Aside:读取时先查缓存,未命中则查数据库,回填缓存并设置 TTL(例如 1 小时)。
    • 兜底保护:缓存宕机时流量直接打到数据库,需要做好数据库的容量评估和限流。
  • 常用缓存方案:Redis 或 Memcached 集群,容量规划需覆盖最热门的短链接集。

分库分表策略

当数据量达到数百亿级别,单库单表无法承载。由于短码无序或规律不明显,通常采用一致性哈希键值范围分片

  • short_code 的前 2-3 位作为分片键,映射到不同的数据库实例/表。
  • 例如:short_code 前两位 ab → 分片1,xy → 分片 N。这样查询时可直接定位到具体分片,避免全库扫描。

重定向流程设计

用户访问短链接 https://short.domain/abc123 时,服务端需要高效完成重定向。

详细步骤

  1. DNS 解析:将短链接域名解析到负载均衡器 IP。
  2. 负载均衡:将请求分发至后端的重定向服务实例。
  3. 提取短码:从 URL 路径中提取 abc123
  4. 缓存查询:用 abc123 查询 Redis 缓存。
    • 若命中,直接获取原始 URL。
    • 若未命中,查询数据库(根据分片键找到对应分片),获取后写入缓存。
  5. HTTP 重定向:返回 HTTP 状态码 301(永久重定向)302(临时重定向),并在响应头部加入 Location: 原始URL
  6. 浏览器跳转:浏览器收到响应后自动跳转至原始地址。

301 vs 302 的选择

  • 301 永久重定向:浏览器会缓存重定向结果,后续访问同一短链接不再请求服务器,直接跳转。可以大幅降低服务器负载,但不利于后面做点击统计或链接修改。
  • 302 临时重定向:浏览器每次都会向短链接服务器发送请求,服务器可以记录每次点击,适合需要统计数据的场景,但服务器压力更大。

建议:对普通跳转使用 301,对需要统计或链接可能变更的短链使用 302。

高并发优化

  • 硬件/网络:使用高性能负载均衡器(如 LVS、Nginx),多机房部署。
  • 应用层:使用异步非阻塞 Web 框架(如 Netty、Go net/http、Node.js),单机即可维持数十万连接。
  • 缓存层:Redis 集群采用主从 + 哨兵,保证高可用;热键使用本地缓存(如 Caffeine)进行 L1 缓存,进一步降低网络开销。
  • 限流与熔断:接入层对单 IP/单短码进行频率限制,防止恶意刷量;对数据库故障实施熔断降级,返回默认提示页或缓存数据。

安全与扩展思考

防止短链接枚举

如果短码是自增 ID 或可预测,攻击者可以遍历访问所有短链,窃取链接信息。缓解手段:

  • 将 ID 加密后再编码(如采用 AES 加密后 Base62,但会增加短码长度)。
  • 使用随机生成的键池,使短码不可预测。
  • 在短码中加入校验位,使随机猜测命中率极低。

恶意链接过滤

对用户提交的长 URL 进行安全检查,调用黑名单服务或内容安全 API,防止短链成为钓鱼、欺诈链接的跳板。

自定义短码

允许用户设置自定义短码时,需要:

  • 校验短码格式(长度、可用字符)。
  • 检查是否与保留字、已有短码冲突。
  • 考虑敏感词过滤。

数据清理与生命周期

对于设置有效期的短链,可通过定时任务定期扫描 expires_at 字段,清理过期映射关系,并可将释放的短码回收到键池(如果采用键池方案)。

扩展:分布式系统架构示意

                           ┌──────────────────┐
                           │      DNS / CDN   │
                           └────────┬─────────┘
                                    │
                           ┌────────▼─────────┐
                           │  Load Balancer   │
                           └────────┬─────────┘
                                    │
                    ┌───────────────┼───────────────┐
                    │               │               │
            ┌───────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
            │ Web/Redirect │ │ Web/Redirect│ │ Web/Redirect│
            └───────┬──────┘ └──────┬──────┘ └──────┬──────┘
                    │               │               │
                    └───────────────┼───────────────┘
                                    │
                    ┌───────────────┼───────────────┐
                    │               │               │
            ┌───────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
            │  Redis Cache │ │  Redis Cache│ │  Redis Cache│
            └───────┬──────┘ └──────┬──────┘ └──────┬──────┘
                    │               │               │
                    └───────────────┼───────────────┘
                                    │
             ┌──────────────────────┼──────────────────────┐
             │                      │                      │
     ┌───────▼──────┐       ┌───────▼──────┐       ┌───────▼──────┐
     │  DB Shard 0  │       │  DB Shard 1  │       │  DB Shard N  │
     └──────────────┘       └──────────────┘       └──────────────┘

通过上述设计,一个生产级短链接系统即可稳健运行。从算法选择到存储、缓存、重定向和安全,每一步都需要根据实际流量、一致性需求和运维成本进行权衡。