URL Shortener — 短链接服务
V1:产品经理说下周活动要用短链
Section titled “V1:产品经理说下周活动要用短链”市场部下周有个推广活动,产品经理跑过来说:“我们需要一个短链接服务,把活动长链接缩短一下,方便放到海报上。” 你看了一眼日历,离活动只剩三天。没时间搭服务器,也不想用第三方服务(怕数据泄露)。 你决定先做一个纯前端版本,能在自己浏览器里生成短链就行,活动海报上的链接手动复制过去。
你要解决什么
Section titled “你要解决什么”用纯前端实现一个短链接生成器,输入长链接,生成随机短码,数据存在 localStorage 里。
给 AI 的 Prompt
Section titled “给 AI 的 Prompt”帮我创建一个纯前端的短链接生成器,要求如下:
1. 单个 index.html 文件,所有 CSS 和 JS 内联,不需要任何构建工具或外部依赖2. 功能: - 输入框输入长链接,点击按钮生成 6 位随机短码(字母+数字) - 短码格式显示为 http://localhost:3000/{code}(模拟短链域名) - 生成后显示短链,旁边有"复制"按钮(用 navigator.clipboard API) - 下方显示所有已生成的短链列表(长链接 → 短码),支持删除3. 数据存储:所有映射关系存在 localStorage,刷新页面不丢失4. 如果同一个长链接已经生成过,直接返回之前的短码,不重复生成5. 界面简洁美观,用内联 CSS,浅色主题- 打开 index.html,输入长链接,点击生成,得到 6 位短码
- 点击复制按钮,粘贴验证短链格式正确
- 刷新页面,之前生成的短链还在列表中
- 输入同一个长链接,返回相同的短码
- 删除某条记录后,该记录从列表和 localStorage 中消失
你学到了什么
Section titled “你学到了什么”- localStorage 的读写与序列化:JSON.stringify / JSON.parse 存取结构化数据 → M2 数据模型
- 随机字符串生成:Math.random + toString(36) 的常见技巧 → M9 数据处理
- Clipboard API:navigator.clipboard.writeText 的使用 → M1 API 基础
V2:短链要分享给别人,但只在我浏览器有效啊
Section titled “V2:短链要分享给别人,但只在我浏览器有效啊”活动上线了,你把短链接印在海报上。结果用户扫码后,浏览器打开的是 localhost——根本访问不了。 你意识到:短链接的核心价值是”任何人都能通过短链跳转到原始链接”,必须有一个后端服务来做重定向。 但你不想装数据库,JSON 文件存储够用了——反正现在就市场部几个人在用。
你要解决什么
Section titled “你要解决什么”搭建一个 Go 后端服务,用 JSON 文件存储映射关系,支持创建短链和通过短链重定向。
给 AI 的 Prompt
Section titled “给 AI 的 Prompt”帮我创建一个 Go 短链接服务,要求如下:
1. 技术栈:Go + Gin 框架,不需要数据库2. 数据存储: - 用一个 JSON 文件 (data.json) 存储所有短链映射 - 格式:{"mappings": [{"code": "abc123", "url": "https://...", "created_at": "..."}]} - 每次创建新短链时,读取文件 → 追加 → 写回文件3. API 接口: - POST /api/shorten:接收 {"url": "长链接"},返回 {"code": "abc123", "short_url": "http://localhost:8080/abc123"} - GET /:code:根据短码查找原始链接,302 重定向过去;找不到返回 404 - GET /api/list:返回所有短链列表4. 短码生成:随机 6 位字母数字组合,确保不重复5. 启动时如果 data.json 不存在,自动创建空文件6. 同时提供一个简单的 index.html 作为前端页面(Gin 提供静态文件服务)- 启动服务后,POST /api/shorten 创建短链成功,返回短码
- 浏览器访问 http://localhost:8080/{code},成功 302 重定向到原始链接
- 重启服务后,之前的短链仍然有效(数据已持久化到 JSON 文件)
- data.json 文件中能看到正确的映射数据
- 从另一台电脑(同一局域网)访问短链,重定向成功
你学到了什么
Section titled “你学到了什么”- HTTP 重定向机制:301 vs 302 的语义区别,为什么短链用 302 → M13 网络基础
- 文件作为数据存储:读写 JSON 文件的并发问题初现(目前还没解决)→ M2 数据模型
- RESTful API 设计:POST 创建资源、GET 读取资源的基本约定 → M1 API 设计
V3:营销活动上线,短链服务被打爆了
Section titled “V3:营销活动上线,短链服务被打爆了”公司搞了个全国性营销活动,短链服务一天的请求量从几百飙升到几百万。 你发现了三个问题:JSON 文件在高并发下频繁读写导致数据损坏;每次重定向都要读文件太慢; 有人写脚本疯狂调用创建接口,一秒钟创建几千条短链。是时候上正经的基础设施了。
你要解决什么
Section titled “你要解决什么”用 PostgreSQL 存储数据,Redis 做缓存加速重定向,加入限流防止滥用。
给 AI 的 Prompt
Section titled “给 AI 的 Prompt”帮我升级短链接服务到生产级别,要求如下:
1. 技术栈:Go + Gin + PostgreSQL + Redis2. 数据库设计: - 表 short_links:id, code (唯一索引), original_url, click_count, created_at - code 字段加 B-tree 索引,这是最高频的查询字段3. 缓存策略(Cache-Aside 模式): - GET /:code 时先查 Redis,命中直接重定向 - Redis 未命中则查 PostgreSQL,查到后写入 Redis(TTL 1 小时) - 创建新短链时同时写入 PostgreSQL 和 Redis - 每次重定向成功,异步更新 click_count(用 goroutine + channel 批量写入)4. 限流: - POST /api/shorten 接口加 Token Bucket 限流器 - 每个 IP 每分钟最多创建 10 条短链 - 超限返回 429 Too Many Requests5. 提供 docker-compose.yml 包含 PostgreSQL 和 Redis6. 提供健康检查接口 GET /health,检查 DB 和 Redis 连接状态- docker-compose up 启动 PostgreSQL 和 Redis,服务正常启动
- 创建短链写入数据库和缓存,通过 redis-cli GET 能看到缓存数据
- 访问短链时,第一次从 DB 加载并写缓存,第二次直接从 Redis 返回(日志可区分)
- 快速连续调用创建接口超过 10 次,返回 429 状态码
- 多次访问同一短链后,click_count 在数据库中正确累加
- 调用 /health 接口返回 DB 和 Redis 的连接状态
你学到了什么
Section titled “你学到了什么”- 数据库索引:B-tree 索引如何加速等值查询,唯一索引防止短码冲突 → M2 数据模型
- Cache-Aside 模式:缓存与数据库的读写协调策略,TTL 的作用 → M4 缓存
- 令牌桶限流:Token Bucket 算法原理,按 IP 维度限流的实现 → M8 扩展性
- 异步写入:用 goroutine + channel 做批量写入,避免每次请求都更新数据库 → M9 数据处理
- 健康检查:生产服务的基本可观测性,探活接口的设计 → M13 网络基础
V4:每天创建量涨到1万,统计页面也越来越慢
Section titled “V4:每天创建量涨到1万,统计页面也越来越慢”短链服务在公司内推广开了,每天创建量从几百涨到1万条,累计已经有几十万条短链。 产品经理要看点击统计报表,但统计页面加载要 8 秒——因为每次点击都直接写数据库,click_count 的更新和查询互相抢锁。 运维反馈 Redis 内存用了 2GB,很多冷门短链也占着缓存。监控?没有监控,出了问题全靠用户反馈。
你要解决什么
Section titled “你要解决什么”引入点击事件的异步批量处理,优化缓存淘汰策略,加入基础监控。
给 AI 的 Prompt
Section titled “给 AI 的 Prompt”帮我优化短链接服务的性能和可观测性,要求如下:
1. 技术栈:Go + Gin + PostgreSQL + Redis + Prometheus2. 点击统计异步化: - 短链跳转时不再同步更新 click_count,改为将点击事件写入 Redis List(click_events 队列) - 事件格式:{"code": "abc123", "timestamp": "...", "ip": "...", "user_agent": "..."} - 后台 worker 每 5 秒从队列批量取出事件(LPOP 最多 500 条),聚合后批量更新数据库 - 新增 click_logs 表:id, short_link_id, clicked_at, ip, user_agent,用于详细分析3. 缓存优化: - 热门短链(点击量 Top 1000)设置更长 TTL(24 小时) - 冷门短链 TTL 缩短为 10 分钟 - 用 Redis OBJECT IDLETIME 或访问计数区分冷热 - 缓存预热:服务启动时加载 Top 1000 热门短链到 Redis4. 统计查询优化: - 新增 daily_stats 汇总表:short_link_id, date, click_count - 每小时定时任务从 click_logs 聚合写入 daily_stats - 统计页面查询 daily_stats 而不是实时聚合 click_logs5. 监控(Prometheus + Grafana): - 暴露 /metrics 端点 - 指标:请求 QPS、重定向延迟 P99、缓存命中率、队列积压长度、数据库连接池使用率 - 提供 Grafana dashboard JSON 配置6. docker-compose.yml 新增 Prometheus 和 Grafana 服务- 短链跳转后,click_events 队列中出现新事件(redis-cli LLEN click_events)
- 等待 5 秒后,click_logs 表中出现对应记录,short_links 的 click_count 正确累加
- 热门短链缓存 TTL 为 24 小时,冷门短链 TTL 为 10 分钟(redis-cli TTL 验证)
- 服务重启后,Top 1000 热门短链已在 Redis 中(缓存预热生效)
- daily_stats 表每小时更新,统计页面查询响应时间低于 500ms
- 访问 /metrics 能看到 Prometheus 指标
- Grafana 面板显示 QPS、延迟、缓存命中率等图表
你学到了什么
Section titled “你学到了什么”- 异步批量处理:用消息队列解耦实时请求和批量写入,降低数据库压力 → M5 消息队列 / M9 数据处理
- 冷热数据分离:不同访问频率的数据用不同的缓存策略 → M4 缓存
- 预聚合表:用汇总表加速统计查询,空间换时间的经典方案 → M2 数据模型
- 可观测性基础:Prometheus 指标采集 + Grafana 可视化,生产环境必备 → M15 可观测性
V5:日访问量100万次,单机Redis也吃力
Section titled “V5:日访问量100万次,单机Redis也吃力”短链服务对外开放了,日访问量突破 100 万次。单台应用服务器的 CPU 经常跑满 90%; Redis 单实例内存已经到 8GB,偶尔出现慢查询;统计分析的 SQL 查询拖慢了线上短链跳转的响应速度。 运维说:“该加机器了。“但加了机器之后,请求怎么分配?缓存怎么共享?数据库读写怎么分离?
你要解决什么
Section titled “你要解决什么”实现多实例水平扩展,Redis 集群化,数据库读写分离,让系统支撑百万级日访问。
给 AI 的 Prompt
Section titled “给 AI 的 Prompt”帮我将短链接服务扩展为多实例水平扩展架构,要求如下:
1. 技术栈:Go + Gin + PostgreSQL + Redis Cluster + Nginx2. 应用层水平扩展: - 应用服务无状态化,支持启动多个实例 - Nginx 作为负载均衡器,轮询分发请求到多个应用实例 - 健康检查:Nginx 定期探测 /health,不健康的实例自动摘除 - 提供 Nginx 配置文件,upstream 配置 3 个应用实例3. Redis 集群: - 从单实例 Redis 迁移到 3 主 3 从的 Redis Cluster - 应用代码使用 go-redis 的 Cluster 客户端,自动处理 key 分片 - 缓存 key 设计避免热点:短码本身足够随机,天然分散到不同 slot - 集群监控:节点状态、内存使用、key 分布4. 数据库读写分离: - PostgreSQL 一主一从,主库负责写入,从库负责读取 - 短链跳转(高频读)走从库:SELECT original_url FROM short_links WHERE code = ? - 创建短链(写入)走主库 - 统计分析查询全部走从库,不影响主库性能 - 应用层实现读写分离:配置两个数据库连接池(write_db, read_db)5. 会话与状态: - 限流器状态存入 Redis Cluster(而非本地内存),多实例共享限流计数 - 分布式锁:创建短链时用 Redis SETNX 防止短码冲突(多实例并发生成同一短码)6. docker-compose.yml 包含:Nginx、3 个应用实例、PostgreSQL 主从、Redis Cluster7. 提供平滑部署脚本:逐个重启应用实例,保证零停机更新- Nginx 启动后,请求均匀分发到 3 个应用实例(通过响应头或日志区分实例)
- 停掉 1 个应用实例,服务仍然正常(Nginx 自动切换到健康实例)
- Redis Cluster 的 CLUSTER INFO 显示 3 主 3 从,状态 ok
- 创建短链写入主库,短链跳转从从库读取(通过数据库日志验证)
- 统计分析查询不出现在主库的慢查询日志中
- 多实例并发创建短链,不出现短码冲突(分布式锁生效)
- 限流在多实例间共享:3 个实例合计每分钟每 IP 仍然只允许 10 次
你学到了什么
Section titled “你学到了什么”- 无状态应用设计:状态外移到 Redis/DB,应用实例可随意增减 → M8 扩展性
- 负载均衡:Nginx 轮询、健康检查、自动摘除不健康节点 → M13 网络基础
- Redis Cluster:数据分片、哈希槽、主从切换的基本原理 → M4 缓存
- 读写分离:主从复制 + 应用层路由,读多写少场景的经典方案 → M3 复制
- 分布式锁:Redis SETNX 实现互斥,防止多实例资源冲突 → M6 事务与一致性
V6:全球用户,海外跳转延迟500ms
Section titled “V6:全球用户,海外跳转延迟500ms”公司业务出海了,短链服务面向全球用户。海外用户反馈:点击短链后跳转延迟 500ms 以上,体验很差。 原因很简单——所有服务器都在国内,海外用户的请求要跨越半个地球。 同时,数据量爆炸式增长:短链总量突破 1 亿条,单表查询开始变慢;每天新增 50 万条,单库写入压力到极限。 你需要做三件事:数据分片解决单表瓶颈、多地域部署降低延迟、CDN 边缘节点实现就近跳转。
你要解决什么
Section titled “你要解决什么”实现数据库分片、多地域部署和 CDN 边缘重定向,让全球用户都能快速跳转。
给 AI 的 Prompt
Section titled “给 AI 的 Prompt”帮我将短链接服务升级为全球化多地域架构,要求如下:
1. 技术栈:Go + Gin + PostgreSQL + Redis + Nginx + CDN2. 数据库分片(按短码前缀): - 短码从 6 位扩展为 7 位:第 1 位为分片标识(a-d 对应 4 个分片) - 4 个 PostgreSQL 实例,每个负责一个前缀范围的短链数据 - 应用层分片路由:根据短码第 1 位决定查询哪个数据库实例 - 创建短链时随机分配分片,保证数据均匀分布 - 分片路由逻辑封装为独立模块:ShardRouter.GetShard(code) → db_instance - 跨分片查询(如全局统计):并行查询所有分片后合并结果3. 多地域部署(GeoDNS): - 3 个地域节点:中国(主节点)、东南亚、北美 - 每个地域部署完整的应用服务 + Redis 缓存 - GeoDNS 根据用户 IP 地理位置将请求路由到最近的节点 - 写入操作(创建短链)统一路由到中国主节点,通过异步复制同步到其他地域 - 读取操作(短链跳转)在本地地域完成,优先查本地 Redis,再查本地数据库副本 - 数据同步:主节点写入后发布消息到消息队列,各地域消费者更新本地数据库和缓存4. CDN 边缘重定向: - 利用 CDN 的边缘计算能力(如 Cloudflare Workers)在边缘节点完成重定向 - 边缘逻辑:收到短链请求 → 查边缘 KV 存储 → 命中则直接 302 重定向 → 未命中则回源 - 边缘 KV 存储热门短链(Top 10万),由源站定期同步 - 冷门短链回源处理,回源后将结果写入边缘 KV(TTL 1 小时)5. 全局监控: - 各地域节点的 Prometheus 指标汇聚到中心 Grafana - 全局视角:各地域 QPS、延迟分布、缓存命中率对比 - 告警:某地域延迟 P99 超过 200ms 触发告警6. 提供架构图描述和各组件的配置说明- 短码第 1 位正确路由到对应分片(插入数据后在对应的 PostgreSQL 实例中能查到)
- 4 个分片的数据量大致均匀(偏差不超过 10%)
- 模拟不同地域请求(修改 DNS 解析),请求被路由到最近的地域节点
- 在中国节点创建短链,30 秒内在东南亚和北美节点也能跳转(异步复制生效)
- 热门短链在 CDN 边缘节点直接返回 302(响应头显示 CDN 缓存命中)
- 冷门短链回源后,再次请求从边缘 KV 返回(不再回源)
- Grafana 面板显示各地域的独立指标和全局汇总视图
你学到了什么
Section titled “你学到了什么”- 数据库分片:按 key 前缀分片的路由策略,跨分片查询的挑战 → M8 扩展性
- 多地域部署:GeoDNS、就近接入、跨地域数据同步的架构设计 → M17 基础设施
- CDN 边缘计算:边缘节点重定向,KV 存储加速热门内容 → M4 缓存 / M13 网络基础
- 最终一致性:多地域异步复制带来的一致性权衡,适合读多写少场景 → M6 事务与一致性
- 全局监控体系:多地域指标汇聚、全局视角告警的设计 → M15 可观测性