哞菇神社

搞事的心是你的魔法!记录一次校庆活动的全过程

2017.07.05 / 技术 / 点击 442 / 回复 8 / PHP, ThinkPHP, 搞事, 记录, 学校

好像又有大半年没有更新博客了,最近在学校独立策划上线了一次基于微信的活动游戏。
中途经历了几次大起大落,感觉充满了人生的经验。
无论是在技术上或是在策划和执行的环节上,难得有这样的机会去付诸实现面对大量用户的检验。
总结一下发出来吧-w-+

01 校庆做点啥?万恶的起源!

学校微光网络工作室是品牌部下属组织,致力于打造学校网络媒体品牌,构建弘扬具有东软特色的网络文化。团队主要负责学校网站项目和相关互联网产品的策划开发、运营和推广。.(捧读)
学校6月16号校庆,今年品牌部的老佛爷来闲聊,想要看看校庆做点什么活动。聊着聊着,话题就跑偏到了最近大家玩的手游。
讲道理啊,不知道为什么,现在人的收集欲为什么这么强啊,同寝室的土豪室友为了氪手游听说充了上千块了。
那么最近参与最多的卡片集换式游戏是什么呢?
当蓝是春节时候敬业福了!

通过一定的方式收集卡片,卡片可以互相流通,形成自发分享和互动,最后通过集卡完成目标来换取奖励。

听起来就是这么的富有实用价值,稳赚不赔啊!就做这个,但是这里有几个问题

1、 获取卡片的方式?
2、 奖励是什么?

问题二的问题不是一个问题,学校这边可以提供大量的学校限定周边,嘿嘿嘿。但是问题一就需要解决咯。
像是支付宝去年的“咻一咻”,推广了支付宝基于地理位置的线下支付业务,今年的扫福字,用H5做起来在技术上又有一定的难度,
经过了工作室几个人一顿头脑风暴,

1、 获取卡片的方式不能太简单
2、 获取卡片的方式对品牌宣传有实际意义

结果一直咕咕咕到上线前几周,我才联系到之前做的OtakuTester,用答题的方式,答对一定数量的题目之后就可以获得卡片。

于是一切就这么串起来了,东软版的敬业福这样上线了。

NeuQA流程图

NeuQA预览

通过微信活动进行推送,用答题的方式来随机获得四张活动卡片,获得的卡片可以通过分享的方式分享給其他好友,集齐四张卡片就可以抽取奖品,奖品分为三个等级,100%中奖。

轻松愉快的活动套路经过了大家的一致满意通过,于是我想了想,给活动起了个响亮的名字,“NeuQ&A”。

至于技术选型,害怕爆炸的我用了当时用着最拿手的ThinkPHP3.2,前端粗暴的用jQuery怼出来。
ThinkPHP很可爱的你们不要黑他

但是令我没想到的是,在经历了活动艰难上线,上线后瞬间爆炸,爆炸后连环多重炸,等等一系列故事之后,这大概变成了我难忘的一次小尝试。
接下来是关于这些小事中大事的一些记录,现在想想,真tm坑哇!!!

02 人人有份!通过埋点发进行抢占式的精确抽奖

进入到了程序开发部分,因为是TP3.2,当时拍黄片的技术也很糟糕,大部分都是粗暴的的怼库怼库怼库操作,直到发奖这里问题就出来了。

参与抽奖人数无法确定的情况下如何保证有限的奖品在有限的时间内可以被平均抽取?

传统的按照比例来调节的方式显然不太靠谱。
之前的晚会上尝试过手动调节的方案,一边疯狂刷新数据查看库存,一遍满头大汗的调节中奖几率,最后奖品还是发快了,导致活动后期的中奖率很低的经历还历历在目。更何况这次的活动要持续三天,人工调节中奖几率是不现实的。
在网上收集资料和评估之后,我们使用了抢占式发奖的方案。

设定一张卡片为稀有卡片,这张卡片的中奖数量和奖品数量相同。
在活动时间上随机或者加权随机生成时间点作为中奖点。
在这个中奖点之后领奖的用户获得这一时间点上的奖品。

