news 2026/10/23 5:05:26

微信运动每天晚上 10 点推送排行榜,技术上到底有多难?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
微信运动每天晚上 10 点推送排行榜,技术上到底有多难?

每天晚上十点多,微信会推一条微信运动的消息,报一下今天的步数,顺便叫你看看排行榜。大家可能注意到过一个细节:推送时间并不是统一的。根据我的体感上来看,大概时间在10点整后的1分钟上下浮动。

这条消息看起来只是"把数读出来发一下",放大到全量用户,它至少牵扯定时、计算、发送三件事。微信内部怎么实现没有公开资料,这里不进行猜测实际的实现原理。我们只从学习角度分析一下这个问题


先算个数

假设日活 1 亿(只是假设值,真实规模没有公开),希望所有提醒在 1 分钟内发完:

10860≈1.67×106 \frac{10^8}{60} \approx 1.67 \times 10^660108​≈1.67×106

平均每秒 167 万条。这还是摊在 1 分钟里的结果;如果所有任务都定在 22:00:00 触发,就是 1 亿条落在同一秒。

三个问题:1 亿条待发任务怎么调度?每个人的好友排行榜都不一样,怎么算?这 1 亿份排名,是不是真的都要提前算好等着人来看?


难点一:1 亿条推送怎么发出去

单机定时任务卡在哪

最直接的做法是一张任务表,remind_at一列存时间,定时任务每分钟扫一次:

selectuidfromuser_remindwhereremind_at<=now();

扫描本身不是问题,加了索引就能顶住,问题在于扫出来之后还得挨个发。单机每秒几千条已经不错,按 5000 条/秒算:

1085×103=2×104 s≈5.5 h \frac{10^8}{5 \times 10^3} = 2 \times 10^4\ \text{s} \approx 5.5\ \text{h}5×103108​=2×104s≈5.5h

发完凌晨三点半,中间这台机器还不能挂。任务表本身也扛不住:扫描条件随时间往后走,天然是热点;失败没有重试,扩容只能换机器。

定时只负责入队

把"什么时候发"和"怎么发"拆开:调度器到点只做一件事,把这一批 uid 塞进队列,发送交给消费者。队列这儿不是解耦上下游,是缓冲:上游一次性写进 1 亿条,下游按自己的能力拉,队列长度先涨后落

消费端还要限流。下游通道有速率上限,超了会被批量拒绝,重试又会把积压放大一轮,所以限流卡在消费端。

分片和错峰

1 亿条任务按uid % N分给 N 个调度实例,每个实例只扫自己那一片,单机压力降到 1/N。

再切一层:1 分钟 = 60 秒,按hash(uid) % 60决定这一批用户分到第几秒发,每秒 167 万条,分布由 hash 保证大致均匀,不会扎堆。

回到开头:用户能感知到的只是"十点过一会儿收到通知",精确到秒的差异谁也看不出来。1 分钟内怎么排布发送时刻,是我们自己能定的。

单机定时任务分片 + 队列
任务存储数据库里一行一条队列消息,可重放
扩容换更好的机器加消费者
失败处理查日志人肉补重试 / 死信队列
峰值全压在整点那一秒按秒摊开

难点二:每个人的好友排行榜都不一样

全局榜是所有人都看同一份排名,比如"全站步数前 100",ZSet正好合适:ZINCRBY更新分数是O(log⁡N)O(\log N)O(logN),ZREVRANGE取前若干名是O(log⁡N+M)O(\log N + M)O(logN+M)。1 亿成员存一份大概十 GB,内存不小,但方向是对的。

好友榜不是同一件事。我们看的是"我的好友里谁走得最多",每个人的成员集合不同,名次也不同,全局ZSet给的名次回答不了这个问题。

一人一份 ZSet 行不行

假设平均 200 个好友:

108×200=2×1010 10^8 \times 200 = 2 \times 10^{10}108×200=2×1010

两百亿个条目,每条几十字节就是 TB 级,而这还是给一天只结算一次的数据准备的常驻内存。

存储还次要,麻烦的是写。一个人步数变了,要改他所有好友榜里那一条,写放大 200 倍。而步数不是晚上 10 点才写,是白天持续上报的,每次增量都变成 200 次操作。

查询时实时排序是另一副样子:拿 200 个好友 uid,批量取步数再排序,比较次数是200×log⁡2200≈1500200 \times \log_2 200 \approx 1500200×log2​200≈1500量级,一次查询毫秒以内,写入零成本。

方案一次查询一次步数更新空间
每人一个 ZSet(预计算)O(log⁡k)O(\log k)O(logk),最省O(klog⁡k)O(k \log k)O(klogk),要改 k 个榜O(Nk)O(Nk)O(Nk)
查询时实时排序O(klog⁡k)O(k \log k)O(klogk)O(1)O(1)O(1)无

k 不是一个定值

选哪条路,看好友数kkk和访问频率fff,而且要看kkk的分布,不是平均值。微信好友上限的公开说法是 1 万左右,kkk从几十到一万都有,长尾很长。按平均 200 设计,碰上一个 8000 好友的账号,读成本直接翻 40 倍。

还有一点容易忽略:真正进排行榜的人不等于好友数,没开微信运动的不参与,设置了不公开步数的也不参与。

