面试官:为什么全中国 10 亿人零点步数一齐清零,微信服务器却没崩?

发布时间:2026/7/31 3:34:20

面试官:为什么全中国 10 亿人零点步数一齐清零,微信服务器却没崩? 在高级系统架构师的面试中“高并发”往往被具象化为电商秒杀、12306 抢票等场景。但很少有人注意到每天深夜 23:59 到 00:01 这短短两分钟内你的微信里正在发生一场全中国规模最大的分布式“数据海啸”全国接近 10 亿的活跃用户每天积攒的微信步数会在零点准时逻辑清零与此同时系统需要瞬间完成昨天的步数结算、拉取几十万个微信群的排行榜、生成步数冠军、并承受数亿次“点赞占领封面”的社交并发写冲击。这种“绝对零点”场景在架构层面的恐怖之处在于全网用户在同一秒钟由物理时钟协同触发没有任何前置的用户行为缓冲是一场人为蓄意的顶级 DDoS 攻击。如果让你来设计这个系统面对 10 亿级的数据清零与群排行结算如何才能做到让服务器稳如泰山腾讯的顶尖架构师们究竟用到了哪些秘籍一、 饮鸩止渴如果用常规 MySQL 思路硬刚零点会发生什么面对这种“全网在同一秒钟协同触发”的绝对零点场景很多缺乏高并发经验的程序员第一反应通常是这有什么难的零点一到后台跑一个定时任务Cron Job执行一条UPDATE语句把全表的步数清零不就得了如果真这么做公司第二天就可以直接开除你了。10 亿行数据的全表更新会引发极其恐怖的行锁与表锁争用IOPS每秒输入输出量瞬间打满数据库会直接陷入死锁和瘫痪。那么面试官的第一个灵魂拷问就来了既然不能直接更新那面对 10 亿用户量微信到底还用不用 MySQL 关系型数据库1. 微信对 MySQL 的核心定位最终无状态的持久化归档根据微信后台团队在历届 InfoQ 架构师峰会及腾讯内部技术大讲堂如《从无到有微信后台系统的演进之路》披露的信息微信并没有完全抛弃关系型数据库但 MySQL 被放到了存储链条的最末端。在微信的全局架构中所有的突发流量洪峰点赞、高频上报步数、拉取排行100% 在内存缓存层和自研分布式中间件层被消化掉。送到 MySQL 里的数据不是高频突发的请求而是经过了消息队列MQ削峰、聚合、洗干净后的“冷账本”。2. 激进的“分库分表 用户隔离”微信内部拥有海量的 MySQL 实例。它通过用户全局逻辑标识UIN/UID进行严格的 Hash 路由把 10 亿用户切得极碎分流到数十万个标准的 MySQL “小数据表”中。每一个分表可能只负责 1 万个用户。零点时高并发的落地压力被平均分摊到了无数台独立的物理服务器和硬盘上。对单个 MySQL 实例而言它在零点根本感知不到“10 亿人清零”的宏观洪峰它只看到自己负责的那 1 万个用户在按部就班地由后台线程写入一条历史记录而已。二、 微信官方披露的底层存储底牌PaxosStore 与自研生态单纯的 MySQL 显然无法支撑微信步数这种“写多读少、高频覆盖、强社交关联”的业务。根据腾讯官方披露的技术演进微信运动背后的真正底牌是自研分布式强一致性存储系统。1. 核心底牌PaxosStore微信目前全量核心业务包括朋友圈、三方登录、微信运动等的底层运行在腾讯自研的PaxosStore上。这是一款基于 Paxos 协议的、具备多副本强一致性的海量分布式 KVKey-Value/ Table 存储系统。抗峰值能力PaxosStore 的底层完全是基于内存 WAL预写日志的。步数上报时请求直接在内存中完成原子累加Atomic Increment并写盘持久化日志其并发吞吐量比传统关系型数据库高出几个数量级。UIN 路由微信运动的数据在技术特征上属于数值型。PaxosStore 以用户的 UINuint32_t 整型为 Key实现极速的 级读写直接在前端筑起了一道无法撼动的“防洪堤”。2. 全球多数据中心Multi-DC的自治闭环微信团队在分享多数据中心架构时提到为了让 10 亿用户在不同地区都能秒级打开微信微信采用了“用户归属地自治”的存储架构你的微信步数上报时写操作必须回到你归属的数据中心完成例如你在南方就写入深圳集群在北方则写入上海集群。零点的排行榜结算首先在各个数据中心内部的缓存集群中各自闭环计算然后再通过腾讯骨干网异步同步Async Replication到其他数据中心从而彻底避免了跨地域网络延迟带来的系统阻塞。三、 微信核心算法演进如何实现“10亿人秒级无感清零”真正的高并发系统从来不会在核心业务路径上去做真正的“物理删除”或“同步更新”。微信步数之所以能“秒级清零”核心秘密在于数据从未被真正清空改变的只是时间的指针。杀手锏一基于时间窗的版本号滚动Time-Based Versioning架构师在设计数据 Key 时不会针对每个用户存一个叫user:steps:12345且不断修改的变量而是引入了一个逻辑版本号通常以当前的日期作为 Key 的一部分。1. 数据的存储结构前天5月15日的 KeyUser:Steps:20260515:UIN_12345值12800 步昨天5月16日的 KeyUser:Steps:20260516:UIN_12345值15400 步今天5月17日的 KeyUser:Steps:20260517:UIN_12345值0 步或未初始化2. 零点无感切换当时间从 23:59:59 迈入 00:00:00 的那一刹那服务器内部的机器时钟发生变化。此时业务逻辑层在获取当前日期的格式化字符串时自动从20260516变成了20260517。当你的手机端在零点后第一次上报步数或者请求步数主页时路由代码自动去读写User:Steps:20260517:UIN_12345。因为新一天的 Key 尚未初始化系统默认返回的就是 0 步。看明白了吗微信根本没有去遍历 10 亿用户把数据改成 0它只是把写请求的靶子从“昨天的盘子”平滑移到了“今天的盘子”。这就是所谓的“逻辑清零”时间复杂度是完美的 O(1)。杀手锏二延迟双写Lazy Double-Write缓冲期如果仅仅靠时间戳切换还会面临一个严重的分布式问题全网时钟不同步。尽管有 NTP网络时间协议进行时钟同步但分布式集群中各台服务器、以及全球 10 亿条手机客户端的时间不可能做到绝对零误差的对齐。有些用户的手机可能慢了 2 秒在 00:00:02 的时候还在上报 23:59:58 的步数。为了防止这部分因时钟微弱偏差而迟到的数据被彻底丢弃或者误写到新一天的账本里微信采用了延迟双写和动态时间窗口策略在零点前后的一个微小时间窗口内例如 23:58 到 00:05接入层网关会采用双写机制客户端上报的步数流既会累加到昨天的 Key 中确保昨天的冠军结算数据绝对准确也会同步初始化到今天的 Key 中。过了缓冲期后昨天的 Key 彻底变成只读的冷数据静静等待异步归档。这就是分布式架构中经典的“用空间换取时间一致性”。通过这短短 7 分钟的双写缓冲窗口微信不仅完美容忍了全网由于物理时钟漂移Clock Skew带来的分布式误差还极其巧妙地完成了新旧账本的平滑过渡。它最厉害的地方在于在流量最凶猛的交汇点全网没有发生任何一次高空坠落式的阻塞等待而是像丝绸滑过桌面一样完成了新旧一天的无感交替。解决了写冲击与时间错峰的难题那么接下来的考验就是当零点过后用户陆陆续续点开手机那令人期待的“群步数排行榜”又是如何在瞬间完成高并发计算且不引发 Redis 瘫痪的呢我们接着往下看。四、 高并发排行与冷数据归档如何解决 Redis BigKey 与存储成本在解决了“逻辑清零”的写冲击后微信运动面临的第二个天堑是如何高效生成排行榜并处理海量的历史冷数据杀手锏三关系链懒加载与微信群 ZSet 哈希分片在 Redis 中排行榜最天然的数据结构是ZSet有序集合。它可以通过ZADD动态更新步数通过ZREVRANGE瞬间拉取前几名。但如果直接把全网 10 亿用户放进一个 ZSet单 Key 元素过多会导致严重的BigKey 问题引发单台 Redis 实例的内存分配阻塞和网关暴毙。微信的解法是拒绝全局大总榜化整为零。1. 朋友圈排行基于关系链的“动态懒加载Lazy Load”微信运动其实并没有一个“全国大总榜”你的排行榜里只有你的微信好友。当用户在零点后第一次打开微信运动时系统不会去触动任何全局大表而是拿着该用户的好友列表 UIN例如 200 人去内存缓存中执行一次高效的批量获取MGET拿到这 200 个用户今天的动态步数。随后在应用层内存中完成一次轻量级的排序Sort然后渲染给用户。架构收益这个查询压力被均匀分散到了全网用户自发、错峰刷新的动作中将 的全局计算降维成了 的局部读操作。2. 微信群排行群 ID 哈希分片Sharding对于微信群排行榜每个群都拥有一个独立的Group_ID。微信通过Hash(Group_ID) % Redis_Nodes算法将全中国数亿个微信群均匀地打散到成千上万台 Redis 缓存节点上。每一个群对应一个独立的、体积很小的 ZSet。这样一来即便是零点有几百万人同时在群里飙步数流量也被物理隔离在了不同的机器上任何一台服务器的负载都在安全水位以下。杀手锏四历史冷数据的“低谷期静悄悄归档”那些已经过去的日子比如昨天、前天的步数 Key如果一直堆在昂贵的内存缓存Redis/PaxosStore 内存层里会带来恐怖的硬件成本。在零点海啸过去、全网流量进入深夜低谷期凌晨 2:00 - 4:00时微信后方的分布式调度系统基于 Flink 或大数据的批处理组件开始悄悄发力异步批处理归档归档线程以低优先级、限流Throttling的方式将昨天已经“盖棺定论”的步数数据批量同步到持久化分布式数据库中。过期自毁TTL内存中的旧 Key 都会被设置 2~3 天的生存时间TTL。一旦数据安全落地到分布式硬盘中内存中的旧 Key 到期后会被自动回收。通过这种内存抗高并发现货、持久化留存历史期货的冷热分离架构既保证了零点的丝滑又控制了运营成本。五、 面试满分答案模板当面试官问“如何设计10亿用户零点清零系统”如果在面试中遇到了类似的场景设计题如微信步数清零、全网会员积分跨年清零、大型游戏排行榜零点结算你可以直接抛出下面这套高级架构师级别的满分作答模板。面试官提问“如果让你来设计微信步数系统面对 10 亿用户在零点同时清零和排行榜结算你会如何设计整体的架构会用 MySQL 吗”核心回答框架分为四步第一步定调存储选型破除“单体 MySQL 误区”回答示例“首先面对 10 亿用户和绝对零点的瞬时洪峰绝对不能让流量直达传统的单体关系型数据库如 MySQL。在我的设计中MySQL 只会作为最末端的、解耦后的持久化归档账本并且必须通过用户 UIN 进行严格的分库分表如 1024 个库、每库 1024 张表确保单表数据量控制在万级将物理写压力彻底打散。真正的核心战场在缓存和自研 KV 层。我会参考微信PaxosStore的设计前端采用‘内存 WAL预写日志’的强一致性分布式 KV 存储来支撑高频的步数原子累加上报。”第二步引入“逻辑清零”将 降维为回答示例“其次针对‘10 亿用户瞬间清零’这一诉求我在零点那一秒连一条数据都不会去物理修改或删除。因为任何物理操作都会导致严重的锁表或缓存阻塞。 我会采用‘基于时间窗的版本号滚动Time-Based Versioning’策略。将数据 Key 设计为User:Steps:{Date}:{UIN}。零点一过全网服务器的机器时钟自动向前跳动一秒业务层的日期指针从昨天切换到今天。此时客户端上报和查询的请求会自动路由到新日期的 Key 上。由于新一天的账本尚未初始化系统读取出的默认值自然就是 0 步。通过改变时间指针我将 10 亿次清除操作降维转变成了 的逻辑偏移对服务器而言零点瞬间的工作量是完美的 0。”第三步容忍分布式缺陷设计“延迟双写缓冲期”回答示例“考虑到分布式环境下服务器与客户端之间存在时钟漂移Clock Skew为了防止零点前后几秒钟内由于时钟不同步导致的数据丢失我会设计一个5分钟的‘延迟双写时间窗口’。在 23:58 到 00:03 之间客户端上报的步数流会同时累加到昨天和今天的两个 Key 中。这样既能保证昨天冠军结算数据的绝对准确又能确保今天新账本的平滑过渡。”第四步化整为零解决排行榜 BigKey 与冷数据归档回答示例“在社交排行方面为了防止 Redis ZSet 出现 BigKey我拒绝设计全局总榜。对于朋友圈排行利用关系链在应用层进行懒加载Lazy Load在用户打开瞬间批量 MGET 好友步数并在内存中排序将写扩散转化为读扩散利用用户行为错峰消减压力。对于群排行榜以Group_ID作为分片键将不同群的 ZSet 均匀哈希路由到不同的 Redis 节点。最后在凌晨 2:00 到 4:00 的业务低谷期通过分布式调度任务将昨天的冷数据异步刷入底层的分库分表或 HBase内存 Key 结合 TTL 机制自动过期释放实现整体架构的闭环。”Fox 老师的技术总结这个案例的精髓在于“避其锋芒借力打力”。 在面对极端高并发时顶尖的架构师从来不去硬碰硬地优化物理删除的速度而是通过改变数据结构引入时间版本号把一个原本需要消耗海量算力的灾难级场景直接消解于无形。你在面试中展示出这种“空间换时间”、“逻辑清除代替物理清除”、“分片路由隔离流量”的思维模型正是大厂期望的高级/资深架构师所具备的技术大局观。满大街吃灰资料改不了底薪看透业务本质的架构思维才能真正决定职业上限。

相关新闻