原子性判断,防并发思路
<?php /** * 高并发原子性 true/false 业务设置 * 每个限制业务1000W用户 内存占用 2.5MB 10000W用户 内存占用12MB * @author MikePeng */ class Model_Atombit extends Model_Tables{ const BUCKET = 1000000; //业务限制类型 高并发业务true/false检测模块 public static $aModeList = array( 'isplaypoker'=>array( //用户今天是否玩牌 'time' => 'Ymd', //业务按天限制 'expire' => 86400, //限制过期时间 ), ); public static function redis(){ return mm::redis('limit'); } /** * 原子性设置 状态值,同一业务 同一用户只能设置一次 * @param int $mid 要设置的用户mid * @param int $mode 要设置的业务 * @param boole $value 要设置的值 1/0 * @param int $time 业务时间戳 * @param int $bucket 是否需要拆分桶 因为bit操作有512MB限制 假如一个业务的内存占用超过此值 务必采用桶模式存储 * @return 0/1 业务设置前的值 */ public function setAtomBit($mid,$mode,$value=1,$time=0,$bucket=false){ if( !($config = self::$aModeList[$mode]) ){ fc::debug(date('Ymd H:i:s')."|{$mid}-{$mode} is not find!", __FUNCTION__.'_error.log', 10); return false; } //设置原子桶ID $bucketid = $bucket ? ceil($mid/self::BUCKET) : 0; //根据桶余数表示用户在此桶的位置 $mid = $bucket ? $mid%self::BUCKET : $mid; $date = $time ? date($config['time'],$time) : date('Ymd'); $cachekey = $this->_getCacheKey($mode,$date,$bucketid); $value = $value ? 1 : 0; $flag = self::redis()->setBit($cachekey,$mid,$value); self::redis()->expire($cachekey,$config['expire']); return $flag; } /** * 获取用户具体业务的限制值 * @param int $mid 要设置的用户mid * @param int $mode 要设置的业务 */ public function getAtomBit($mid,$mode){ if( !($config = self::$aModeList[$mode]) ){ return false; } $cachekey = $this->_getCacheKey($mode,$config['time']); return self::redis()->getBit($cachekey,$mid); } } 例子 public function statisticsNewPlay($api, $mid, $aData) { $mstatModel = mm::model('mstat'); $statModel = mm::model('stat'); $aMidCache = $mstatModel->mget($mid); if( !mm::model('atombit')->setAtomBit($mid,'isplaypoker',1,$aData['begin_time']) ){ $statModel->incrby($api, 'otherStat', 'lgplay'); if( !$aMidCache['lgdays'] || $aMidCache['lgdays']<2 ){ $statModel->incrby($api, 'otherStat', 'firstplay'); } } $mstatModel->mset($mid, array('lastplaytime' => $aData['begin_time']));//更新最后一次玩牌时间 $mstatModel->incrby($mid, 'plays');//玩一局牌后,往里加玩牌数 if ($aMidCache['plays'] >= 2) { mm::model('validated')->updc(date('Ymd', time()), $mid); } mm::model('mstatmonth')->update($mid, $aData['begin_time']); }