所以可行的是分场景处理:

  • 好友少、访问不频繁:查询时直接算,成本低,也没有一致性问题
  • 好友多,或者被反复访问:算一次缓存起来,设短 TTL,下次直接读
  • 访问集中、好友又多的少数账号:单独处理

权衡的不是"预计算还是实时算",而是这个用户的kkk乘上访问频率fff值不值得存一份结果。kkk小的时候存是浪费,kkk大的时候不算就扛不住。


难点三:真的需要提前算吗

前面两节都在假设这 1 亿份排行榜要提前算好。但推送和计算本来就是两件事,产品上完全可以拆开。

提醒里如果只有"你今天走了 8324 步",不需要任何排名,只是把自己当天的数据读出来;需要"你在好友里排第 7",才需要排序,而这个排序也可以等用户点开时再做。

收益取决于点开率。假设 10% 的用户会点开(仍然只是假设),就是 1000 万次排序,比给 1 亿份都算一遍少一个数量级;更要紧的是没点开的那 90%,一次都没算。

但按需计算不是白赚的,它把压力从发送侧搬到了读取侧,还多出几个新问题:

问题表现常规对策
读洪峰推送后几分钟用户集中点开,QPS 陡增入口限流、排队、骨架屏
缓存冷启动第一批请求全部回源提前预热热点、合并请求
依赖放大一次请求要读好友列表 + 批量取步数好友列表本地缓存、批量接口
降级高峰时算不出来先只返回自己的步数,排名稍后加载

这里提醒一句:排序本身不贵,贵的是排序之前要拿的两样东西——好友列表和每个人的步数。所以按需方案优化的重点不在排序,在这两处读取。

不管选哪条路,核心的设计思想是同一个:最有效的优化,往往不是让计算更快,而是让不需要的计算根本不发生。1 亿次计算提速 10 倍,和只算 1000 万次,省下来的是同一个量级,但后者还省机器、省钱。


总结

  1. 集中到来的工作,先用分片和队列摊开,再谈怎么发得快。
  2. 排行榜怎么算,取决于kkk的分布和访问频率fff,不取决于"排行榜"这个功能名。
  3. 能用业务流程消掉的负载,就别用架构去硬扛。

但每一条都换来额外的复杂度:队列要运维,缓存会不一致,按需计算要处理冷启动和降级。1 万用户的时候,一个 crontab 加一次内存排序就够了,多一层队列反而是负担;到了 1 亿,前面每一步的复杂度又都省不掉。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 5:03:28

航天器材料辐照试验:原子氧与紫外协同侵蚀及姿态效应

LEO环境对航天器外露材料的考核贯穿整个任务周期。空间环境模拟要同时控住通量、光谱与姿态。少一个变量&#xff0c;地面数据就无法外推。原子氧侵蚀与紫外辐射叠加&#xff0c;损伤累积得比任一单项都快。在约200&#xff5e;800 km的LEO环境里&#xff0c;短于243 nm的紫外辐…

作者头像 李华
网站建设 2026/10/23 5:02:50

从0开始学架构-37:微内核架构详解

微内核架构(Microkernel Architecture),也被称为插件化架构(Plug-in Architecture),是一种面向功能进行拆分的可扩展性架构,通常用于实现基于产品(原文为product-based,指存在多个版本、需要下载安装才能使用,与web-based相对应)的应用。例如Eclipse这类IDE软件、UN…

作者头像 李华
网站建设 2026/10/23 5:02:50

文科研究生写作辅助怎么分工?5 个环节的判据与文科特有卡点

文科研究生的论文卡点很少出在字数上&#xff0c;而是集中在理论框架、史料细读、长文本论证、注释体例、语言风格这五处。按环节拆开配置辅助&#xff0c;比找一个包办一切的通用工具更稳。知学术AIPaperGPT 的免费智能大纲适合起步搭骨架&#xff0c;改稿环节则适合逐段精修。…

作者头像 李华
网站建设 2026/10/23 5:01:57

混沌拓扑学(HDT)三维唯一原理 对弦论高维假说的剖析

摘要 本文在混沌拓扑学的框架下&#xff0c;提出并严格证明一条基本定理&#xff1a;三维是唯一维度。维度唯一性 论证的核心&#xff0c;是把"维度"的判据从"方向的条数"改为"能否与既有方向正交"。在此判据下&#xff1a; 一维&#xff1a;正交…

作者头像 李华
网站建设 2026/10/23 5:01:11

工频相位计在电抗器、变压器、交流回路相位检测中的使用

摘要&#xff1a;工频相位计针对50Hz工频信号优化&#xff0c;可精准测量电压、电流间相位差&#xff0c;广泛应用于变压器接线组别校验、电抗器阻抗相位测试、交流二次回路及CT/PT极性与保护矢量检查。本文介绍该仪器在三类场景下的测试目的、实操要点、误差影响因素以及选型建…

作者头像 李华
网站建设 2026/10/23 4:57:15

Qt Onboard开发套件实战(3): 多媒体与摄像头集成

前言 边缘AI应用往往离不开多媒体能力&#xff0c;像摄像头采集图像、麦克风采集语音、扬声器播放TTS结果。在FactoryPulse方案中&#xff0c;Qt Onboard针对高通跃龙IQ-9075做了多项多媒体定制优化&#xff1a; 音频&#xff1a;用ALSA替换PulseAudio&#xff0c;支持USB音频…

作者头像 李华