之前因为工作需要,经常要把长链接转成短链接发给客户。用第三方的短链接服务吧,又担心链接被人删了或者服务挂了,所以干脆自己写了一个。今天分享一下设计思路和实现方案。
一、为什么不用现成的?
市面上短链接服务很多,比如bit.ly、t.cn这些,但都有一些问题:
- 免费版有次数限制
- 数据不在自己手里,随时可能被删
- 有些服务的短链会跳转到中间页,体验不好
- 自定义后缀要收费
所以我就想,反正也不复杂,自己写一个算了。
二、功能设计
我需要的功能不多:
1. 输入长链接,生成短链接
2. 点击短链接,302跳转到原始链接
3. 统计点击次数
4. 可以设置过期时间
5. 简单的管理后台
就这些,够用就行。
三、技术选型
- 后端:PHP(因为我服务器上PHP环境最方便)
- 数据库:MySQL + Redis
- 前端:简单的HTML+JS,没用框架
为什么用Redis?因为短链接的跳转是高频操作,每次都查数据库太慢了。把映射关系缓存到Redis里,跳转速度能快好几倍。
四、核心算法
短链接的关键就是怎么把长URL变成短的。我的方案是:
1. 对长URL做MD5哈希
2. 取哈希值的前6位作为短码
3. 如果碰撞了(概率很小),就取后6位
4. 再碰撞就用随机字符串
6位短码用62进制(a-z, A-Z, 0-9),能表示568亿个不同的链接,对一般需求完全够用。
五、数据库设计
就一张表:
CREATE TABLE short_urls (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
short_code VARCHAR(10) NOT NULL UNIQUE,
original_url TEXT NOT NULL,
click_count INT DEFAULT 0,
expire_at DATETIME NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_short_code (short_code),
INDEX idx_expire (expire_at)
);
六、跳转逻辑
这是最核心的部分。用户访问短链接时:
1. 先查Redis缓存,有就直接跳转
2. Redis没有就查数据库,查到后写入Redis
3. 数据库也没有就返回404
4. 检查是否过期,过期了就删除并返回提示
点击计数用的是Redis的INCR,每分钟批量写入数据库,避免频繁更新。
七、管理后台
后台很简单,就是个列表页,能看到所有短链接的信息:
- 短链接地址
- 原始链接
- 点击次数
- 创建时间
- 过期时间
- 操作(删除、复制)
加了个简单的密码认证,没有做复杂的权限系统。
八、性能优化
1. Redis缓存命中率达到95%以上,大部分跳转不经过数据库
2. 点击计数异步写入,不阻塞跳转
3. 过期链接用定时任务清理,每小时跑一次
4. Nginx层面做了限流,防止恶意刷接口
实测单机QPS能到8000+,对于我这种个人使用完全够用。
九、部署方式
我用Docker部署的,一个docker-compose文件搞定:
- Nginx容器:处理HTTP请求
- PHP-FPM容器:运行PHP代码
- MySQL容器:数据存储
- Redis容器:缓存层
整个部署过程5分钟就能搞定。
十、后续打算
目前这个系统我用了大半年了,一直很稳定。后续可能要加的功能:
- 批量生成短链接
- 链接分组管理
- 更详细的统计报表
- API接口(方便程序调用)
如果你也想自己搭一个短链接服务,可以参考这个思路。真的不难,核心代码也就几百行。有问题欢迎留言讨论。
