Skip to content
venaissancePublic

About

A URL shortener built in Go — designed for frontend engineers to learn backend from zero

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

shorturl

Go Tests License

English

用 Go 从零实现的短链接服务 — 专为前端工程师设计的后端学习项目。

作为一个前端工程师,我需要快速补齐分布式系统、数据库、缓存、容器化、CI/CD 方面的知识。这个项目就是我的学习路径:从零开始,用一个真实的短链接服务串联所有后端核心技术。每一行代码都有详细注释,所有后端概念都有前端类比(Express ↔ Gin、localStorage ↔ Redis、Vercel ↔ K8s)。如果你也是前端想学后端,这个项目适合你。

为什么做这个项目?

你已经会 HTTP、JSON、异步编程、Vercel 部署。但全栈岗位要求的那些后端知识,你没碰过:

后端要求 你已经会的 这个项目教你的
"设计一个短链接系统" 没接触过 从零完整实现
"缓存怎么用?" 浏览器缓存、localStorage Redis Cache-Aside、TTL、穿透防护
"分布式 ID 怎么生成?" crypto.randomUUID() Snowflake:时间戳 + 机器ID + 序列号
"限流算法?" debounce / throttle 令牌桶(保护数据库,不是保护用户体验)
"Docker 和 K8s?" Vercel 自动部署 Dockerfile、Compose 编排、K8s 配置
"数据库设计?" localStorage.setItem() MySQL 索引、B+ 树、连接池
"CI/CD 流水线?" git push → Vercel 构建 GitHub Actions:lint → test → build → Docker

前端 ↔ 后端概念对照表

前端 后端(本项目) 核心区别
Express / Koa Gin 同样的中间件模式,但 Go 编译型 + 真并发
fetch('/api') db.Where().First() 前端调 API,后端调数据库
localStorage Redis 都是键值存储;Redis 多台服务器共享
npm install → node_modules go mod tidy → 全局缓存 Go 没有 node_modules,依赖全局共享
npm run build → dist/ go build → 单个二进制文件 Go 编译成一个文件,不需要运行时
Vercel / Netlify Docker + K8s 前端:平台全包。后端:你自己管
.env ConfigMap / Secret 一样的思路,但 K8s 在多台机器间统一管理
Sentry Prometheus + Grafana Sentry 捕获错误;Prometheus 追踪指标趋势
console.log 结构化 JSON 日志 后端日志要机器可解析,用于搜索和告警
Promise.all() goroutine + WaitGroup JS 假并行;Go 真并行
ESLint + Prettier golangci-lint 同样的理念,不同的生态

功能

  • 短链接生成 — Base62 编码的 Snowflake ID
  • 302 跳转 — 临时重定向,支持点击统计
  • 点击统计 — 异步事件收集,并发消费者
  • Redis 缓存 — Cache-Aside 模式,30 分钟 TTL
  • 令牌桶限流 — 100 req/s,突发 200
  • Prometheus 监控 — 请求延迟直方图 + 计数器
  • Docker 就绪 — 多阶段构建,镜像约 15MB
  • CI 流水线 — GitHub Actions:lint → test → build → Docker
  • K8s 配置 — Deployment、Service、ConfigMap

架构

                     ┌──────────────────────────────────────────┐
                     │              Gin HTTP 路由                │
                     │  /api/v1/shorten  /:code  /api/v1/stats  │
                     └────────────┬─────────────────────────────┘
                                  │
                     ┌────────────▼─────────────────────────────┐
                     │         Handler(类似 Express Controller)  │
                     └────────────┬─────────────────────────────┘
                                  │
                     ┌────────────▼─────────────────────────────┐
                     │         Service(业务逻辑层)               │
                     │  Snowflake ID → Base62 → 短码              │
                     └──┬─────────┬──────────────┬──────────────┘
                        │         │              │
               ┌────────▼──┐ ┌───▼────┐  ┌──────▼───────┐
               │ Repository │ │  Cache │  │  Analytics   │
               │  (MySQL)   │ │ (Redis)│  │ (事件收集器)  │
               └────────────┘ └────────┘  └──────────────┘

技术栈

层 技术 用途 前端等价物
语言 Go 1.26 编译成单文件,内置并发 Node.js
HTTP Gin 高性能路由 + 中间件 Express
ORM GORM 数据库操作 Prisma / TypeORM
数据库 MySQL 8.0 持久化存储 —
缓存 Redis 7 Cache-Aside 加速读取 localStorage
ID 生成 Snowflake 分布式唯一 ID crypto.randomUUID()
编码 Base62 短码生成 —
监控 Prometheus 指标采集 Sentry / DataDog
容器化 Docker + Compose 构建 + 编排 —
编排 Kubernetes 部署 + 服务发现 Vercel
CI/CD GitHub Actions 自动化流水线 Vercel CI

快速开始

环境要求

  • Go 1.26+(brew install go)
  • MySQL 8.0+(brew install mysql && brew services start mysql)
  • Redis 7+(brew install redis && brew services start redis)
  • Make

1. 克隆并安装依赖

git clone https://github.com/venaissance/shorturl.git
cd shorturl
make deps

2. 初始化数据库

mysql -u root -e "CREATE DATABASE IF NOT EXISTS shorturl DEFAULT CHARSET utf8mb4;"
mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'root123';"
mysql -u root -proot123 shorturl < scripts/init.sql

3. 启动服务

make run
# 服务运行在 http://localhost:8080

API 接口

POST /api/v1/shorten — 创建短链接

curl -s -X POST http://localhost:8080/api/v1/shorten \
  -H "Content-Type: application/json" \
  -d '{"url": "https://github.com"}' | python3 -m json.tool

