原子性判断,防并发思路

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

  




posted @ 2017-08-18 10:18  詹老师  阅读(273)  评论(0编辑  收藏  举报