国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

用memcache,文件操作代替數據庫進行及時統計

2024-07-21 02:04:12
字體:
來源:轉載
供稿:網友

一 db ,file i/o應用層面速度的比較

       關于數據庫的i/o操作,將很早以前看過的摘錄也整理下:
       1. 對于i/o操作,大部分是在和buffer打交道,注意這個buffer是數據庫控制的buffer,而不是操作系統的page buffer,真正的物理io,是要對讀入數據進行 合理化的預先組織,即 預先讀,排隊,分塊寫,小數據量寫入。

       2.對于物理i/o動作,db可以通過raw/cooked設備來實現,在raw設備上操作的話,db自己管理設備以及數據在raw設備上的存儲細節,也就是說db對于實際的物理存儲是了解的,比如說,有2塊device,上面各自分別有2個raw devices,那么db可以用2個theread在2個device上面同時動作,對于同一device上面的logical volum, db對數據的預先安排可以大大提高io性能.而文件系統上的io由于有double-buffer,所以數據庫所有對io的優化基本上沒作用(因為db的buffer通常比os的io buffer大的多,當db buffer對應的os buffer映射失敗的時候,io就要通過物理io來完成了,并且db并不知道實際的io操作在物理設備上的實現細節(比如文件系統在物理設備上的位置))。

      3.所有物理的io動作最后還是對應到了r/w操作,只不過在raw方式下的r/w是對設備直接操作的,不需要借助于文件系統實現.

      4. 對于寫操作,數據庫與文件相比,不占任何優勢(都是立即寫磁盤)。唯一就是寫入的數據在buffer里面可控的。
即使是一般的文件讀寫,一般的io操作,因為有page buffer,讀寫,SEEK,再讀寫,仍然比數據庫快的多。但是這個在多次讀的情況下,就不一定了,數據庫的buffer操作,比page buffer快許多。

       其實總體看來,數據庫的強大在于cache的充分運用,和其無敵的查詢功能。其優勢是體現的大量數據的查詢、統計以及并發讀寫,不是在速度上。
       那么在不需要關系運算,不需要海量操作,或者不需要立即查詢數據的情況下,用文件來代替數據庫進行數據記錄,會是一個很好的選擇。

二 動機
       之前做過一個數據統計的處理,因為數據量比較大,不可能對每條及時數據進行入庫處理。原因主要是兩個,個是立即寫入數據庫的速度慢,影響及時統計的效率;另一個是,數據的后期分析,從數據庫順序讀取數據也要比文件系統的順序讀取慢很多。在數據量大的情況下,不能滿足在有限時間內的數據整理工作。

       基于以上原因,就開始考慮及時數據的緩存處理。緩存處理分兩層,一個是memcache層,一個是文件系統層。即先將當前到來的數據,記錄在memcache中,在memcache數據隊列長度達到一定限度時,就將memcache的緩存數據轉移到文件進行存儲。

三 代碼
      很早之前寫的代碼,先抄在下面:
[php]
<?php
/**
*=------------------------------------------------------------------------=
*                         InstantRecorder.php
*=------------------------------------------------------------------------=
*
*
* Copyright(c) 2008 by guigui. All rights reserved.
* @author guigui <evan_gui@163.com>
* @version $Id: InstantRecorder.php, v 1.0 2008/4/21 $
* @package systen
* @link http://www.guigui8.com/index.php/archives/108.html
*
* history:
* 1. add this file. (by 桂桂 on 2008/4/21)
*/
define('INSTANT_DATA_SEP', '|g|');    //及時存儲的數據 字段間的分隔符
define('MAX_MEM_QUEUE_LENGTH', 1000);   //memcached中允許存在記錄條數的最大值
/**
*=--------------------------------------------------------------------=
* class InstantRecorder
*=--------------------------------------------------------------------=
*
* 及時數據記錄類 的 工場類
*
*/
class InstantRecorder
{
/**
  * 獲取及時數據記錄的對象實例
  *
  * @param string $mode
  * @param  string $dir    - 最終存儲文件時,數據文件被存儲的目錄路徑
  * @param  string $dataFileSurfix   - 最終存儲文件時,數據文件名的后綴
  * @return InstantMemcachedRecorder or InstantFileRecorder object
  */
static public function getRecorder($mode, $dir = '', $dataFileSurfix = '') {
  switch (trim($mode)) {
   case 'mem':
    return new InstantMemcachedRecorder($dir, $dataFileSurfix);
    break;
   case 'file':
    return new InstantFileRecorder($dir, $dataFileSurfix);
    break;
   default:
    return new InstantFileRecorder($dir, $dataFileSurfix);
  }// end of switch
}//end of function

}//end of class
/**
*=--------------------------------------------------------------------=
* class InstantMemcachedRecorder
*=--------------------------------------------------------------------=
*
* 用memcache記錄及時數據的處理類
*
* 注:memcache記錄的數據,最終要被寫到文件中去;
*    寫入時機根據memcache設置的緩存隊列長度而定。
*    請通過setQueueLength()方法設置隊列長度。
*
*/
class InstantMemcachedRecorder
{
private $_host = "127.0.0.1";  //提供memcache服務的主機
private $_port = "11211";    //memcache使用端口號
private $_dataFileSurfix;    //數據文件名的后綴
private $_baseDir;             //數據文件的目錄路徑

private $_memcachedObj;     //memcached對象句柄
private $_queueLenth;     //memcached允許的某個索引對應的記錄隊列條數的最大值


/**
  *=-------------------------------------------------------------------=
  *=-------------------------------------------------------------------=
*      Public Methods
  *=-------------------------------------------------------------------=
  *=-------------------------------------------------------------------=
  */

/**
  * memcache及時數據記錄的對象構造函數
  *
  * @param  string $dir    - 最終存儲文件時,數據文件被存儲的目錄路徑
  * @param  string $dataFileSurfix   - 最終存儲文件時,數據文件名的后綴
  * @return InstantMemcachedRecorder object
  */
public function __construct($dir = '', $dataFileSurfix = '') {
  if (empty($dir)) {
   $dir = dirname(__FILE__) . DIRECTORY_SEPARATOR;
  }
  if (empty($dataFileSurfix)) {
   $dataFileSurfix = '_noname.txt';
  }
  $this->setBaseDir($dir);
  $this->setDataFileSurfix($dataFileSurfix);
  $this->_queueLenth = MAX_MEM_QUEUE_LENGTH;
}

/**
  * 設置memcache緩存隊列的長度
  *
  * @param unknown_type $len
  * @return unknown
  */
public function setQueueLength($len=0) {
  $len = intval($len);
  if ($len < 1) return false;
  $this->_queueLenth = $len;
}


/**
  * 設置數據文件的文件綴名
  *
  * @param unknown_type $str
  */
public function setDataFileSurfix($str) {
  $this->_dataFileSurfix = $str;
}

/**
  * 設置數據文件名
  *
  * @param unknown_type $str
  */
public function setDateFileName($str) {
  $this->_dateFileName = $str;
}

/**
  * 設置數據文件的目錄路徑
  *
  * @param unknown_type $dir
  */
public function setBaseDir($dir) {
  $this->_baseDir = $dir;
}

/**
  * 將數據進行及時記錄
  *
  * @param string $data
  * @return boolean
  */
public function record($data) {
  //
  // 1. detect and initiate memcache module, if not found, the then use file writing strategy.
  //
  if (!class_exists('Memcache') || !function_exists('memcache_connect')) {
   $file_recorder = new InstantFileRecorder($this->_baseDir, $this->_dataFileSurfix);
   return $file_recorder->record($data);
        } else {
         $this->_initMemcached();
        }
      
        
  //
  //2. write data into memcache.
  //
  $data_key_prefix = trim($this->_baseDir) . trim($this->_dataFileSurfix);
  $num_key         = $data_key_prefix . '_num';
  $cur_queue_num   = intval($this->_memcachedObj->get($num_key));
  $data_key        = $data_key_prefix . $cur_queue_num;
  
  $this->_memcachedObj->set($data_key, $data . "/r/n");
  
  if ($cur_queue_num >= $this->_queueLenth - 1) {
   //if the record time surplus 23:55, we write all memcached data into file.
   $this->_writeIntoFile($data_key_prefix, $this->_queueLenth);
   $this->_memcachedObj->set($num_key, 0);
  } else {
   $this->_memcachedObj->set($num_key, $cur_queue_num + 1);
   
   //if the record time surplus 23:55, we write all memcached data into file.
   if (intval(date('Hi')) >= 2355) {
    $this->_writeIntoFile($data_key_prefix, $cur_queue_num + 1);
    $this->_memcachedObj->set($num_key, 0);
   }
  }
  return true;
}

/**
  * 將所有通過本類處理的所有memcache數據,立即寫入到文件
  *
  * @return unknown
  */
public function clearMemData() {
  $this->_initMemcached();
  $data_key_prefix = trim($this->_baseDir) . trim($this->_dataFileSurfix);
  return $this->_writeIntoFile($data_key_prefix);
}


/**
  *=-------------------------------------------------------------------=
  *=-------------------------------------------------------------------=
*      Private Methods
  *=-------------------------------------------------------------------=
  *=-------------------------------------------------------------------=
  */

/**
  * 初始化memcache對象句柄
  *
  */
private function _initMemcached() {
        $this->_memcachedObj = new Memcache();
        $this->_memcachedObj->connect($this->_host, $this->_port)
         or die ("Could not connect memcached server!");
}

/**
  * 將memcache緩存的數據 立即 寫入到指定的 文件
  *
  * @param string $data_key_prefix  - 被寫入的memcache數據key的前綴名
  * @param integer $flush_queue_len      - 設置寫入的隊列長度(默認為0,表示都寫入)
  */
private function _writeIntoFile($data_key_prefix, $flush_queue_len=0) {
  $flush_queue_len == 0 && $flush_queue_len = $this->_queueLenth;
  $file_recorder = new InstantFileRecorder($this->_baseDir, $this->_dataFileSurfix);
  $data = '';
  for ($i = 0; $i < $flush_queue_len; $i++) {
   $data_key = $data_key_prefix . $i;
   $data .= $this->_memcachedObj->get($data_key);
   $this->_memcachedObj->set($data_key, '');
  }
  $data = substr($data, 0, -2);
  $file_recorder->record($data);
}

private function _needFlush() { }

}//end of class
/**
*=--------------------------------------------------------------------=
* class InstantFileRecorder
*=--------------------------------------------------------------------=
*
* 用文件記錄及時數據的處理類
*
* 注意:因為對文件數據后期綜合分析工作是在第二天凌晨進行,為防程序運行
*       過程中出現異常導致分析不完全,需要設置分析日期時間點的記錄文件。
*       這個在分析文件數據的時候,需要通過
*
*/
class InstantFileRecorder
{
private $_dateFileName;
private $_dataFileSurfix;
private $_baseDir;
private $_lastTimestamp;

/**
  *=-------------------------------------------------------------------=
  *=-------------------------------------------------------------------=
*      Public Methods
  *=-------------------------------------------------------------------=
  *=-------------------------------------------------------------------=
  */

public function __construct($dir = '', $dataFileSurfix = '') {
  if (empty($dir)) {
   $dir = dirname(__FILE__) . DIRECTORY_SEPARATOR;
  }
  if (empty($dataFileSurfix)) {
   $dataFileSurfix = '_noname.txt';
  }
  $this->setBaseDir($dir);
  $this->setDataFileSurfix($dataFileSurfix);
}

/**
  * 將數據記錄到文件中
  *
  * 最終寫入數據的文件名為basedir/年月/日_dataFileSurfix
  *
  * @param string $data  - 被寫入數據
  */
public function record($data) {
  $dir = $this->_baseDir . date('Ym');
  if (!is_dir($dir)) {
   $this->_mkdirs($dir, 0777);
  }
  $filename = $dir . DIRECTORY_SEPARATOR . date('d') . $this->_dataFileSurfix;
  $data .= "/r/n";
  $this->_writeover($filename, $data, 'a+');
}

/**
  * 設置文件后綴
  *
  *
  * @param string $str  - 文件后綴
  */
public function setDataFileSurfix($str) {
  $this->_dataFileSurfix = $str;
}

/**
  * 設置分析日期點的記錄文件名
  *
  *
  * @param string $str  - 文件后綴
  */
public function setDateFileName($str) {
  $this->_dateFileName = $str;
}

public function setBaseDir($dir) {
  $this->_baseDir = $dir;
}

/**
  * useless function, just for adapting instantMemcachedFileRecorder's interface...
  *
  * @return unknown
  */
public function setQueueLength($len=0) {
  $len = intval($len);
  if ($len < 1) return false;
}
/**
  * 獲取文件數據文件所在目錄路徑
  *
  * @return unknown
  */
public function getBaseDir() {
  return $this->_baseDir;
}

//////////////////////////////////////////////////////////////
//    以下公有方法,用來在讀取數據文件 進行后期分析的相關處理
/////////////////////////////////////////////////////////////
/**
  * 在整個數據文件讀取分析工作完畢之后,需要向日期點記錄文件寫入分析數據的時間記錄
  *
  * @return unknown
  */
public function recordDate() {
  $dir = $this->_baseDir;
  if (!is_dir($dir)) {
   $this->_mkdirs($dir, 0777);
  }
  $file_name      = $dir . $this->_dateFileName;
  $this_timestamp = empty($this->_lastTimestamp) ? time() - 86400 : $this->_lastTimestamp + 86400;
  $this->_writeover($file_name, $this_timestamp . '|' . date('Y-m-d', $this_timestamp), 'r+');
}

/**
  * 根據初始化的數據文件參數,獲取該數據文件所在的完整路徑
  *
  * @return string    - 數據文件路徑
  */
public function getFullDataFilePath() {
  $timestamp = ($this->_lastTimestamp == null) ? $this->getLastAnalyzeTime() : $this->_lastTimestamp;
  $timestamp = empty($timestamp) ?  time() - 86400 : $timestamp + 86400; //默認分析昨天的數據
  $dir = $this->_baseDir . date('Ym', $timestamp);
  return $dir . DIRECTORY_SEPARATOR . date('d', $timestamp) . $this->_dataFileSurfix;
}

/**
  * 根據設置的日期記錄文件 獲取 上次分析過的文件數據所在日期時間戳
  *
  * @return unknown
  */
public function getLastAnalyzeTime() {
  $file_name = $this->_baseDir . $this->_dateFileName;
  if (!file_exists($file_name)) {
   return '';
  }
  $data = explode('|', file_get_contents($file_name));
  $this->_lastTimestamp = isset($data[0]) ? $data[0] : '';
  return $this->_lastTimestamp;
}


/**
  *=-------------------------------------------------------------------=
  *=-------------------------------------------------------------------=
*      Private Methods
  *=-------------------------------------------------------------------=
  *=-------------------------------------------------------------------=
  */

/**
  * create multi dirs.
  */
private function _mkdirs($dir,$mode=0664){
  if(!is_dir($dir)){
   $this->_mkdirs(dirname($dir), $mode);
   @mkdir($dir,$mode);
  }
  return ;
}

/**
  * 進行數據文件的寫操作。注意本方法是fopen,fclose各一次,所以請慎重使用。
  *
  * @return unknown
  */
private function _writeover($filename, $data, $method="rb+", $iflock=1, $chmod=1) {
  touch($filename);
  $handle = fopen($filename, $method);
  if (!is_resource($handle)) {
   return false;
  }
  $iflock && flock($handle, LOCK_EX);
  fwrite($handle, $data);
  if($method == "rb+") ftruncate($handle, strlen($data));
  fclose($handle);
  $chmod && @chmod($filename, 0777);
  return true;
}
}
//設置文件緩存的目錄


?>
[/php]

四 使用示例


1. 記錄數據處理


[php]$instat_recorder = InstantRecorder::getRecorder('mem', 'cache/instant_data/', '_filename.txt');
$arr_args = array(
    'key1' => 'val1',
    'key2' => 'val2'
);
$instant_recorder->record(implode(INSTANT_DATA_SEP, $arr_args));[/php]


2. 讀取數據處理


[php]$instat_recorder = InstantRecorder::getRecorder('file', 'cache/instant_data/', '_filename.txt');
$instat_recorder->setDateFileName('last_analyze_time.inc');
$_analyzing_data_file = $this->_instantRecorder->getFullDataFilePath();
$fp = fopen($this->_analyzingDataFile, 'r+');
if (!$fp) {
    return false;
}
while (!feof($fp)) {
    // process of analyzing data...
}[/php]



五 其他
        代碼寫的不好,只是提供思路。不當之處請指正^_^
  (ps: 歡迎訪問本人blog http://www.guigui8.com

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 察隅县| 定襄县| 五莲县| 绵阳市| 宁化县| 富裕县| 湘潭市| 灌阳县| 安阳县| 唐河县| 呼伦贝尔市| 马边| 梧州市| 泽州县| 博乐市| 麻栗坡县| 湘乡市| 九龙县| 徐汇区| 贞丰县| 教育| 昌邑市| 电白县| 温州市| 南川市| 县级市| 曲麻莱县| 丰镇市| 苏尼特左旗| 腾冲县| 施甸县| 安平县| 寿阳县| 洛阳市| 温州市| 察雅县| 阜城县| 天津市| 岳阳县| 汝城县| 西峡县|