返回 201 Created:

{
  "short_url": "http://localhost:8080/mfXXX",
  "short_code": "mfXXX",
  "original_url": "https://github.com"
}

GET /:code — 短链跳转

浏览器直接打开 http://localhost:8080/mfXXX,自动跳转到原始 URL。

GET /api/v1/stats/:code — 点击统计

curl -s http://localhost:8080/api/v1/stats/mfXXX | python3 -m json.tool

返回 200 OK:

{
  "short_code": "mfXXX",
  "total_clicks": 42
}

动手体验

启动服务后(make run),试试这些:

查看 Redis 缓存

redis-cli keys "short:*"              # 看哪些短码被缓存了
redis-cli get "short:你的短码"         # 看缓存的值
redis-cli ttl "short:你的短码"         # 看剩余过期时间(秒)

查看 MySQL 数据

mysql -u root -proot123 -e \
  "SELECT id, short_code, LEFT(original_url,40) as url FROM shorturl.short_urls;" 2>/dev/null

查看 Prometheus 监控

curl -s http://localhost:8080/metrics | grep http_requests_total

测试限流

# 正常流量(不超限)— 全部 302
hey -n 100 -c 10 -disable-redirects http://localhost:8080/你的短码 2>&1 | grep "Status"

# 突发流量(超限)— 部分 429
hey -n 300 -c 50 -disable-redirects http://localhost:8080/你的短码 2>&1 | grep -E "\[302\]|\[429\]"

限流器允许 100 req/s,突发 200。超出的请求返回 429 Too Many Requests。

压测(关闭限流后的裸性能)

go test -bench=. -benchmem ./internal/service/

项目结构

.
├── cmd/api/main.go            # 入口:依赖注入 + 启动服务
├── configs/config.go          # 配置管理
├── internal/
│   ├── handler/               # HTTP 处理器(类似 Express Controller)
│   ├── service/               # 业务逻辑(缩短、解析、统计)
│   ├── repository/            # 数据库 CRUD(GORM)
│   ├── model/                 # 数据模型(对应 MySQL 表)
│   ├── cache/                 # Redis Cache-Aside 实现
│   ├── analytics/             # 异步点击事件收集器
│   ├── middleware/             # 限流器、Prometheus 指标
│   ├── database/              # MySQL 连接管理
│   └── util/                  # Snowflake ID、Base62 编码
├── proto/shorturl.proto       # gRPC 服务定义
├── k8s/                       # Kubernetes 配置
├── scripts/init.sql           # 数据库建表脚本
├── docs/                      # 学习文档(每个 Phase 一份)
├── Dockerfile                 # 多阶段构建
├── docker-compose.yml         # 完整服务编排
├── Makefile                   # 常用命令
└── .github/workflows/ci.yml  # CI 流水线

24 个 Go 源文件,13 个包。

学习路径

分 5 个阶段,每个阶段包含:

  • 学习笔记 — 详细注释 + 前端类比
  • 交互式测验 — 克隆后用浏览器打开 HTML 即可做题(选择题 + 连线 + 填空 + 成绩单)
  • 所有代码都有详细注释,每个 Go 概念都有 TypeScript/JS 等价物
阶段 你会学到什么 前端类比 学习笔记 交互式测验
1 Go 基础、HTTP 服务、MySQL、分层架构 "像用 Express + Prisma 搭 API" 笔记 测验
2 Redis 缓存、Snowflake ID、限流、压测 "像加上 localStorage 缓存 + UUID + throttle" 笔记 测验
3 微服务模式、异步事件、gRPC/Protobuf "像把 monorepo 拆成多个 package + EventEmitter" 笔记 测验
4 Docker、Docker Compose、K8s 配置 "像从 Vercel 到自己管理基础设施" 笔记 测验
5 CI/CD 流水线、Prometheus 监控、可观测性 "像 GitHub Actions + Sentry 的后端版" 笔记 测验

交互式测验是独立的 HTML 文件,克隆项目后用浏览器打开即可,如 open docs/phase1-quiz.html

额外文档

  • 从开发到上线全链路拆解 — 以大厂标准对比前端和后端从代码到上线的完整工程链路(85KB,覆盖 CI/CD、灰度发布、监控告警、容量规划)

测试

make test

52 个测试用例,覆盖全部 9 个包:

包 测试数 覆盖内容
handler 9 HTTP 端点、错误响应、E2E 流程
service 7 缩短/解析、幂等性、缓存命中、过期
repository 7 CRUD、重复检测、更新
cache 6 Redis 读写、TTL 过期、穿透防护
analytics 6 事件收集、并发安全、优雅关闭
middleware 5 限流、Prometheus 指标
model 4 过期判断、表名
util 8 Base62 编解码、Snowflake 唯一性/并发

压测数据

Resolve 性能对比(Apple M4 Pro):

场景 ops/sec 延迟 内存/次
有 Redis 缓存 ~25,700 45μs 264B
无缓存(纯 MySQL) ~9,200 123μs 4,667B

Redis 缓存带来 2.7 倍吞吐提升,94% 内存节省。

压力测试(关闭限流,单机):

并发 请求数 QPS 平均延迟 失败
100 5,000 20,586 4.8ms 0
200 10,000 23,058 8.5ms 0
500 50,000 25,877 19.1ms 0

作者

米大王 — 目前专注于 AI Agent 全栈开发

如果这个项目对你有帮助,欢迎 Star 支持。有问题可以在知乎或 Issue 里交流。

License

MIT

About

A URL shortener built in Go — designed for frontend engineers to learn backend from zero

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages