zoukankan      html  css  js  c++  java
  • 项目 经验记录

         最近工作很忙,为什么呢?因为双11快到了,作为电商公司的技术部苦逼程序员,又到了需求满天飞的时候了。赶上这几天项目提测,稍微空闲一点,决定好好写篇随笔。记录一下最近工作上的收获。

         双11,我们组接到的一个需求是 抽奖转盘的开发。公司以前有着专门的抽奖系统的,但是现在听说是压力很大,而且以前的设计也不太好,现在需要重新开发一个专门的抽奖系统。不止双11使用,以后作为公司开展抽奖,使用的都是这个抽奖系统了。我们组是后台组,抽奖页面的开发并不是属于我们的。我们的需求大概是:

    1)建造一个抽奖后台,包括三个页面,分别是:抽奖活动管理页面,查询抽奖名单页面,设置抽奖条件页面。共业务使用

    2)给前台提供一个抽奖API,实现抽奖

    3) 作业,将抽奖结果写进中奖表,在后台抽奖显示页面显示

    具体的就不细写了。由于我一直都是负责后台对外API这块,因此我就负责了此次的API编写。另外两个同事一个负责页面开发,一个负责作业编写。

    考虑到抽奖活动的特殊性,就是高并发,大流量,因此对API的响应时间有很高要求,因此在开发方案讨论时,就决定API需要的数据全部存储在redis中。

    再说一下API设计思路

    分三个类:1)活动类,包含活动开始时间,结束时间,是否100%中奖,活动资格数组(身份限制,消费限制等),奖品库存

    2)抽奖者类 ,包含抽奖者身份(vip,普通用户),资格(是否有资格),抽奖剩余次数

    3)抽奖类,实现抽奖。

    客户端的流程大概是:

    1 获取活动类开始时间,结束时间,判断活动是否正在进行

    2 获取用户资格

    3 获取用户抽奖次数

    4 抽奖

    API中存在的难点有几个

    1 奖品抽完了,转为不中奖。因为是高并发,可能存在一个用户在判断库存之后,另一个用户抽到了,抽完了,数据不一致。解决办法:读库存的时候同时减一,如果这个原子操作存在的话,就可以避免高并发情况下抽奖抽超了的情况。幸好,redis的decr是这么一个原子操作。

    2 次数的维护,也是判断用户是否还有次数的同时,把次数减一。避免了恶意刷新。

    3 整个活动期间次数限制和每天刷新次数的两种情况。最后的解决办法是在次数的存储上,如果是按天刷新次数,在key里面加上日期来区分。

    4 一定中奖策略的实现。其实这个还好。需要维护一个数组。

    最后这个项目由于并发高,流量大,肯定是单独部署的。一共申请了8台服务器做轮询,2台redis作为缓存。单独部署也避免了对现有的系统造成影响。

    2014年11月14日晚间补充:

    忙的时候是双11之前,这几天还算闲。今天周五,组长召集我们开了个会。好久没开组会了。会上回顾了近期做的项目,说到了这个抽奖项目。这个项目是比较锻炼人的一个项目了。组长还说最近面试几个高级工程师,都把我们这个项目作为一个高并发实例,问了一下几个面试者,看看他们的设计思路,如何解决难点。晚上回来途中,还和另外一个组同事说了 一下这个项目。决心今晚加点内容。

    这个项目对我来说,是一次很好的锻炼机会,我也得到了比较大的提升。

    说一下技术难点吧:

    1 API相应速度:

    抽奖API反应时间要短,支持高并发,首先做轮询(六台服务器),然后API请求数据全部存入redis。

    2 防止奖品抽过量

    奖品m 库存目前为1 ,请求A B 同时到达,都中奖了,为m。  A B 都要请求 m的库存,发现库存为1,结果两个显示都中奖,导致抽超了。

    利用redis的操作decr,返回减一之后的结果,这是一个原子操作。redis是单线程的,不会存在两个命令同时操作一条数据,命令会排队的。

    这样A 在判断m的库存有没有的时候就把m的库存-1了,B 再去判断时就没有库存了,把B的中奖结果转为不中奖。

    3 次数防止过量

    跟奖品抽超 一样的解决,读的时候同时减一。

    4 如何解决整个活动周期有n次抽奖机会和每天有n次抽奖机会的重置。

    什么意思呢,比如说业务在后台设置 活动期间每天有三次机会抽奖,那么到了每天凌晨,这个数要重置,很多用户的话,那么这个重置就比较耗时间了。

    例如,用户次数存入redis是这样的    lottery|activity_id:12|cust_id:765|times =>3  表示用户765在活动12中每天都三次机会,耗掉一次 -1.

    解决方案 如果用户每天有三次的话,在上面的key上加上日期,这样每天的次数就有了。

    lottery|activity_id:12|cust_id:765|times|data:20141014

    如果是整个活动周期,那么我们就不带日期

    5 异步处理中奖结果

    API 运行得到中奖奖品id时,往list里面写一条纪录,直接返回。处理中奖结果,交给作业来处理,这样就是异步处理了。作业将中奖明细写入库

    例如说中奖奖品是一个礼券,那么就要执行绑定礼券的操作,API只负责往list里面写入,具体的绑定礼券交由作业后续处理。这样做的好处一个是API响应快,更外一个作业绑定礼券后台执行,对礼券接口压力小,(不用高并发,接口绑定的话那么绑定礼券就是高并发了)。

    此处的list用来做队列。若redis当掉了,会丢失一部分数据。架构师的意见是 使用消息中间件。

    6 前台跨域调用我的API

    前台只负责做一个页面,js还要我们提供。最好发现是跨域。这个在我的其他博客中有详细讲解,不再赘述。

    7 中奖算法,分为100%中奖和非100%中奖

    非100%中奖:产生随机数,落在哪个区间,返回那个奖品,若奖品库存为空,之间转为不中奖

    100%中奖: 维护一个中奖概率数组array(‘A’=>2,'B'=>3);产生一个随机数,落在哪个区间,哪个中奖,若库存为空,维护的数组中踢掉那一项,所有库存为空,返回奖品被抽完的提示信息。

    主要是以上几点,后续若有想起来的,再做补充。

    太久没总结,文笔不太好。希望提高。

  • 相关阅读:
    30天养成一个好习惯
    ym——安卓巴士总结了近百个Android优秀开源项
    内存泄漏以及常见的解决方法
    Android学习笔记(四十):Preference的使用
    Android中View绘制流程以及invalidate()等相关方法分析
    NumberFormat 类
    开发人员福利!ChromeSnifferPlus 插件正式登陆 Chrome Web Store
    memset函数具体说明
    分分钟教会你使用HTML写Web页面
    UVA 465 (13.08.02)
  • 原文地址:https://www.cnblogs.com/taijun/p/4040823.html
Copyright © 2011-2022 走看看