拼多多面试: 设计“砍一刀”算法,怎么防止被刷破产?90% 的人死在了“最后 0.01 元”

写在开头

上一篇我们聊了"千万级对账",那是后台的资金底裤。今天我们聊聊前台最疯狂的**"病毒营销引擎"------拼多多的"砍一刀"**。

有个粉丝去面拼多多(Temu 部门),二面被问了一个非常硬核的场景题:

面试官: "我们要上线一个送手机的'砍一刀'活动。手机成本 2000 块。 面对海量并发和黑产刷单,你怎么设计算法和架构,保证用户能领到手机,但公司绝不会亏本?"

粉丝答:"用 Redis 原子减,每次随机砍个金额......" 面试官打断:"随机?万一前 10 个人每人砍 200,手机不就白送了?或者黑产搞 1000 个机器号来砍,我们岂不是要破产?"

这道题考的不是简单的减法,而是**"概率论控制成本""人性博弈"**。 今天 Fox 就带你拆解这套让全中国人民"又爱又恨"的系统。


一、 核心算法:不是"随机",是"看人下菜碟"

首先要明确:"砍一刀"绝不是真随机!它是一个基于"用户价值(User Value)"的动态定价游戏。

如果手机成本 2000 元,平台愿意付出的**获客成本(CAC)**是 200 元。

算法的核心目标: 必须让你拉够价值 200 元的"人头",才能给你手机。

算法策略:价值系数 + 芝诺悖论

1. 每一刀砍多少,取决于"谁在砍"

你以为金额是随机的?错!算法会根据用户画像计算权重:

  • 新用户(贵客): 权重 10.0。一刀下去砍 20 元。(激励你继续拉新)

  • 老用户(熟客): 权重 0.1。一刀下去砍 0.2 元。(因为你已经没啥拉新价值了)

  • 黑产号(垃圾): 权重 0.001。一刀下去砍 0.01 元

2. 永远砍不完的"最后一刀"

当进度条达到 99% 时,算法进入**"收敛模式"。 剩余金额不再是"钱",而是一个 数学极限**。 假设还差 1 元,算法会把这 1 元切分成无限份:0.5 + 0.2 + 0.1 + ... 无论你拉多少人,金额永远无限逼近 0,却很难等于 0。这就是数学上的**"芝诺悖论"**。

bash 复制代码
// 伪代码:基于权重的动态砍价public BigDecimal cut(User helper) {// 1. 获取帮砍人的画像权重 (0.01 ~ 10.0)BigDecimal weight = UserProfileService.getWeight(helper.getId());// 2. 计算基准金额 (剩余金额 * 衰减系数)BigDecimal base = remainAmount.multiply(DECAY_RATE);// 3. 最终金额 = 基准 * 权重// 4. 兜底逻辑:最小不能少于 1 分钱(对应存储的 10000 微)return calculate(base, weight);}

二、 架构设计:高并发下的"防刷墙"

算法保证了不亏,架构要保证**"不崩"**。

1. 金额存储:Integer 优于 BigDecimal

坑点: 在 Redis 里存浮点数(String)进行计算,慢且有精度风险。

解法:"去小数点化" 。将金额单位转为 "微" (1 元 = 1,000,000 微)。 Redis 里存的是 Long 类型的整数,Lua 脚本执行 DECRBY 是纳秒级的,且绝对精准

2. 解决"大 V 热 Key"问题

如果某个大 V 分享了链接,瞬间涌入 100 万人帮砍,Redis 单个 Key 会被打爆。

解法:"本地缓存(LocalCache)前置"

  • 对于超级热单,在应用服务器(JVM)层做一层缓存,拦截 90% 的无效查询。

  • 写入时利用 MQ 削峰填谷,串行处理砍价请求,前端只显示"砍价中..."。


三、 核心风控:与黑产的"图灵博弈"

这是面试官最想听的部分。如果 1000 个机器人瞬间把 2000 元砍完了,算法再好也没用。

1. 设备指纹 + 行为生物学

不要只看 IP。要看陀螺仪、按压面积 。真人在砍价时,手指按压屏幕的面积是变化的,手机会有轻微物理抖动;而脚本的数据是死板的。 策略: 识别为机器人的,执行**"风控降权"**------前端提示砍价成功,后台实际扣减金额为 0

2. 终极杀招:强制图灵测试

现在的高级云控脚本已经能模拟陀螺仪了。怎么办?

解法: 在砍价的关键节点 (如最后 1 元、最后 0.01 元),强制弹出**"滑动拼图""选字验证码"**。 这一招能直接废掉 99% 的自动化脚本,因为打码平台的响应速度赶不上用户的并发速度。


四、 致命争议:为什么最后变成了"金币"?

很多人骂拼多多:"明明显示还差 0.01 元,我拉了人,怎么变成了送金币?" 这其实是技术与法务的"保命策略"。

技术真相: 数据库里的金额已经拆分到 1 微(0.000001 元) 了,但前端只能显示 2 位小数。继续砍金额,用户会发现数字**"不动了"**(看起来像 Bug)。

产品黑魔术------"单位置换(Unit Switch)":为了让游戏继续,系统会把"金额模式" 切换为 "道具模式"

  • 还差 0.01 元 -> 抽到"10 个金币" -> 100 金币换 0.01 元。

  • 还差 1 金币 -> 抽到"1 个碎片" -> 10 个碎片换 1 金币。 本质: 通过不断贬值货币单位,把进度条无限拉长,让你永远觉得**"只差一点点"**。


五、 面试标准回答模板

下次面试被问到"设计砍一刀",请按这个套路输出:

"面试官,这个系统的核心不是随机算法,而是 '基于 CAC(获客成本)的动态定价模型'

  1. 算法层: 利用 '用户价值权重''芝诺悖论',确保金额无限收敛但不为零。

  2. 存储层: Redis 中使用 'Long 类型(单位:微)' 存储金额,避免浮点数精度问题,提升 Lua 执行效率。

  3. 风控层: 组合使用 '生物探针' (陀螺仪)和 '关键节点验证码'(图灵测试)拦截脚本。

  4. 产品策略: 在精度耗尽时,启用 '单位置换'(切金币/碎片),既规避了技术尴尬,又合法地延长了用户留存。"


写在最后

"砍一刀"的本质,不是技术,而是对人性的精准计算 。 技术保证了**"平台不亏",而心理学保证了用户"觉得能赢"**。 当你理解了这一点,你写的代码就不再是冷冰冰的逻辑,而是商业的引擎。

觉得有收获的,点个赞,转发给那个总让你"砍一刀"的朋友!

关注公众号【Fox爱分享】,这里没有八股文,只有被坑出来的血泪经验。

文章首发地址

相关推荐
NGC_66111 小时前
归并排序算法
java·数据结构·算法
你撅嘴真丑1 小时前
第十章-训练参考
算法
初次攀爬者2 小时前
Redis分布式锁实现的三种方式-基于setnx,lua脚本和Redisson
redis·分布式·后端
UrbanJazzerati2 小时前
Python Web项目环境配置:从开发到生产的 `.env`文件完全指南
后端·面试
岛雨QA2 小时前
稀疏数组和队列「Java数据结构与算法学习笔记2」
数据结构·算法
Lazy_zheng2 小时前
一文读懂:CommonJS 和 ES Module 的本质区别
前端·面试·前端工程化
沉在嵌入式的鱼2 小时前
温度嵌入式软件算法补偿方案及步骤
stm32·单片机·算法·温度传感器·温度补偿
Pitiless-invader2 小时前
MySQL 相关知识及面试问题汇总
面试·职场和发展