应选先SHA256哈希再截断+base62编码:用SHA256(url)确保唯一性,截前8字节转大整数后mod 62^6生成6位可读短码,并入库前查重防碰撞。

短链哈希怎么选:MD5、SHA256 还是自定义 base62?
直接用 MD5 或 SHA256 做短码,看似省事,实则埋雷。MD5 输出 32 位十六进制字符串(如 5f4dcc3b5aa765d61d8327deb882cf99),太长;SHA256 更糟。用户要的是 6–8 位可读短码,比如 aB3xK9,不是哈希摘要本身。
真正可行的路径只有一条:先用可靠哈希(如 SHA256)确保原始 URL 映射唯一,再对哈希结果做截断 + base62 编码。别跳过哈希——否则相同 URL 多次提交会生成不同短码,破坏幂等性。
- 必须用
SHA256(url)作为源输入,不能直接对 URL 做 base62(URL 含特殊字符、长度不定) - 截取哈希前 8 字节(64 bit),转为大整数后 mod
62^6,再编码成 6 位 base62(兼顾碰撞率与长度) - 入库前查重:哪怕哈希一致也得
findOne({ shortCode: 'xxx' }),防极小概率碰撞
MongoDB 文档结构:为什么不能把统计字段全塞进主文档?
把 clickCount、lastAccessAt、countryStats 全放在短链主文档里,写放大严重。每次访问都要 $inc 和 $set,高并发下容易触发文档扩容(尤其是嵌套数组增长),引发性能抖动甚至写锁争用。
正确做法是分离「元数据」和「访问流」:主文档只存不可变或低频变更字段(originalUrl、createdAt、ownerId),所有访问行为写入独立集合,用预聚合策略降频更新主文档。
- 建单独集合
shortlink_access_logs,每条记录含shortCode、timestamp、ip、ua、country - 用定时任务(如每 5 分钟)跑聚合:
db.shortlink_access_logs.aggregate([ { $match: { timestamp: { $gt: ... } } }, { $group: { _id: '$shortCode', count: { $sum: 1 }, countries: { $push: '$country' } } } ]) - 聚合结果批量更新主文档的
clickCount和topCountries字段,避免实时写压力
原子计数器失效了?别用 $inc 直接更新访问量
很多人图快,直接在访问路由里写 db.links.updateOne({ shortCode: 'abc123' }, { $inc: { clickCount: 1 } })。短期看不出问题,但当 QPS 超 500+,你会发现 clickCount 明显少于真实请求量——不是 MongoDB 不支持原子性,而是网络超时、重试、客户端崩溃导致部分 $inc 丢失,且无法回溯。
根本解法是放弃“强一致计数”,改用“日志保底 + 定时校准”。所有访问必须落库(哪怕只是轻量日志),再通过离线聚合补全数字。这样丢的只是延迟,不是数据。
- 访问接口必须成功写入一条
shortlink_access_logs记录,失败则重试 2 次或退化到本地队列(如 Redis List) - 禁止任何业务逻辑依赖
clickCount的实时值;对外展示用“近似值”(如缓存 30 秒的聚合结果) - 每天凌晨跑一次全量校验:对比
shortlink_access_logs总数与各links.clickCount之和,差值写入告警指标
索引怎么建:为什么 { shortCode: 1 } 不够,还得加 { createdAt: -1 }?
只给 shortCode 加唯一索引,能保证跳转查询快,但运营后台查“最近创建的 100 条短链”会全表扫。MongoDB 默认不利用复合索引的后缀字段做排序,除非前缀条件存在。
真正需要的是两个索引协同:一个支撑高频跳转(等值查询),一个支撑后台管理(范围 + 排序)。别试图用单个复合索引覆盖全部场景,维护成本高、效果反而差。
- 必须建
{ shortCode: 1 }唯一索引,用于find({ shortCode: 'xyz' })场景 - 额外建
{ createdAt: -1, ownerId: 1 }索引,支撑分页查询:find({ ownerId: 'uid123' }).sort({ createdAt: -1 }).limit(20) - 如果要做按访问量排序(如“热门短链”),不要实时
sort({ clickCount: -1 }),而是在预聚合阶段写入hotScore字段并建索引——因为clickCount本身是滞后的
哈希映射不是难点,难的是让预聚合节奏和业务容忍度对齐:统计晚 2 分钟可以,但不能晚 2 小时;短码重复率要低于 0.0001%,但为此多加一层分布式锁就得不偿失。这些边界,得靠线上真实流量卡点验证,不是设计时拍板就能定的。










