焦点

购物返积分抽奖源码

时间:2010-12-5 17:23:32  作者:知识   来源:时尚  查看:  评论:0
内容摘要:去年帮一个做美妆电商的朋友改代码,他那个“购物返积分抽奖”活动上线三天,服务器崩了两次。不是流量太大,是积分发放逻辑写成了同步阻塞——每笔订单完成都要等积分写入、抽奖次数更新、奖品池扣减全部跑完才返回

去年帮一个做美妆电商的购物朋友改代码,他那个“购物返积分抽奖”活动上线三天,返积分抽服务器崩了两次。奖源不是购物流量太大,是返积分抽积分发放逻辑写成了同步阻塞——每笔订单完成都要等积分写入、抽奖次数更新、奖源奖品池扣减全部跑完才返回成功。购物用户点一次结算,返积分抽后台串行跑四五个数据库操作,奖源不崩才怪。购物

这套源码的返积分抽核心其实就三块:积分累积、抽奖触发、奖源奖品分发。购物但很多人一上来就写抽奖算法,返积分抽把积分当附属品,奖源结果活动跑起来发现积分对不上账。我见过最离谱的一个项目,用户买了500块的东西,返了500积分,但抽奖一次扣10积分,用户抽了50次之后积分显示-20。查了半天,是并发扣减没加锁,两个请求同时读到积分余额100,各自扣10,写回去都是90,实际应该扣20。

// 错误示范:先读后写,并发下必出问题 $points = get_user_points($uid); if ($points >= 10) {  update_points($uid, $points - 10); do_lottery($uid); } 

正确的做法是用数据库原子操作,或者Redis的DECR。积分这东西,宁可少发也不能超发,超发就是真金白银的损失。我朋友那个项目后来改成先扣积分再抽奖,扣减用UPDATE user_points SET points = points - 10 WHERE uid = ? AND points >= 10,影响行数为1才继续。就这么一个改动,崩溃问题直接消失。

抽奖概率别写死在代码里

见过太多人把奖品概率硬编码在PHP数组里,改个中奖率要重新部署。运营那边急得跳脚,技术这边还在走发布流程。正确姿势是概率配置存数据库,后台可调,代码里只做权重计算。比如一等奖权重1,二等奖权重10,三等奖权重100,总权重111,生成1-111的随机数,落在哪个区间就是哪个奖。

但这里有个坑:库存。权重算出来是一等奖,结果库存没了,你得降级到二等奖。降级逻辑要写得干净,别嵌套一堆if-else。我习惯把奖品按权重排序,从高到低遍历,库存为0就跳过,第一个有库存且随机数命中的就是结果。这样代码短,逻辑也清楚。

积分有效期是个隐形炸弹

很多源码只写了积分增加,没写积分过期。用户攒了两年积分,突然要兑奖,你发现数据库里一堆历史积分,兑还是不兑?兑了成本爆炸,不兑用户投诉。我建议积分表加个expire_at字段,发放时设置有效期,比如一年。查询可用积分时带上expire_at > NOW(),过期的积分定时任务清理或者标记失效。

还有个细节:退款。用户买了东西返了积分,抽了奖,然后申请退款。积分要不要扣回?奖品要不要追回?源码里必须处理这个逆向流程。我朋友那个项目就是漏了退款逻辑,被人薅了几万块。后来加了退款钩子,扣回对应积分,如果积分不够扣就扣成负数,下次购物返积分先抵扣负数。

抽奖接口要做频率限制

没限流的抽奖接口等于把奖品池敞开给脚本。同一个用户一秒抽一百次,你后台日志都来不及记。简单做法是用Redis给每个用户加个lottery:uid的key,设置1秒过期,存在就拒绝。复杂点用令牌桶,但小项目没必要。还有,抽奖结果要记日志,谁、什么时候、扣了多少积分、中了什么、奖品发放状态。出了问题全靠这张表追溯。

源码这东西,网上开源的很多,但能直接用的少。大部分只写了主流程,边界情况全没处理。你拿过来跑个demo没问题,上线就是事故。我的建议是:积分扣减必须原子、概率必须可配、库存必须校验、退款必须回滚、接口必须限流。这五点做到了,再谈用户体验和活动效果。

最近更新
热门排行
copyright © 2026 powered by 烟消火灭网   sitemap