Skip to content
open-portfoliosPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

14 Commits

Folders and files

Repository files navigation

短链接服务 (Short URL Service)

基于 Go-Zero 微服务框架构建的高性能短链接生成系统,集成 Bloom Filter、Redis 缓存、Singleflight、分布式锁、Prometheus 监控等生产级特性。

效果展示

前端页面

前端页面

Prometheus + Grafana 监控面板

Grafana 监控面板


核心功能

  • 短链接生成与解析(支持永久有效、7 天失效、自定义过期时间)
  • 管理员手动禁用短链
  • Bloom Filter 内存级拦截无效请求,DB 无效查询降低 100%
  • Singleflight 合并热点并发查询,防止缓存击穿
  • Redis 分布式锁保证转链幂等,防止并发重复发号
  • Redis 缓存分层(sqlc 自动缓存 + 手动缓存)
  • 请求超时控制、并发限流、优雅关闭
  • Prometheus 指标暴露 + OpenTelemetry 链路追踪 + 结构化日志
  • MD5 去重 + 62 进制编码 + 违禁词过滤
  • RESTful API + gRPC 双协议支持
  • Go stdlib 自研压测器,验证 22000+ QPS / P99 < 17ms

技术栈

组件 技术选型 说明
Web 框架 Go-Zero v1.9.0 微服务框架
通信协议 gRPC + HTTP 双协议支持
数据库 MySQL 持久化存储,6 索引 + 2 唯一键
缓存 Redis 序列号生成、分布式锁、sqlc 缓存
服务发现 Etcd 服务注册与发现
布隆过滤器 bits-and-blooms/bloom/v3 内存级无效请求拦截
请求合并 go-zero syncx.SingleFlight 防止缓存击穿
分布式锁 go-zero redis.RedisLock 转链幂等保护
监控 Prometheus + Grafana 四层全链路指标监控
链路追踪 OpenTelemetry + Jaeger 分布式追踪
压测工具 Go stdlib net/http 自研压测器

架构设计

                          ┌──────────────────────────────────────────────┐
                          │                  Client                       │
                          └──────────────────────┬───────────────────────┘
                                                 │
                                                 ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│                           API Gateway (Go-Zero) :8888                         │
│                                                                              │
│  ┌─────────┐  ┌──────────┐  ┌───────────────┐  ┌──────────┐  ┌───────────┐ │
│  │ CORS    │→│ 限流(500) │→│ Bloom Filter  │→│Singleflt │→│ sqlc Cache│ │
│  │ 中间件  │  │ 信号量    │  │ 拦截无效请求  │  │ 合并查询 │  │ Redis缓存 │ │
│  └─────────┘  └──────────┘  └───────────────┘  └──────────┘  └─────┬─────┘ │
│                                                                     │       │
│  ┌──────────┐  ┌───────────┐  ┌──────────────┐                     │       │
│  │/convert  │  │/{shortUrl}│  │/debug/stats  │                     ▼       │
│  │ 转链接口 │  │ 跳转接口  │  │ 指标端点     │              ┌──────────────┐│
│  │ +Redis锁 │  │ +Bloom    │  │              │              │   MySQL      ││
│  └──────────┘  └───────────┘  └──────────────┘              │ (持久化)     ││
│                                                               └──────────────┘│
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │  Prometheus :9101 /metrics  │  OpenTelemetry → Jaeger  │  结构化日志    │ │
│  └─────────────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────┘
                                         │ gRPC
                                         ▼
                              ┌─────────────────────┐
                              │   RPC Service       │
                              │   (Transform)       │
                              └─────────────────────┘
                                         │
                    ┌────────────────────┼────────────────────┐
                    ▼                    ▼                    ▼
              ┌──────────┐       ┌──────────┐         ┌──────────┐
              │  MySQL   │       │  Redis   │         │  Etcd    │
              │ 持久化   │       │ 序列号   │         │ 服务发现 │
              └──────────┘       └──────────┘         └──────────┘

