短链接生成的核心逻辑是随机映射+数据库去重校验。需用62进制随机生成6位字符串,查库确保唯一,配合Redis SETNX防并发冲突;跳转走302,路由通配,DB建唯一索引,开发用SQLite+Redis,压测P99

短链接生成的核心逻辑不是加密,而是映射 + 去重
短链接服务本质是把长 URL 映射成一个极短字符串(如 abc123),用户访问 /abc123 时 302 跳转到原始地址。Golang 里不推荐用 base64 或哈希直接截断——md5(url)[:6] 碰撞率高、不可读、无法控制长度;也不该用自增 ID 转 62 进制后暴露总量和顺序。
真正靠谱的做法是:生成随机、定长、可校验的字符串,同时在数据库或缓存中检查是否已存在。常见长度选 6 位(约 560 亿组合),字符集用 0-9a-zA-Z(62 个)。
- 每次生成先用
rand.Read()取随机字节,再映射到 62 进制字符表,避免依赖时间戳或 PID - 生成后必须查库:
SELECT COUNT(*) FROM links WHERE short = ?,重复则重试(建议上限 3 次,超时就报错) - 别用
uuid.NewString()—— 太长,且带连字符,不适合做路径段 - 如果并发高,单靠应用层重试容易雪崩,可配合 Redis 的
SETNX做原子预占(SETNX short:abc123 "pending")
数据库设计要支持快速跳转和防刷
跳转性能取决于能否单次索引查询完成,所以 short 字段必须建唯一索引;但光有这个不够,还要防恶意构造短码刷库、防爬虫批量探测。
-
short设为VARCHAR(12)(留余量,兼容未来扩展),加UNIQUE INDEX - 加
created_at和updated_at,方便清理过期链接(比如 30 天无访问自动归档) - 加
visit_count,但更新时用UPDATE ... SET visit_count = visit_count + 1,别先查再写,避免竞态 - 别把原始 URL 存成 TEXT 无限制——限制
url VARCHAR(2048)即可,超长 URL 本身就不该被短链化 - 如果要做防刷,可在表里加
ip_hash CHAR(32)记录首次创建者 IP 的 MD5,同一 IP 1 小时内最多提交 5 条
HTTP 路由和跳转必须绕过中间件开销
Golang 的 net/http 默认路由树对静态路径高效,但如果你用 gorilla/mux 或 gin 的正则匹配 /[a-zA-Z0-9]{6},会引入不必要的编译和匹配成本。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
- 直接用
http.HandleFunc("/" + short, handler)不现实,因为短码是动态的;正确做法是注册通配路由:http.HandleFunc("/", rootHandler),然后在rootHandler里取r.URL.Path[1:]作为 short 码 - 跳转必须用
http.Redirect(w, r, targetURL, http.StatusFound)(即 302),别用 301——否则浏览器缓存后改目标 URL 就不生效了 - 别在跳转前做任何耗时操作(如日志落盘、统计上报),这些应走异步 goroutine 或消息队列
- 如果用了反向代理(如 Nginx),确保它透传
X-Forwarded-For,否则所有请求 IP 都是 127.0.0.1
本地开发时 Redis 和 SQLite 就够用,别一上来就上 MySQL
短链服务最核心的读操作是「根据 short 查 URL」,QPS 上千时 MySQL 完全 OK,但本地调试或小流量场景下,MySQL 启动慢、配置重、事务开销大,反而拖累迭代效率。
- 开发阶段用
sqlite3+github.com/mattn/go-sqlite3,单文件、零配置,PRAGMA journal_mode = WAL开启后并发读写也稳 - 缓存层用
redis存热 key(GET short:abc123),但别把所有短码都塞进去——冷数据查库即可,避免 Redis 内存爆炸 - 别用
go-redis/redis/v9的WithContext包裹每个调用——短链跳转路径必须极致轻量,超时设 10ms 足够,context.WithTimeout 带来额外分配,可直接用client.Get(ctx, key).Val()中的默认超时 - 上线前务必压测:用
hey -n 10000 -c 100 http://localhost:8080/abc123看 P99 是否稳定在 5ms 内;慢多半出在 DB 连接池没设(db.SetMaxOpenConns(20))或没加索引
短码生成看似简单,真正难的是在高并发下保持低延迟、零冲突、可追溯。很多人卡在“为什么生成重复短码”,其实问题不在算法,而在没做存在性检查;也有人跳转变慢,结果发现是日志中间件同步写了磁盘。这些点不显眼,但线上一跑就露馅。

