这样就以时间为基准,设定了中奖的问题。

啊对了,好像有要求,抽卡游戏必须公布中奖概率,在这里我也权威发布一下我们的中奖概率(震声)

$rand = mt_rand(0,100);
if($rand>=0&&$rand<35)    $card = "1";//卡1:35%
if($rand>=35&&$rand<70)   $card = "2";//卡2:35%
if($rand>=70&&$rand<=100)   $card = "3";//卡3:30%

至于稀有的卡4和奖品数量一样,都是616张,平均分布到了活动时间上。

NeuQA后台稀有卡片截图

我和你们讲,我这游戏一点也不坑的!

03 上线后的噩梦:依赖于框架的我摔倒了

2017年6月14日晚上8点半,那是我难以忘记的时刻,我端坐在工作室,如临大敌。
上线前已经测试了多次,没有任何问题,于是我胸有成竹的关闭了调试模式,准备进行发布。
稀有卡片数据ok,奖池重置ok,中奖数据清空ok
时间一到,之间服务器的nginx日志哗哗的刷起来,我蹲在后台看着数据蹭蹭往上涨,正欣喜万分。

突然发现哪里不对,稀有卡片的数量突然变少了,说明有人兑奖了,查看奖品列表,没有减少,中奖数量却还是0。

赶紧爬起来去看错误日志,发现了奇怪的错误。

ERR: 1364:Field 'avatar' doesn't have a default value
 [ SQL语句 ] : INSERT INTO `xxx_prize` (`user`,`shared`,`time_create`,`get`,`flag`,`type`) VALUES ('1','0','1497445790','0','0','0')

诶诶诶诶诶?尼玛奖品怎么怼不进去数据库了?我的用户信息用户名和头像哪去了?被吃了?
赶紧跑去看了代码:

$prize['avatar'] = session('user.headimgurl');
$prize['name'] = session('user.nickname');
$prize['prize_name'] = $jackpot[$prizeid]['name'];
$result = $db_prize->add($prize);

这不是有传入吗!!!

又跑去检查了session,用户信息储存的清清楚楚。
就算session为空也应该传入一个null才对,不可能这个字段都消失了。

我顿时慌了,在我爆炸的检查的功夫,又有几个人在活动一开始的时候就集齐了卡片并兑奖,错误日志里又多出了几条巨大的ERROR。

顿时他们的遭遇在我的脑海中放起了小电影——

他们是这个活动的幸运儿,
活动刚开始就集齐了四张卡片,
开心的点了兑奖按钮,然后——
“Oppos!出错啦!”

Biu的一下,卡…没了,奖品…也没领上。
卧槽我要是用户直接就炸了,你这是欺诈!赤果果的欺诈!

感觉我正在被问候着。赶忙先关闭了兑奖功能,并给了个“诶嘿,兑奖功能修复中★~”的提示(你卖萌也没用啊!!!

时间一分一秒的过去,老佛爷和小伙伴们围在我的后面盯着,一边日志以看不清的速度刷屏,而我现在连问题是啥情况都无法理解,好好的数据怎么就没了?我万念俱灰。

HELP!!救命!!助けて!!

连滚带爬的跑去给大佬@sylingd打了电话,连上服务器进行处理。

说明问题之后,大佬没怎么看日志开始使用xdebug进行调试,很快定位到了问题。

大概情况就是因为之前开发过程中我修改过数据表的结构,而thinkPHP在调试模式并不会care缓存。
上线前我关闭调试模式后,缓存没有刷新,而且服务器上的Runtime临时目录权限有问题也无法刷新缓存。
导致缓存的表结构和数据库表结构不符,那两个字段直接被丢掉了。

详细的原因后来大佬也整理出来发了篇博客,《使用xdebug调试PHP程序(实例)》https://blog.sylingd.com/archives/335.html

问题很快解决了,大概20分钟后,兑奖功能就恢复并且重新上线,之前没有成功兑奖的几个人也能从之前的错误日志里抓出来uid补发奖品。没有造成什么太大的问题。

但是这一下也好疼哇,一直以来自己的PHP完全依赖于框架,对于框架的一些特性和细节又不是特别了解,像是这个数据库字段缓存,我之前几乎就没接触过,完全不知道怎么处理,大概我研究处理下去,花了很久之后也只能搞明白是调试模式的问题而没有后文了。

Xdebug也很重要,虽然跟踪出来的日志上万行,看着眼睛都疼,但是重要的细节也就那几行,要静下心读嘛。

本以为这样就ok了,但是毕竟还是too young。

04 数学老师请救我:差集?差集!

感觉解决了上面这个隐藏很深的bug,应该可以完事无忧了,第二天,隔壁一个群里传出了消息。
“独家独家!答题只要全选就可以全对。” 顿时……瞬间爆炸
的确之前测试的时候没有想过测试全选的情况,跑去试了一下,真的如此,打开答题部分的代码,大概长成这个样子

    $option_right = explode('.',$qes['opition_right']);//正确答案数组
    $option_choosed = explode('.',I('post.qesid_'.$questionlist[$i]));//已选选项数组
            
    $diff = array_diff($option_right,$option_choosed);//判断是否相同
            
    if(empty($diff))  //正解!!

大概明白,问题出在array_diff这个函数上了,去翻了手册
http://php.net/manual/zh/function.array-diff.php

array_diff — 计算数组的差集
“差集”,这一简单的词语突然显得是如此复杂。

打电话询问了数学好一点的小伙伴才知道……

array_diff( [1,3] , [1,2,3,4] ) -> null
array_diff( [1,2,3,4] , [1,3] ) -> [2,4]

也就是1,3和1,2,3,4的差集是空……所以我还需要反过来再判断一下
天上放起了绚丽的烟花,啪,啪,啪

感觉构成世界的基石崩塌了……

我至今还是觉得,这个函数叫array diff,diff是啥哇,different啊!我英语不好你不要骗我!我数学不好你也不能骗我哇!!
这大概也能解释清楚为什么今年答题数据格外的好,平均每个人答题28份的原因吧……
解决了这个bug,但是卡片和奖品已经发出去了,不可能收回,我知道望向那遥远的天空,再一次怀念起我的数学老师,哦对,当时我还偷偷的做他的表情包来着呢。

数学老师的表情包

05 “我好菜啊”,从这次活动中暴露出的问题和问题以及问题们

至于活动的成果,还是相当可观的,产生了30w+的PV,
活动统计

活动告一段落之后,突然感觉到害怕,如果以后在产品上发生了这样的问题,我的钱呢,我的订单呢,我的用户呢,简直是无法想象的事故……
感谢学校和老佛爷能提供这次机会,感谢@sylingd救人于危难之中。
还是很幸运能在学校这样的活动中发现这么多的问题,受到怎么多帮助。
而且自己也应该尝试用那些酷炫的新技术了,总是抱着那几个破玩意玩来玩去是不会有长进的。

转眼间又到了夏天,好热啊……
还有好多想做的事情没做呢!

那么以上。

已有 8 条评论

  1. 看着好刺激,,就像还有两分钟就割接了然而割接一瞬间停电了

  2. 虽然看不懂,但是看着心疼,不过看着幽默的文风莫名想笑,哈哈哈

  3. 过来看看

  4. 让我们切换到高大上的DisQus评论吧!!

    1. 原 生 大 法 好
      不 爽 不 要 用

  5. sy1x sy1x

    我的博客也快写完了,也借鉴了你的博客,嘿嘿嘿,我也是发现多说挂掉了

  6. 啊,喂喂喂!
    顺便测试一下Typecho原生的评论,纪念一下天国的多说。
    蘑菇神社已经切换回Typecho原生评论并且更新了主题增加了评论部分的样式。
    最近顺便还想重新装修一下神社,咕咕咕,很快就会弄好的!咕咕咕。

    1. 王陈 王陈

      棒,读起来惊心动魄啊,哈哈