0

0

如何设计MongoDB的短链系统_哈希映射与访问统计预聚合

P粉602998670

P粉602998670

发布时间:2026-03-14 11:03:31

|

298人浏览过

|

来源于php中文网

原创

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

如何设计mongodb的短链系统_哈希映射与访问统计预聚合

短链哈希怎么选:MD5、SHA256 还是自定义 base62?

直接用 MD5SHA256 做短码,看似省事,实则埋雷。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 文档结构:为什么不能把统计字段全塞进主文档?

clickCountlastAccessAtcountryStats 全放在短链主文档里,写放大严重。每次访问都要 $inc$set,高并发下容易触发文档扩容(尤其是嵌套数组增长),引发性能抖动甚至写锁争用。

正确做法是分离「元数据」和「访问流」:主文档只存不可变或低频变更字段(originalUrlcreatedAtownerId),所有访问行为写入独立集合,用预聚合策略降频更新主文档。

  • 建单独集合 shortlink_access_logs,每条记录含 shortCodetimestampipuacountry
  • 用定时任务(如每 5 分钟)跑聚合:db.shortlink_access_logs.aggregate([ { $match: { timestamp: { $gt: ... } } }, { $group: { _id: '$shortCode', count: { $sum: 1 }, countries: { $push: '$country' } } } ])
  • 聚合结果批量更新主文档的 clickCounttopCountries 字段,避免实时写压力

原子计数器失效了?别用 $inc 直接更新访问量

很多人图快,直接在访问路由里写 db.links.updateOne({ shortCode: 'abc123' }, { $inc: { clickCount: 1 } })。短期看不出问题,但当 QPS 超 500+,你会发现 clickCount 明显少于真实请求量——不是 MongoDB 不支持原子性,而是网络超时、重试、客户端崩溃导致部分 $inc 丢失,且无法回溯。

Peppertype.ai
Peppertype.ai

高质量AI内容生成软件,它通过使用机器学习来理解用户的需求。

下载

根本解法是放弃“强一致计数”,改用“日志保底 + 定时校准”。所有访问必须落库(哪怕只是轻量日志),再通过离线聚合补全数字。这样丢的只是延迟,不是数据。

  • 访问接口必须成功写入一条 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%,但为此多加一层分布式锁就得不偿失。这些边界,得靠线上真实流量卡点验证,不是设计时拍板就能定的。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
什么是分布式
什么是分布式

分布式是一种计算和数据处理的方式,将计算任务或数据分散到多个计算机或节点中进行处理。本专题为大家提供分布式相关的文章、下载、课程内容,供大家免费下载体验。

411

2023.08.11

分布式和微服务的区别
分布式和微服务的区别

分布式和微服务的区别在定义和概念、设计思想、粒度和复杂性、服务边界和自治性、技术栈和部署方式等。本专题为大家提供分布式和微服务相关的文章、下载、课程内容,供大家免费下载体验。

251

2023.10.07

counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

203

2023.11.20

sort排序函数用法
sort排序函数用法

sort排序函数的用法:1、对列表进行排序,默认情况下,sort函数按升序排序,因此最终输出的结果是按从小到大的顺序排列的;2、对元组进行排序,默认情况下,sort函数按元素的大小进行排序,因此最终输出的结果是按从小到大的顺序排列的;3、对字典进行排序,由于字典是无序的,因此排序后的结果仍然是原来的字典,使用一个lambda表达式作为key参数的值,用于指定排序的依据。

409

2023.09.04

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

761

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1570

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

651

2023.11.24

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号