实战--积分投票系统血泪教训

好几天没有写博客了,一直忙这写这个积分投票-兑换礼包系统.有非常多血泪的教训来分享下: 
之前,我一直是写手机接口的,跟前端基本上没有交集,即使有也是给内部提供管理平台: 
1.实时性:大量的操作是建立在memcache缓存的基础上的,mysql数据库是为了提供数据持久性和记录日志的.因此查询之前会先訪问缓存,假设缓存不存在或者失效,去訪问数据库. 


2.数据量比較大:数据库的索引没有建立到最好. 


3.权限的问题,不是全部人都拥有权限能够投票,于是我把拥有权限的用户id放入了一个数组中并放在缓存,同步到数据库里面,最后发现这次投票人数特别多,每次查询一个用户的权限,须要把全部人的权限都拿出来,使用in_array(),来推断,主管发现后,果断改啊,每一个用户使用独立的key来保存是否拥有权限. 

4.安全性:从前端传递过来的參数要假设是不可靠的,在兑换礼包的时候,我从前端传递过来了礼包的类型和要扣除的积分,放入数据库中,哎!首先悲剧的就是要扣除的积分不能是传递过来的,而是依据礼包的类型来推断.而且要把礼包的类型做出范围配置来检查是否合法.刚写完程序的时候,主管看了看然后请求了一个url: www.example.com/?type=6&score=1,本来第六个礼包要扣除积分80个,结果如今仅仅扣除1个积分用户就领取到了第六个礼包.然后要推断礼包仅仅有六中type应该大于1,小于7.写成配置文件来推断例如以下:

/**
 * @brief 将礼包相应扣除的积分写成配置。不要相信用户提交的数据,
 * @return array();
 */
public function getTypes() {
    return array(
            11 => 5,    //礼包1相应扣除的积分5,同下
            12 => 10,
            13 => 20,
            14 => 30,
            15 => 50,
            16 => 80
    );
}

5.防止刷积分的处理:假设用机器大量高速请求,有可能出现server挂掉,且出现一个人领取多个礼包,因此将用户id:uid和礼包类型:type做唯一索引: 
UNIQUE KEY unique_uid_type (uid,type), 
在memcache中存入一个1s过期的key,保证一个uid每秒仅仅能领取一次礼包.

6.一些非实时的数据,採用数据查询时从缓存中读取,不存在再从数据库读取;增删改时清除该key的缓存.下次从数据库读取.结果因为仅仅改变了查询的时候的缓存的key,没有改 增删改 数据时缓存的key,导致数据全部从数据库中读取..因此一定要保证,写入缓存和读取缓存的key保持一致.否则...

7.因为有非常多页面,须要共享用户的信息,而用户信息须要经过处理,就把用户的信息放到了__construct()里面,也就是说全部的页面都会处理用户信息,结果有几个页面是不使用用户信息的...

8.命名的规范:对缓存命名时必须遵循团队规范,否则可能会和其它开发者发生缓存key冲突.

9.特殊字符的编码处理:username是utf-8编码的,而程序中是gbk编码的,结果转码后发现,username凌乱了.处理办法:copy到txt文档中使用记事本打开,又一次复制一遍,非常多的username中会出现特殊字符比方双引號等,使用:htmlspecialchars();

10.数据表中添加一个create_time,用来记录时间排除bug

11.缓存设置的时间要依据详细的业务逻辑来设计,比方以下的场景:用户投票和兑换积分一般时间不会超过十分钟,因此,一些非实时的缓存的过期时间设置成10分钟就够了

12.将全部权限的检測封装到一个函数中统一处理,是代码更简洁方便

13.jsonencode()不能处理gbk编码:jsonencode('gbk','utf-8',$array);

这次的任务做的太失败了,太凌乱了,写出来的总结感觉也非常凌乱,心情不爽,以后慢慢改吧!记录下来做日志,防止再犯相同的错误