点击追踪
第 10 封邮件 📧
周五下午,我收到本周第 10 封邮件,主题还是一样:
“我的链接到底被点了多少次?哪个渠道效果最好?我的推广预算花得值不值?”
这些问题我已经听了太多次。我看着自己的代码——创建短链接时只是存了个映射关系,重定向就是 302 跳转。完全没有记录任何访问信息!
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
我知道,点击统计不能再拖了。营销用户需要知道他们的推广效果,我需要记录每次点击的详细信息。但我心里也很清楚——不能影响跳转速度。
要追踪什么?
我打开笔记本,开始列出需要追踪的数据:
基础信息
- 时间戳——什么时候点的
- 短链接——点了哪个链接
- 目标 URL——最终跳到哪里
用户信息
- IP 地址——知道大概位置
- User-Agent——解析出设备、浏览器、操作系统
- Referer——从哪里来的(搜索、社交媒体、直接访问)
- Accept-Language——用户语言偏好
渠道信息
- UTM 参数——营销人员最关心的来源标记
utm_source:来源(微信、微博、抖音)utm_medium:媒介(链接、二维码、Banner)utm_campaign:活动名称
地理位置
- 国家——IP 推算
- 城市——IP 推算
我写了数据收集函数:
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
解析 User-Agent
User-Agent 是个复杂的字符串,我写了几个解析函数:
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
第一次尝试:同步写入 🐌
数据收集好了,接下来就是存储。我最开始的想法很简单——直接写数据库:
数据设计要点
- 核心是在
click_logs里保存业务事实,而不是把规则散落在应用逻辑里。- 关键字段包括
id、short_code、long_url、ip、country、city、device、browser,它们决定了后续查询和管理能力。
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
我部署上线,开始监控性能。结果让我倒吸一口凉气:
之前:平均响应时间 20ms
现在:平均响应时间 100ms
跳转速度涨了 5 倍! 😱我一看数据库监控,每次跳转都要执行一次 INSERT,数据库 QPS 瞬间飙到 1000+。这不行——用户体验会严重下降。
同步写入是死路。我需要异步。
第二次尝试:异步队列 ⚡
我的新方案:缓冲区 + 批量写入 + 后台线程。
核心思路:
- 收集到点击数据后,不直接写数据库
- 放入内存缓冲区
- 后台线程定期批量写入数据库
- 跳转响应不等待写入完成
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
再次部署上线,监控结果:
平均响应时间:22ms ✅
数据库 QPS:从 1000+ 降到 50(批量写入)完美!跳转速度恢复正常,数据库压力也大幅降低。
第三次尝试:Kafka 高吞吐 🚀
随着用户量增长,日点击量从 10 万涨到 100 万,再到 1000 万。内存缓冲区方案开始吃力——缓冲区太大占用内存,进程重启会丢失数据。
我引入了 Kafka:
用户点击
↓
[短链接服务] → [Kafka] → [消费者] → [数据库/ClickHouse]
↓
消息队列缓冲
峰值可抗 100K+/秒落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
三种方案对比
| 方案 | 响应延迟 | 吞吐量 | 可靠性 | 复杂度 |
|---|---|---|---|---|
| 同步写 DB | 10-50ms | 1K/s | 高 | ⭐ |
| 异步批量写 | <1ms | 10K/s | 中 | ⭐⭐ |
| Kafka | <1ms | 100K+/s | 高 | ⭐⭐⭐ |
建议:日点击 < 10 万用异步批量写,> 100 万上 Kafka。
数据模型优化 📊
我重新审视了数据表设计,做了些优化:
数据表设计
数据设计要点
- 核心是在
click_logs里保存业务事实,而不是把规则散落在应用逻辑里。- 关键字段包括
id、short_code、ip、city_id、browser、os、referer、utm_source,它们决定了后续查询和管理能力。
数据量估算
每条记录约 200 字节
日访问量 50 万 = 每天 100MB = 每月 3GB
日访问量 1000 万 = 每天 2GB = 每月 60GB查询统计
数据存好了,用户要能查。我写了几个常用查询:
数据设计要点
- 查询目标是用短码快速找到目标链接、状态或统计结果,避免在跳转路径上做大范围扫描。
统计 API
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
隐私考量 ⚖️
数据收集到什么程度?这是个问题。
我思考了很久,决定这条线:
我会收集
- ✅ IP(脱敏到前 3 段)
- ✅ 城市(不收集精确位置)
- ✅ 设备、浏览器、操作系统
- ✅ 来源渠道(UTM 参数)
我不会收集
- ❌ 完整 IP
- ❌ GPS 位置
- ❌ 个人身份信息
- ❌ Cookie 跟踪
IP 脱敏实现
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
这样既能提供有价值的统计数据,又保护了用户隐私。这是我的底线。
想一想
点击追踪会影响重定向的速度吗?
会,如果同步写入的话。我改成异步队列后,响应时间从 100ms 降回 20ms。如果追踪系统暂时不可用(如 Kafka 挂了),应该怎么处理?
我的选择是放行——宁可丢数据,也不能影响用户体验。可以在本地文件缓存,等恢复后再补传。如何防止伪造点击数据(刷量)?
这是个难题。我做了几个防护:
- 限制同一 IP 的短时间点击频率
- 检测异常 User-Agent
- 识别代理 IP
- 统计异常模式(比如连续点击同一链接)