查询链路

短链跳转的完整查询链路,逐层过滤无效请求:

请求进入
  │
  ├─① 限流中间件 ──── 超过 500 并发 → 503 Server Busy
  │
  ├─② Bloom Filter ── 不存在 → 直接返回 404(0 DB 查询)
  │
  ├─③ Singleflight ── 合并相同短链的并发请求(1 次 DB 查询)
  │
  ├─④ Redis 缓存 ──── 命中 → 直接返回(0 DB 查询)
  │
  ├─⑤ MySQL 查询 ──── 缓存未命中才查库
  │
  └─⑥ 状态校验 ────── 禁用→403 / 过期→410 / 正常→302 跳转

项目结构

.
├── api/                         # API 网关层
│   ├── etc/                     # 配置文件 (Bloom/Prometheus/Telemetry/限流)
│   ├── frontend/                # 前端页面
│   ├── internal/
│   │   ├── config/              # 配置定义
│   │   ├── handler/             # HTTP 处理器 + Debug 端点
│   │   ├── logic/               # 业务逻辑 (Show + Bloom/Singleflight, Convert + Redis锁)
│   │   ├── svc/                 # 服务上下文 (Bloom 初始化)
│   │   ├── stats/               # atomic 计数器 (压测埋点)
│   │   └── types/               # 类型定义
│   ├── model/                   # 数据模型 (带 DB 查询埋点)
│   ├── pkg/                     # 工具包 (62 进制编码、MD5)
│   ├── sequence/                # 发号器 (Redis/MySQL 双实现)
│   └── shorturl.go              # 入口 (限流中间件 + 优雅关闭)
├── rpc/                         # RPC 服务层
│   ├── transform/               # 短链接转换服务
│   └── proto/                   # Protobuf 定义
├── benchmark/                   # 压测工具
│   ├── seed/                    # 数据灌入 + URL 生成
│   ├── loadgen/                 # Go stdlib 自研压测器
│   └── results/                 # 压测报告
├── docker/                      # 监控部署
│   ├── docker-compose.yml       # Prometheus + Grafana
│   ├── prometheus/prometheus.yml
│   └── grafana/dashboard.json   # 预置 Dashboard
└── go.mod

快速开始

前置要求

  • Go 1.24.1+
  • Docker(用于 Redis、Etcd、Prometheus、Grafana)

1. 启动基础设施

# Redis
docker run -d --name redis -p 6379:6379 redis:latest

# Etcd
docker run -d --name etcd -p 2379:2379 \
  -e ALLOW_NONE_AUTHENTICATION=yes \
  bitnami/etcd:latest

# Prometheus + Grafana(监控)
cd docker
docker compose up -d

2. 数据库初始化

CREATE DATABASE IF NOT EXISTS gozero;
USE gozero;

