<?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']);
}