做秒杀的深有体会
做抽奖的深有体会
体会什么?
奖品不一会儿就被抽光了??纳尼(一脸懵逼)
说好的这些奖品要维持一天呢!!
去数据库查查去~
这货怎么能有两个订单??不是说好的一个用户只能抽奖一次么!!(沮丧脸)
这货又是谁?他们的名字怎么那么相似??(挖日)
感觉要被老板艹翻了!我出1毛钱谁能帮我砍X老板,在线等,急~(滑稽脸)
下面言归正传
在做营销活动时候会经常遇到上面这些情况,咋办。
一、对于同一个用户能违规提交多个订单的情况
在用户抽奖时候都要检测一下用户上次抽奖产生的标识符,比如在缓存中存储的一个值。比如这个样子
Util.CacheManager.InsertCache(KeyName + UserModel.ID,"1", DateTime.Now.AddSeconds(10));
如果下次抽奖的时候这个值还在,说明两次抽奖间隔小于10s,那么给与相关提示,比如:抽奖关于频繁拉
验证通过后进入下一步。
为用户生成一个标志,在缓存中,对缓存的插入操作一定要是线程安全的,(线程安全圈起来这是重点,要考)。比如这样:
object timeobje = Util.CacheManager.GetCache(KeyName + UserModel.ID);
当然你也可以使用redis,memcached 等缓存服务来实现这种方式。
引申一下你可以使用乐观锁来实现:用户请求进入时候为用户创建一个标识值,插入订单前判断这个值是否变化,变化了,放弃本次操作,未变化,继续本次操作。
redis,memcached 都提供有相关功能。
使用了上述手段就能完全避免恶意的提交么? 否 ,但是能解决绝大部分恶意的提交
有没有完全的解决方案? 我这里暂时没有
你也可以参考他们的文章:
http://blog.csdn.net/zlhzhj/article/details/51245807
http://blog.csdn.net/lvqingyao520/article/details/52974217
二、多个相类似的用户,通过正常的流程进行活动
通过实名认证来解决? 优点:可以98%的规避机器人注册账号和提高用户的真实性 。 缺点:认证成本高,流程麻烦,用户粘性小,不适合营销活动
封IP?有点:能屏蔽部分非法注册和非法参与活动的人。 缺点:使用代理的用户可以轻松绕过,会误伤同一个局域网的用户,比如同一个办公室的
通过算法分析用户行为?优点:可靠程度比较高,针对性比较强,误伤率低 缺点:得有个会写相关算法分析的
以上为个人看法,通常我们的营销活动对于这种情况的选择都是:忽略(滑稽脸,不要扔砖)
三、那我们是怎样确保奖品不会很快被人抽光呢?重点来了,开始集中活力,哦不是注意力~~
在活动中将整个活动时间换算成秒,然后拿来除以奖品总数量 。比如一天有 (24*60*60s)/(3000个奖品)得到平均两个奖品发放时间间隔(得到值A),当然平均时间发放容易让人诟病,做营销活动的知道,总是能遇到
死缠烂打的这样的一些爱占便宜的和钻牛角尖的用户。我们总归有办法解决这个问题(废话)。
根据活动结束时间和最后一次发奖时间 之差 (得到值B)作为随机数种子
根据已经发放的奖品数量得到完美的情况下理论上需要使用的时间(A*发放的奖品数量,得到值C)
用活动开始时间+C+随机时间(使用种子B得到,这样每个Random第一次Next()得到的值是固定的)得到下个奖品的发放时间 (得到时间D)
如果当前时间>=时间D 则说明下个奖品应该发放了。即:发放给时间D之后第一个进入抽奖的用户
罗哩罗嗦的,说的有点蒙。~~~~~~~~来让我们看看代码吧
/// <summary> /// 奖项 /// </summary> public interface IAward { /// <summary> /// 奖品编号 /// </summary> int ID { get; set; } /// <summary> /// 奖品名称 /// </summary> string Name { get; set; } /// <summary> /// 奖品剩余数量 /// </summary> int SurplusCount { get; set; } /// <summary> /// 产品总数 /// </summary> int TotalCount { get; set; } /// <summary> /// 奖品位置 /// </summary> int TurnLocation { get; set; } /// <summary> /// 商品价格 /// </summary> decimal TurnPrice { get; set; } /// <summary> /// 最后一次被抽中时间 /// </summary> DateTime LastWinningTime { get; set; } }