CREATE TABLE `short_url_map` (
  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  `create_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `create_by` VARCHAR(64) NOT NULL DEFAULT '',
  `is_del` TINYINT UNSIGNED NOT NULL DEFAULT '0',
  `status` TINYINT UNSIGNED NOT NULL DEFAULT '1' COMMENT '1启用 2禁用',
  `lurl` VARCHAR(2048) DEFAULT NULL,
  `md5` char(32) DEFAULT NULL,
  `surl` VARCHAR(11) DEFAULT NULL,
  `expire_at` DATETIME DEFAULT NULL COMMENT 'NULL=永久有效',
  `disabled_at` DATETIME DEFAULT NULL,
  PRIMARY KEY (`id`),
  INDEX `idx_is_del` (`is_del`),
  INDEX `idx_status` (`status`),
  INDEX `idx_expire_at` (`expire_at`),
  UNIQUE KEY `uniq_lurl` (`md5`),
  UNIQUE KEY `uniq_surl` (`surl`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `sequence` (
  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  `stub` VARCHAR(1) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_uniq_stub` (`stub`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

3. 修改配置

编辑 api/etc/shorturl-api.yaml,修改数据库密码、Redis 地址等:

ShortUrlDB:
  DSN: "root:你的密码@tcp(127.0.0.1:3306)/gozero?parseTime=true"

Redis:
  Host: "127.0.0.1:6379"

BloomFilterEnabled: true      # Bloom Filter 开关
Timeout: 3000                 # 请求超时 3s
MaxConns: 500                 # 最大连接数
ShutdownGracePeriod: 5s       # 优雅关闭宽限期

4. 启动服务

# 启动 RPC 服务
go run rpc/transform/transform.go -f rpc/etc/transform.yaml

# 启动 API 网关
go run api/shorturl.go -f api/etc/shorturl-api.yaml

5. 访问

服务 地址
前端页面 http://localhost:8888
API 接口 http://localhost:8888
Prometheus 指标 http://localhost:9101/metrics
Prometheus UI http://localhost:9090
Grafana http://localhost:3000 (admin/admin)

API 接口

生成短链接

POST /convert
Content-Type: application/json

{
  "longUrl": "https://github.com",
  "expireType": "permanent"
}

expireType 支持:permanent(永久) / 7d(7天) / custom(自定义,需传 expireAt)

访问短链接

GET /{shortId}
# 正常 → 302 跳转
# 过期 → 410 Gone
# 禁用 → 403 Forbidden
# 不存在 → 404 Not Found

禁用短链

POST /admin/disable
Content-Type: application/json

{ "shortUrl": "abc123" }

Debug 端点(压测用)

GET  /debug/stats    # 查看统计计数器
POST /debug/reset    # 重置计数器

返回 totalRequest、bloomBlocked、dbQuery、cacheHit 四个指标。

性能压测

测试环境

  • 数据量:1 万条短链
  • 压测器:Go stdlib 自研 (net/http + goroutine)
  • 机器:20 核 Windows / GOMAXPROCS=20

指标一:DB 无效查询降幅

轮次 Bloom DB 查询 BloomBlocked 降幅
基线 OFF 16,398 0 -
优化 ON 6,398 99,853 无效查询 100%

Bloom Filter 完美拦截全部 50% 无效请求,有效请求零误判。

指标二:QPS / P99 延迟

场景 QPS P50 P90 P99 DB 查询
缓存命中热点 35,654 4.7ms 9.3ms 16.6ms 0
混合 50% 无效 18,425 8.4ms 25.2ms 42.5ms 0
全无效请求 39,459 2.6ms 11.9ms 24.4ms 0

运行压测

# 灌入测试数据
go run benchmark/seed/main.go -mode seed -count 10000

# 压测(混合模式)
go run benchmark/loadgen/main.go -mode mixed -ratio 0.5 -c 200 -d 30s

# 清理测试数据
go run benchmark/seed/main.go -mode cleanup

监控体系

四层全链路监控

层级 指标类别 关键指标
HTTP 入口 请求指标 QPS、P99 延迟、5xx 错误率
中间件 Redis/MySQL 连接池 连接池命中率、等待耗时
Go Runtime 运行时 goroutine 数、堆内存、GC 耗时
OS 进程 系统资源 CPU 使用率、RSS 内存、FD 使用率

Grafana Dashboard

预置 Dashboard 已包含 12 个面板,导入方式:

# 方式一:Docker 启动后通过 API 自动导入(已在 docker-compose 中配置)
cd docker && docker compose up -d

# 方式二:手动导入
# Grafana → Dashboards → Import → 上传 docker/grafana/dashboard.json

关键 PromQL

# QPS
sum(rate(http_server_requests_code_total[1m]))

# P99 延迟
histogram_quantile(0.99, sum(rate(http_server_requests_duration_ms_bucket[1m])) by (le))

# GC 平均耗时
rate(go_gc_duration_seconds_sum[1m]) / rate(go_gc_duration_seconds_count[1m])

# goroutine 数量
go_goroutines

License

MIT License

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages