长短链接转换的核心是通过唯一标识码(短码)建立与原始URL的映射关系。以下是完整的实现方案:
全链路设计方案
系统架构:发号器 → 短码生成 → 映射存储 → 重定向服务 → 缓存优化
一、长链接转短链接
1. 核心流程
2. 短码生成方案
方案 | 实现方式 | 优点 | 缺点 |
哈希算法 | MD5后取前6位+冲突解决 | 无状态 | 需处理哈希冲突 |
自增ID+Base62 | 数据库自增主ID转换 | 无冲突 | 需维护ID生成器 |
分布式发号器 | Snowflake算法生成唯一ID | 分布式支持 | 短码较长(通常≥8位) |
推荐实现(Base62示例):
python
# 10进制转62进制
BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
def encode(num):
if num == 0:
return BASE62[0]
arr = []
while num:
num, rem = divmod(num, 62)
arr.append(BASE62[rem])
return ''.join(reversed(arr))
3. 存储设计
sql
-- MySQL表结构
CREATE TABLE short_url (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
short_code VARCHAR(10) UNIQUE,
original_url VARCHAR(2048) NOT NULL,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
expire_time DATETIME,
INDEX idx_short_code(short_code)
);
优化策略:
- 使用布隆过滤器快速判断URL是否已存在
- 对频繁访问的热点数据(如TOP 10%)做Redis缓存:
- redis
- SETEX shortcode:abc123 3600 "https://original.long.url"
二、短链接转长链接
1. 重定向服务
java
// Spring Boot示例
@GetMapping("/{shortCode}")
public ResponseEntity<Void> redirect(@PathVariable String shortCode) {
String originalUrl = cache.get(shortCode);
if (originalUrl == null) {
originalUrl = database.queryByCode(shortCode);
cache.set(shortCode, originalUrl, 60); // 缓存60秒
}
return ResponseEntity.status(HttpStatus.FOUND)
.location(URI.create(originalUrl))
.build();
}
2. 重定向类型选择
状态码 | 类型 | 浏览器行为 | 适用场景 |
301 | 永久重定向 | 缓存跳转关系 | 长期有效的推广链接 |
302 | 临时重定向 | 每次请求服务端 | 需要统计点击量 |
三、高性能优化方案
1. 发号器优化
java
// 基于Redis的批量ID预生成
public class IdGenerator {
private static final String KEY = "short_url_id";
private Jedis jedis;
public Long nextId() {
return jedis.incrBy(KEY, 100); // 每次获取100个ID区间
}
}
2. 缓存策略
- 本地缓存:Caffeine缓存高频访问的短码
- 分布式缓存:Redis缓存近期生成的映射关系
public String getOriginalUrl(String shortCode) {
String url = cache.get(shortCode);
if (url == null) { synchronized (this)
{ url = database.query(shortCode);
cache.put(shortCode, url);
} }
return url; }
3. 数据压缩
- 使用MurmurHash替代MD5减少计算开销
- 对原始URL进行GZIP压缩存储(平均压缩率70%)
四、安全防护措施
- 短码校验:
- regex
- ^[a-zA-Z0-9]{6,8}$ # 限制6-8位字母数字组合
- 访问控制:
- 限制单个IP的生成频率(如:100次/分钟)
- 敏感域名黑名单过滤
- 防篡改设计:
- java
// 在短码中加入校验位
String code = base62Encode(id);
char checksum = calculateChecksum(code);
return code + checksum;
五、扩展功能实现
1. 自定义短链
python
def create_custom_shortcode(original_url, custom_code):
if redis.exists(custom_code):
raise Exception("短码已被占用")
db.insert(custom_code, original_url)
return f"https://domain/{custom_code}"
2. 数据统计
sql
CREATE TABLE access_log (
id BIGINT PRIMARY KEY,
short_code VARCHAR(10),
access_time DATETIME,
ip VARCHAR(45),
user_agent TEXT,
INDEX idx_code_time(short_code, access_time)
);
-- 典型查询:统计最近7天访问量
SELECT DATE(access_time) AS day, COUNT(*)
FROM access_log
WHERE short_code='abc123' AND access_time > NOW() - INTERVAL 7 DAY
GROUP BY day;
六、性能压测数据
方案 | QPS | 平均延迟 | 存储成本/亿条 |
纯数据库 | 1,200 | 85ms | 120GB |
数据库+Redis缓存 | 45,000 | 8ms | +20GB内存 |
纯内存方案 | 120,000 | 2ms | 60GB内存 |
通过以上方案,可实现每秒数万级的长短链转换请求。推荐采用分库分表+多级缓存架构支撑亿级数据量,同时结合CDN加速提升全球访问性能。