如何使用Golang开发URL短链接服务_Golang短链接生成与存储项目

1次阅读

短链接系统需采用“先生成、再查重、不存则写”策略,用随机base62短码+数据库唯一索引防冲突;redis缓存热key,mysql存全量数据;重定向默认用302并禁用缓存;访问统计须原子更新。

如何使用Golang开发URL短链接服务_Golang短链接生成与存储项目

短链接生成必须避开重复和冲突

hashbase62 直接编码原始 URL 得到的短码,大概率会碰撞——尤其当业务量上来后,md5(url)[0:6] 这类做法在千万级数据下几乎必然重复。真正可用的方案是「先生成、再查重、不存则写」,而不是「直接算完就用」。

  • 推荐用随机生成 + 唯一索引兜底:每次生成 6 位 base62 字符(如 "aB3xK9"),插入前查数据库是否已存在;失败就重试,最多 5 次
  • 数据库表必须给 short_code 字段加唯一索引,否则并发写入时仍可能写入重复值
  • 避免用自增 ID 转 base62:虽然绝对不重复,但暴露业务总量、易被爬取、无法支持多实例分库

Redis 和 MySQL 怎么分工存短链

高频跳转场景下,纯 DB 查询扛不住,但全放 Redis 又丢数据风险大。合理分工是:Redis 存热 key(short_code → long_url),MySQL 存全量+元数据(创建时间、访问统计、所属用户)。

  • 首次请求短链时,先查 Redis;未命中则查 MySQL,查到后立刻 SETNX 写入 Redis,过期时间设为 1 小时(防止雪崩)
  • 写入 MySQL 后,如果失败,要主动删掉刚塞进 Redis 的脏数据,否则下次读会返回错误长链
  • 不要用 Redis 的 EXPIRE 自动过期来替代冷热分离逻辑——过期后大量请求会穿透到 DB,需配合布隆过滤器或本地缓存降级

重定向响应必须控制 http 状态码和头字段

浏览器对 301302 处理差异极大:301 会被强缓存,改链后旧短码仍跳转到旧地址;302 不缓存,但部分客户端(如微信内嵌浏览器)会限制跳转次数。生产环境建议默认用 302,仅对明确需要 seo 收录的链接开放 301 开关。

  • golang 中用 http.Redirect(w, r, url, http.StatusFound) 发送 302;别手误写成 StatusMovedPermanently
  • 务必设置 Cache-Control: no-store, no-cache, must-revalidate,否则 CDN 或中间代理可能缓存重定向响应
  • 如果支持自定义短码(如 /go/github),需额外校验该码未被系统保留(如 /admin/api),否则可能引发路由冲突

Go 并发写入短链时容易漏掉计数更新

访问统计不能只靠 MySQL 的 UPDATE ... SET clicks = clicks + 1,因为高并发下会丢失更新(两个请求同时读出 100,各自加 1 再写回,结果仍是 101)。必须用原子操作或队列异步落库。

立即学习go语言免费学习笔记(深入)”;

  • 简单方案:用 Redis 的 INCR 实时累加,定时任务每 5 分钟把各短码的计数同步到 MySQL
  • 更稳方案:把访问事件发到内存队列(如 chan Struct{ code String }),由单个 goroutine 消费并批量更新 DB
  • 千万别在 HTTP handler 里直接 db.Exec("UPDATE ...") —— 单次请求延迟可能从毫秒级飙到数百毫秒,拖垮整个服务

实际最难的部分不是生成短码,而是让重定向快、准、不翻车。比如微信里点短链,它会预请求一次 HEAD,如果服务没正确响应 302+location,或者返回了 200 带 HTML,就会卡住或跳转失败。这些边界情况比算法本身更耗调试时间。

text=ZqhQzanResources