当前位置:首页 > 技术文章 > openx > openx改造工程一: pv统计中memcached的运用(2.8版本以下)
openx改造工程一: pv统计中memcached的运用(2.8版本以下)
文章来源:本站原创  浏览次数:298  发布日期:2013-04-16
在做这次改造之前,我们有必要先了解一下openx pv统计的运行机制。

ox在广告投放之后,我们在火狐下用HTTPFOX跟踪一下,一共有
  • http://localhost/openx/www/delivery/ajs.php?zoneid=1&cb=15028591281&charset=UTF-8&loc=http://www.example.com/test.html

  • http://localhost/openx/www/delivery/ai.php?filename=468×60.gif&contenttype=gif

  • http://locahost/openx/www/delivery/lg.php?bannerid=2&campaignid=1&zoneid=1&loc=http://www.example.com/test.html&cb=0c9f6849c2

您可以看到,第一个URL是用来获取显示广告的代码,第二个URL用来获取实际的广告图片,第三个URL用来调用1×1.gif图片以记录广告PV展示量。由此可见,在lg.php中肯定有做数据库操作的逻辑,用以记录每条广告的pv展示


打开lg.php,跟踪3214行MAX_Delivery_log_logAdImpression这个函数,他这有一个hook(钩子机制)用来回调,我们不去管它,得到最后运行的函数名Plugin_deliveryLog_OxLogImpression_LogImpression_Delivery_logImpression();这个函数就是他对PV展示量插入数据库做的最后一步操作。而且他是每次都会记录,相当于用户每显示一个广告,这里就会向数据库记录一次,这样无疑大大加重了数据库的压力,也可能造成一个瓶颈。

我们要做的就是改写这个函数,加入memcached缓存机制,极大提升他的运行效率。。

具体代码如下:

function Plugin_deliveryLog_OxLogImpression_LogImpression_Delivery_logImpression($adId = 0, $zoneId = 0, $okToLog = true)
 
{
 
    $host = "127.0.0.1";
 
    $port = '11211';
 
    if (!$okToLog) { return false; }
 
    $aData = $GLOBALS['_MAX']['deliveryData'];
 
     
 
    $aQuery = array(
 
        'interval_start' => $aData['interval_start'],
 
        'creative_id'    => $aData['creative_id'],
 
        'zone_id'        => $aData['zone_id']
 
    );//键值对对应表中的字段和内容
 
    $mem = new Memcache;
 
    $mem->connect($host,$port);
 
    date_default_timezone_set("Asia/Shanghai");//设置时间
 
    $year    =((int)substr($aData['interval_start'], 0,4));
 
    $month   =((int)substr($aData['interval_start'], 5,2));
 
    $day     =((int)substr($aData['interval_start'], 8,2));
 
    $h       =((int)substr($aData['interval_start'],11,2));
 
    $timenow = $year."-".$month."-".$day." ".$h.":00:00";
 
    $memkey  = 'logimpression-' . strtotime($timenow).'-'.$aData['creative_id'] .'-'. $aData['zone_id'];
 
    $startnum=$mem->get($memkey);
 
    if(empty($startnum))
 
        $counter=0;
 
    else
 
        $counter=$startnum;
 
    $counter++;//计数器
 
    $mem->set($memkey,$counter,0,36000);
 
}

这样改写之后,对于记录广告pv展示的记录就会以键值对的形式保存在memcached中,而不会每条记录都产生数据库操作。

但是光这样还不行,还要定期处理这些已经保存的PV信息,所以,还需要写一个程序用来处理这些已经存在缓存中的数据,做入库和删除工作,具体代码参考如下:

$host       = '127.0.0.1';    //主机名
 
        $port       = '11211';        //memcached端口号
 
        $mysqluser  = 'root';         //mysql用户名
 
        $mysqlpw    = '';             //mysql密码
 
        $dbname     = 'openx';        //数据库名称
 
        $impcache   = 'logimpression';//广告PV缓存标志
 
        $tablename  = 'ox_data_bkt_m';// 2.8版本,表:data_bkt_m; 2.4或2.6版本,表:data_raw_ad_request,'ox_'为表前缀
 
        //链接数据库
 
        $link = mysql_connect($host, $mysqluser, $mysqlpw);
 
        if (!$link) die('Could not connect: ' . mysql_error());
 
        mysql_select_db($dbname, $link) or die ('Can\'t use foo : ' . mysql_error());
 
        //创建memcached对象
 
        $mem=new Memcache();
 
        $mem->connect($host,$port);
 
            
 
        $items=$mem->getExtendedStats ('items');
 
        $items=$items["$host:$port"]['items'];
 
        if(empty($items)){
 
             echo '当前缓存为空';
 
             exit;
 
        }
 
   foreach($items as $key=>$values){
 
           $number=$key;
 
         $str=$mem->getExtendedStats ("cachedump",$number,0);
 
         $line=$str["$host:$port"];
 
         if( is_array($line) && count($line)>0){
 
             foreach($line as $key=>$value){
 
                 //缓存中大于第一条数据的时间和小于据它一小时之后的所有数据数据
 
                     $deletekey[]   =  $key;
 
                     $keydata[]   =  explode( '-',$key); //获取所有键
 
                     $keyvalues[] =  $mem->get($key);    //获取所有值
 
              }
 
          }
 
    }
 
    //执行数据库插入操作preg_match($preg, $keydata[$i][0])
 
 
    $time =strtotime(date('Y-m-d H:00:00' , time()));//获取当前时间戳
 
    for($i=0;$i<count($keydata);$i++){
 
       if($keydata[$i][0] == $impcache && $keydata[$i][1]<$time){//判断是否为impression缓存
 
           $query = "
 
            INSERT INTO $tablename
 
                (interval_start, creative_id, zone_id, count)
 
                VALUES ('" . date('Y-m-d H:i:s' ,  $keydata[$i][1] ). "' , '" . $keydata[$i][2] . "', '" . $keydata[$i][3] . "', $keyvalues[$i])
 
            ";
 
            $query .= " ON DUPLICATE KEY UPDATE count = count + $keyvalues[$i]";
 
            @mysql_query($query) or die("Mysql Error: " . mysql_error());   //更新数据
 
            $result = $mem->delete($deletekey[$i]);                         //清除相应缓存内容
 
            $count++;
 
        }
 
    }
 
    if($result){
 
        echo '操作完成,成功删除【' .$count. '】条缓存数据' ;
 
        exit;
 
    }else{
 
        echo '没有要删除的数据';
 
    }


以上就完成了OX的pv的改造工作,只需要在服务器写个计划任务,每小时运行一次该文件即可;

经过这样的改造,在pv统计这一块大大减低了数据库的压力,好处不言而喻了。

对于openx,本人也是刚刚学习,如果有不对或者更好的建议,欢迎大家提出宝贵意见。

原文来自:openx改造工程一: pv统计中memcached的运用(2.8版本以下) http://www.redyun.net/technology/81.html

红云案例Case